Spaces:
Sleeping
Sleeping
Add Streamlit + LlamaIndex + 浦语 API project
Browse files- .ipynb_checkpoints/README-checkpoint.md +13 -0
- app.py +84 -0
- data/.ipynb_checkpoints/README_zh-CN-checkpoint.md +304 -0
- data/.ipynb_checkpoints/readme-checkpoint.md +505 -0
- data/README_zh-CN.md +304 -0
- data/readme.md +505 -0
- data/xtuner +1 -0
- download_hf.py +7 -0
- llamaindex_RAG.py +48 -0
- requirements.txt +156 -0
- test_internlm.py +24 -0
.ipynb_checkpoints/README-checkpoint.md
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: Internlm2.5 RAG
|
3 |
+
emoji: 📉
|
4 |
+
colorFrom: indigo
|
5 |
+
colorTo: red
|
6 |
+
sdk: streamlit
|
7 |
+
sdk_version: 1.40.2
|
8 |
+
app_file: app.py
|
9 |
+
pinned: false
|
10 |
+
short_description: Llamaindex RAG 实践
|
11 |
+
---
|
12 |
+
|
13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
|
3 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
4 |
+
from llama_index.legacy.callbacks import CallbackManager
|
5 |
+
from llama_index.llms.openai_like import OpenAILike
|
6 |
+
import os
|
7 |
+
|
8 |
+
# Create an instance of CallbackManager
|
9 |
+
callback_manager = CallbackManager()
|
10 |
+
|
11 |
+
api_base_url = "https://internlm-chat.intern-ai.org.cn/puyu/api/v1/"
|
12 |
+
model = "internlm2.5-latest"
|
13 |
+
api_key = os.getenv("API_KEY")
|
14 |
+
|
15 |
+
# api_base_url = "https://api.siliconflow.cn/v1"
|
16 |
+
# model = "internlm/internlm2_5-7b-chat"
|
17 |
+
# api_key = "请填写 API Key"
|
18 |
+
|
19 |
+
llm =OpenAILike(model=model, api_base=api_base_url, api_key=api_key, is_chat_model=True,callback_manager=callback_manager)
|
20 |
+
|
21 |
+
|
22 |
+
|
23 |
+
st.set_page_config(page_title="llama_index_demo", page_icon="🦜🔗")
|
24 |
+
st.title("llama_index_demo")
|
25 |
+
|
26 |
+
# 初始化模型
|
27 |
+
@st.cache_resource
|
28 |
+
def init_models():
|
29 |
+
embed_model = HuggingFaceEmbedding(
|
30 |
+
model_name="/root/model/sentence-transformer"
|
31 |
+
)
|
32 |
+
Settings.embed_model = embed_model
|
33 |
+
|
34 |
+
#用初始化llm
|
35 |
+
Settings.llm = llm
|
36 |
+
|
37 |
+
documents = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()
|
38 |
+
index = VectorStoreIndex.from_documents(documents)
|
39 |
+
query_engine = index.as_query_engine()
|
40 |
+
|
41 |
+
return query_engine
|
42 |
+
|
43 |
+
# 检查是否需要初始化模型
|
44 |
+
if 'query_engine' not in st.session_state:
|
45 |
+
st.session_state['query_engine'] = init_models()
|
46 |
+
|
47 |
+
def greet2(question):
|
48 |
+
response = st.session_state['query_engine'].query(question)
|
49 |
+
return response
|
50 |
+
|
51 |
+
|
52 |
+
# Store LLM generated responses
|
53 |
+
if "messages" not in st.session_state.keys():
|
54 |
+
st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]
|
55 |
+
|
56 |
+
# Display or clear chat messages
|
57 |
+
for message in st.session_state.messages:
|
58 |
+
with st.chat_message(message["role"]):
|
59 |
+
st.write(message["content"])
|
60 |
+
|
61 |
+
def clear_chat_history():
|
62 |
+
st.session_state.messages = [{"role": "assistant", "content": "你好,我是你的助手,有什么我可以帮助你的吗?"}]
|
63 |
+
|
64 |
+
st.sidebar.button('Clear Chat History', on_click=clear_chat_history)
|
65 |
+
|
66 |
+
# Function for generating LLaMA2 response
|
67 |
+
def generate_llama_index_response(prompt_input):
|
68 |
+
return greet2(prompt_input)
|
69 |
+
|
70 |
+
# User-provided prompt
|
71 |
+
if prompt := st.chat_input():
|
72 |
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
73 |
+
with st.chat_message("user"):
|
74 |
+
st.write(prompt)
|
75 |
+
|
76 |
+
# Gegenerate_llama_index_response last message is not from assistant
|
77 |
+
if st.session_state.messages[-1]["role"] != "assistant":
|
78 |
+
with st.chat_message("assistant"):
|
79 |
+
with st.spinner("Thinking..."):
|
80 |
+
response = generate_llama_index_response(prompt)
|
81 |
+
placeholder = st.empty()
|
82 |
+
placeholder.markdown(response)
|
83 |
+
message = {"role": "assistant", "content": response}
|
84 |
+
st.session_state.messages.append(message)
|
data/.ipynb_checkpoints/README_zh-CN-checkpoint.md
ADDED
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div align="center">
|
2 |
+
<img src="https://github.com/InternLM/lmdeploy/assets/36994684/0cf8d00f-e86b-40ba-9b54-dc8f1bc6c8d8" width="600"/>
|
3 |
+
<br /><br />
|
4 |
+
|
5 |
+
[](https://github.com/InternLM/xtuner/stargazers)
|
6 |
+
[](https://github.com/InternLM/xtuner/blob/main/LICENSE)
|
7 |
+
[](https://pypi.org/project/xtuner/)
|
8 |
+
[](https://pypi.org/project/xtuner/)
|
9 |
+
[](https://github.com/InternLM/xtuner/issues)
|
10 |
+
[](https://github.com/InternLM/xtuner/issues)
|
11 |
+
|
12 |
+
👋 加入我们:[](https://cdn.vansin.top/internlm/xtuner.jpg)
|
13 |
+
[](https://twitter.com/intern_lm)
|
14 |
+
[](https://discord.gg/xa29JuW87d)
|
15 |
+
|
16 |
+
🔍 探索我们的模型:
|
17 |
+
[](https://huggingface.co/xtuner)
|
18 |
+
[](https://www.modelscope.cn/organization/xtuner)
|
19 |
+
[](https://openxlab.org.cn/usercenter/xtuner)
|
20 |
+
[](https://www.wisemodel.cn/organization/xtuner)
|
21 |
+
|
22 |
+
[English](README.md) | 简体中文
|
23 |
+
|
24 |
+
</div>
|
25 |
+
|
26 |
+
## 🚀 Speed Benchmark
|
27 |
+
|
28 |
+
- XTuner 与 LLaMA-Factory 在 Llama2-7B 模型上的训练效率对比
|
29 |
+
|
30 |
+
<div align=center>
|
31 |
+
<img src="https://github.com/InternLM/xtuner/assets/41630003/9c9dfdf4-1efb-4daf-84bf-7c379ae40b8b" style="width:80%">
|
32 |
+
</div>
|
33 |
+
|
34 |
+
- XTuner 与 LLaMA-Factory 在 Llama2-70B 模型上的训练效率对比
|
35 |
+
|
36 |
+
<div align=center>
|
37 |
+
<img src="https://github.com/InternLM/xtuner/assets/41630003/5ba973b8-8885-4b72-b51b-c69fa1583bdd" style="width:80%">
|
38 |
+
</div>
|
39 |
+
|
40 |
+
## 🎉 更新
|
41 |
+
- **\[2024/07\]** 支持 [MiniCPM](xtuner/configs/minicpm/) 模型!
|
42 |
+
- **\[2024/07\]** 支持训练 [DPO](https://github.com/InternLM/xtuner/tree/main/xtuner/configs/dpo), [ORPO](https://github.com/InternLM/xtuner/tree/main/xtuner/configs/orpo) 还有 [Reward Model](https://github.com/InternLM/xtuner/tree/main/xtuner/configs/reward_model) ! 并且能够支持打包数据以及序列并行功能! 请参考 [文档](https://xtuner.readthedocs.io/zh-cn/latest/dpo/overview.html) 了解更多信息。
|
43 |
+
- **\[2024/07\]** 支持 [InternLM 2.5](xtuner/configs/internlm/internlm2_5_chat_7b/) 模型!
|
44 |
+
- **\[2024/06\]** 支持 [DeepSeek V2](xtuner/configs/deepseek/deepseek_v2_chat/) models! **训练速度提升一倍!**
|
45 |
+
- **\[2024/04\]** 多模态大模型 [LLaVA-Phi-3-mini](https://huggingface.co/xtuner/llava-phi-3-mini-hf) 发布!快速开始请查阅此[文档](xtuner/configs/llava/phi3_mini_4k_instruct_clip_vit_large_p14_336)!
|
46 |
+
- **\[2024/04\]** 多模态大模型 [LLaVA-Llama-3-8B](https://huggingface.co/xtuner/llava-llama-3-8b) 和 [LLaVA-Llama-3-8B-v1.1](https://huggingface.co/xtuner/llava-llama-3-8b-v1_1) 发布!快速开始请查阅此[文档](xtuner/configs/llava/llama3_8b_instruct_clip_vit_large_p14_336)!
|
47 |
+
- **\[2024/04\]** 支持 [Llama 3](xtuner/configs/llama) 模型!
|
48 |
+
- **\[2024/04\]** 支持序列并行训练策略以实现语言模型超长上下文训练!\[[文档](https://github.com/InternLM/xtuner/blob/docs/docs/zh_cn/acceleration/train_extreme_long_sequence.rst)\] \[[速度基准](https://github.com/InternLM/xtuner/blob/docs/docs/zh_cn/acceleration/benchmark.rst)\]
|
49 |
+
- **\[2024/02\]** 支持 [Gemma](xtuner/configs/gemma) 模型!
|
50 |
+
- **\[2024/02\]** 支持 [Qwen1.5](xtuner/configs/qwen/qwen1_5) 模型!
|
51 |
+
- **\[2024/01\]** 支持 [InternLM2](xtuner/configs/internlm) 模型!同时,最新版的多模态大模型 [LLaVA-Internlm2-7B](https://huggingface.co/xtuner/llava-internlm2-7b) / [20B](https://huggingface.co/xtuner/llava-internlm2-20b) 发布,其表现出强大的性能!
|
52 |
+
- **\[2024/01\]** 支持 [DeepSeek-MoE](https://huggingface.co/deepseek-ai/deepseek-moe-16b-chat) 模型!20GB 显存即可实现 QLoRA 微调,4x80GB 即可实现全参数微调。快速开始请查阅相关[配置文件](xtuner/configs/deepseek/)!
|
53 |
+
- **\[2023/12\]** 🔥 支持多模态模型 VLM([LLaVA-v1.5](https://github.com/haotian-liu/LLaVA))预训练和指令微调!快速开始请查阅此[文档](xtuner/configs/llava/README_zh-CN.md)!
|
54 |
+
- **\[2023/12\]** 🔥 支持 [Mixtral 8x7B](https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1) 模型!快速开始请查阅此[文档](xtuner/configs/mixtral/README.md)!
|
55 |
+
- **\[2023/11\]** 支持 [ChatGLM3-6B](xtuner/configs/chatglm) 模型!
|
56 |
+
- **\[2023/10\]** 支持 [MSAgent-Bench](https://modelscope.cn/datasets/damo/MSAgent-Bench) 数据集,并且微调所得大语言模型可应用至 [Lagent](https://github.com/InternLM/lagent) 框架!
|
57 |
+
- **\[2023/10\]** 优化数据处理逻辑以兼容 `system` 字段,相关细节请查阅[文档](docs/zh_cn/user_guides/dataset_format.md)!
|
58 |
+
- **\[2023/09\]** 支持 [InternLM-20B](xtuner/configs/internlm) 系列模型!
|
59 |
+
- **\[2023/09\]** 支持 [Baichuan2](xtuner/configs/baichuan) 系列模型!
|
60 |
+
- **\[2023/08\]** XTuner 正式发布!众多微调模型已上传至 [HuggingFace](https://huggingface.co/xtuner)!
|
61 |
+
|
62 |
+
## 📖 介绍
|
63 |
+
|
64 |
+
XTuner 是一个高效、灵活、全能的轻量化大模型微调工具库。
|
65 |
+
|
66 |
+
**高效**
|
67 |
+
|
68 |
+
- 支持大语言模型 LLM、多模态图文模型 VLM 的预训练及轻量级微调。XTuner 支持在 8GB 显存下微调 7B 模型,同时也支持多节点跨设备微调更大尺度模型(70B+)。
|
69 |
+
- 自动分发高性能算子(如 FlashAttention、Triton kernels 等)以加速训练吞吐。
|
70 |
+
- 兼容 [DeepSpeed](https://github.com/microsoft/DeepSpeed) 🚀,轻松应用各种 ZeRO 训练优化策略。
|
71 |
+
|
72 |
+
**灵活**
|
73 |
+
|
74 |
+
- 支持多种大语言模型,包括但不限于 [InternLM](https://huggingface.co/internlm)、[Mixtral-8x7B](https://huggingface.co/mistralai)、[Llama 2](https://huggingface.co/meta-llama)、[ChatGLM](https://huggingface.co/THUDM)、[Qwen](https://huggingface.co/Qwen)、[Baichuan](https://huggingface.co/baichuan-inc)。
|
75 |
+
- 支持多模态图文模型 LLaVA 的预训练与微调。利用 XTuner 训得模型 [LLaVA-InternLM2-20B](https://huggingface.co/xtuner/llava-internlm2-20b) 表现优异。
|
76 |
+
- 精心设计的数据管道,兼容任意数据格式,开源数据或自定义数据皆可快速上手。
|
77 |
+
- 支持 [QLoRA](http://arxiv.org/abs/2305.14314)、[LoRA](http://arxiv.org/abs/2106.09685)、全量参数微调等多种微调算法,支撑用户根据具体需求作出最优选择。
|
78 |
+
|
79 |
+
**全能**
|
80 |
+
|
81 |
+
- 支持增量预训练、指令微调与 Agent 微调。
|
82 |
+
- 预定义众多开源对话模版,支持与开源或训练所得模型进行对话。
|
83 |
+
- 训练所得模型可无缝接入部署工具库 [LMDeploy](https://github.com/InternLM/lmdeploy)、大规模评测工具库 [OpenCompass](https://github.com/open-compass/opencompass) 及 [VLMEvalKit](https://github.com/open-compass/VLMEvalKit)。
|
84 |
+
|
85 |
+
## 🔥 支持列表
|
86 |
+
|
87 |
+
<table>
|
88 |
+
<tbody>
|
89 |
+
<tr align="center" valign="middle">
|
90 |
+
<td>
|
91 |
+
<b>模型</b>
|
92 |
+
</td>
|
93 |
+
<td>
|
94 |
+
<b>数据集</b>
|
95 |
+
</td>
|
96 |
+
<td>
|
97 |
+
<b>数据格式</b>
|
98 |
+
</td>
|
99 |
+
<td>
|
100 |
+
<b>微调算法</b>
|
101 |
+
</td>
|
102 |
+
</tr>
|
103 |
+
<tr valign="top">
|
104 |
+
<td align="left" valign="top">
|
105 |
+
<ul>
|
106 |
+
<li><a href="https://huggingface.co/internlm">InternLM 2 / 2.5</a></li>
|
107 |
+
<li><a href="https://huggingface.co/meta-llama">Llama 2 / 3</a></li>
|
108 |
+
<li><a href="https://huggingface.co/collections/microsoft/phi-3-6626e15e9585a200d2d761e3">Phi-3</a></li>
|
109 |
+
<li><a href="https://huggingface.co/THUDM/chatglm2-6b">ChatGLM2</a></li>
|
110 |
+
<li><a href="https://huggingface.co/THUDM/chatglm3-6b">ChatGLM3</a></li>
|
111 |
+
<li><a href="https://huggingface.co/Qwen/Qwen-7B">Qwen</a></li>
|
112 |
+
<li><a href="https://huggingface.co/baichuan-inc/Baichuan2-7B-Base">Baichuan2</a></li>
|
113 |
+
<li><a href="https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1">Mixtral</a></li>
|
114 |
+
<li><a href="https://huggingface.co/deepseek-ai/DeepSeek-V2-Chat">DeepSeek V2</a></li>
|
115 |
+
<li><a href="https://huggingface.co/google">Gemma</a></li>
|
116 |
+
<li><a href="https://huggingface.co/openbmb">MiniCPM</a></li>
|
117 |
+
<li>...</li>
|
118 |
+
</ul>
|
119 |
+
</td>
|
120 |
+
<td>
|
121 |
+
<ul>
|
122 |
+
<li><a href="https://modelscope.cn/datasets/damo/MSAgent-Bench">MSAgent-Bench</a></li>
|
123 |
+
<li><a href="https://huggingface.co/datasets/fnlp/moss-003-sft-data">MOSS-003-SFT</a> 🔧</li>
|
124 |
+
<li><a href="https://huggingface.co/datasets/tatsu-lab/alpaca">Alpaca en</a> / <a href="https://huggingface.co/datasets/silk-road/alpaca-data-gpt4-chinese">zh</a></li>
|
125 |
+
<li><a href="https://huggingface.co/datasets/WizardLM/WizardLM_evol_instruct_V2_196k">WizardLM</a></li>
|
126 |
+
<li><a href="https://huggingface.co/datasets/timdettmers/openassistant-guanaco">oasst1</a></li>
|
127 |
+
<li><a href="https://huggingface.co/datasets/garage-bAInd/Open-Platypus">Open-Platypus</a></li>
|
128 |
+
<li><a href="https://huggingface.co/datasets/HuggingFaceH4/CodeAlpaca_20K">Code Alpaca</a></li>
|
129 |
+
<li><a href="https://huggingface.co/datasets/burkelibbey/colors">Colorist</a> 🎨</li>
|
130 |
+
<li><a href="https://github.com/WangRongsheng/ChatGenTitle">Arxiv GenTitle</a></li>
|
131 |
+
<li><a href="https://github.com/LiuHC0428/LAW-GPT">Chinese Law</a></li>
|
132 |
+
<li><a href="https://huggingface.co/datasets/Open-Orca/OpenOrca">OpenOrca</a></li>
|
133 |
+
<li><a href="https://huggingface.co/datasets/shibing624/medical">Medical Dialogue</a></li>
|
134 |
+
<li>...</li>
|
135 |
+
</ul>
|
136 |
+
</td>
|
137 |
+
<td>
|
138 |
+
<ul>
|
139 |
+
<li><a href="docs/zh_cn/user_guides/incremental_pretraining.md">Incremental Pre-training</a> </li>
|
140 |
+
<li><a href="docs/zh_cn/user_guides/single_turn_conversation.md">Single-turn Conversation SFT</a> </li>
|
141 |
+
<li><a href="docs/zh_cn/user_guides/multi_turn_conversation.md">Multi-turn Conversation SFT</a> </li>
|
142 |
+
</ul>
|
143 |
+
</td>
|
144 |
+
<td>
|
145 |
+
<ul>
|
146 |
+
<li><a href="http://arxiv.org/abs/2305.14314">QLoRA</a></li>
|
147 |
+
<li><a href="http://arxiv.org/abs/2106.09685">LoRA</a></li>
|
148 |
+
<li>全量参数微调</li>
|
149 |
+
<li><a href="https://arxiv.org/abs/2305.18290">DPO</a></li>
|
150 |
+
<li><a href="https://arxiv.org/abs/2403.07691">ORPO</a></li>
|
151 |
+
<li>Reward Model</a></li>
|
152 |
+
</ul>
|
153 |
+
</td>
|
154 |
+
</tr>
|
155 |
+
</tbody>
|
156 |
+
</table>
|
157 |
+
|
158 |
+
## 🛠️ 快速上手
|
159 |
+
|
160 |
+
### 安装
|
161 |
+
|
162 |
+
- 推荐使用 conda 先构建一个 Python-3.10 的虚拟环境
|
163 |
+
|
164 |
+
```bash
|
165 |
+
conda create --name xtuner-env python=3.10 -y
|
166 |
+
conda activate xtuner-env
|
167 |
+
```
|
168 |
+
|
169 |
+
- 通过 pip 安装 XTuner:
|
170 |
+
|
171 |
+
```shell
|
172 |
+
pip install -U xtuner
|
173 |
+
```
|
174 |
+
|
175 |
+
亦可集成 DeepSpeed 安装:
|
176 |
+
|
177 |
+
```shell
|
178 |
+
pip install -U 'xtuner[deepspeed]'
|
179 |
+
```
|
180 |
+
|
181 |
+
- 从源码安装 XTuner:
|
182 |
+
|
183 |
+
```shell
|
184 |
+
git clone https://github.com/InternLM/xtuner.git
|
185 |
+
cd xtuner
|
186 |
+
pip install -e '.[all]'
|
187 |
+
```
|
188 |
+
|
189 |
+
### 微调
|
190 |
+
|
191 |
+
XTuner 支持微调大语言模型。数据集预处理指南请查阅[文档](./docs/zh_cn/user_guides/dataset_prepare.md)。
|
192 |
+
|
193 |
+
- **步骤 0**,准备配置文件。XTuner 提供多个开箱即用的配置文件,用户可以通过下列命令查看:
|
194 |
+
|
195 |
+
```shell
|
196 |
+
xtuner list-cfg
|
197 |
+
```
|
198 |
+
|
199 |
+
或者,如果所提供的配置文件不能满足使用需求,请导出所提供的配置文件并进行相应更改:
|
200 |
+
|
201 |
+
```shell
|
202 |
+
xtuner copy-cfg ${CONFIG_NAME} ${SAVE_PATH}
|
203 |
+
vi ${SAVE_PATH}/${CONFIG_NAME}_copy.py
|
204 |
+
```
|
205 |
+
|
206 |
+
- **步骤 1**,开始微调。
|
207 |
+
|
208 |
+
```shell
|
209 |
+
xtuner train ${CONFIG_NAME_OR_PATH}
|
210 |
+
```
|
211 |
+
|
212 |
+
例如,我们可以利用 QLoRA 算法在 oasst1 数据集上微调 InternLM2.5-Chat-7B:
|
213 |
+
|
214 |
+
```shell
|
215 |
+
# 单卡
|
216 |
+
xtuner train internlm2_5_chat_7b_qlora_oasst1_e3 --deepspeed deepspeed_zero2
|
217 |
+
# 多卡
|
218 |
+
(DIST) NPROC_PER_NODE=${GPU_NUM} xtuner train internlm2_5_chat_7b_qlora_oasst1_e3 --deepspeed deepspeed_zero2
|
219 |
+
(SLURM) srun ${SRUN_ARGS} xtuner train internlm2_5_chat_7b_qlora_oasst1_e3 --launcher slurm --deepspeed deepspeed_zero2
|
220 |
+
```
|
221 |
+
|
222 |
+
- `--deepspeed` 表示使用 [DeepSpeed](https://github.com/microsoft/DeepSpeed) 🚀 来优化训练过程。XTuner 内置了多种策略,包括 ZeRO-1、ZeRO-2、ZeRO-3 等。如果用户期望关闭此功能,请直接移除此参数。
|
223 |
+
|
224 |
+
- 更多示例,请查阅[文档](./docs/zh_cn/user_guides/finetune.md)。
|
225 |
+
|
226 |
+
- **步骤 2**,将保存的 PTH 模型(如果使用的DeepSpeed,则将会是一个文件夹)转换为 HuggingFace 模型:
|
227 |
+
|
228 |
+
```shell
|
229 |
+
xtuner convert pth_to_hf ${CONFIG_NAME_OR_PATH} ${PTH} ${SAVE_PATH}
|
230 |
+
```
|
231 |
+
|
232 |
+
### 对话
|
233 |
+
|
234 |
+
XTuner 提供与大语言模型对话的工具。
|
235 |
+
|
236 |
+
```shell
|
237 |
+
xtuner chat ${NAME_OR_PATH_TO_LLM} --adapter {NAME_OR_PATH_TO_ADAPTER} [optional arguments]
|
238 |
+
```
|
239 |
+
|
240 |
+
例如:
|
241 |
+
|
242 |
+
与 InternLM2.5-Chat-7B 对话:
|
243 |
+
|
244 |
+
```shell
|
245 |
+
xtuner chat internlm/internlm2-chat-7b --prompt-template internlm2_chat
|
246 |
+
```
|
247 |
+
|
248 |
+
更多示例,请查阅[文档](./docs/zh_cn/user_guides/chat.md)。
|
249 |
+
|
250 |
+
### 部署
|
251 |
+
|
252 |
+
- **步骤 0**,将 HuggingFace adapter 合并到大语言模型:
|
253 |
+
|
254 |
+
```shell
|
255 |
+
xtuner convert merge \
|
256 |
+
${NAME_OR_PATH_TO_LLM} \
|
257 |
+
${NAME_OR_PATH_TO_ADAPTER} \
|
258 |
+
${SAVE_PATH} \
|
259 |
+
--max-shard-size 2GB
|
260 |
+
```
|
261 |
+
|
262 |
+
- **步骤 1**,使用任意推理框架部署微调后的大语言模型,例如 [LMDeploy](https://github.com/InternLM/lmdeploy) 🚀:
|
263 |
+
|
264 |
+
```shell
|
265 |
+
pip install lmdeploy
|
266 |
+
python -m lmdeploy.pytorch.chat ${NAME_OR_PATH_TO_LLM} \
|
267 |
+
--max_new_tokens 256 \
|
268 |
+
--temperture 0.8 \
|
269 |
+
--top_p 0.95 \
|
270 |
+
--seed 0
|
271 |
+
```
|
272 |
+
|
273 |
+
🔥 追求速度更快、显存占用更低的推理?欢迎体验 [LMDeploy](https://github.com/InternLM/lmdeploy) 提供的 4-bit 量化!使用指南请见[文档](https://github.com/InternLM/lmdeploy/tree/main#quantization)。
|
274 |
+
|
275 |
+
### 评测
|
276 |
+
|
277 |
+
- 推荐使用一站式平台 [OpenCompass](https://github.com/InternLM/opencompass) 来评测大语言模型,其目前已涵盖 50+ 数据集的约 30 万条题目。
|
278 |
+
|
279 |
+
## 🤝 贡献指南
|
280 |
+
|
281 |
+
我们感谢所有的贡献者为改进和提升 XTuner 所作出的努力。请参考[贡献指南](.github/CONTRIBUTING.md)来了解参与项目贡献的相关指引。
|
282 |
+
|
283 |
+
## 🎖️ 致谢
|
284 |
+
|
285 |
+
- [Llama 2](https://github.com/facebookresearch/llama)
|
286 |
+
- [DeepSpeed](https://github.com/microsoft/DeepSpeed)
|
287 |
+
- [QLoRA](https://github.com/artidoro/qlora)
|
288 |
+
- [LMDeploy](https://github.com/InternLM/lmdeploy)
|
289 |
+
- [LLaVA](https://github.com/haotian-liu/LLaVA)
|
290 |
+
|
291 |
+
## 🖊️ 引用
|
292 |
+
|
293 |
+
```bibtex
|
294 |
+
@misc{2023xtuner,
|
295 |
+
title={XTuner: A Toolkit for Efficiently Fine-tuning LLM},
|
296 |
+
author={XTuner Contributors},
|
297 |
+
howpublished = {\url{https://github.com/InternLM/xtuner}},
|
298 |
+
year={2023}
|
299 |
+
}
|
300 |
+
```
|
301 |
+
|
302 |
+
## 开源许可证
|
303 |
+
|
304 |
+
该项目采用 [Apache License 2.0 开源许可证](LICENSE)。同时,请遵守所使用的模型与数据集的许可证。
|
data/.ipynb_checkpoints/readme-checkpoint.md
ADDED
@@ -0,0 +1,505 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Qwen整体介绍
|
2 |
+
Qwen模型架构讲解直播:[直播链接](https://meeting.tencent.com/v2/cloud-record/share?id=0be29bb2-0648-4aeb-9baa-c9dc91dfc7a6&from=3&is-single=false&record_type=2)
|
3 |
+
|
4 |
+
Qwen的整体架构与Llama2类似,如下图所示:
|
5 |
+

|
6 |
+
|
7 |
+
其中:
|
8 |
+
- `tokenizer`将文本转为词表里面的数值。
|
9 |
+
- 数值经过`embedding`得到一一对应的向量。
|
10 |
+
- `attention_mask`是用来看见左边、右边,双向等等来设定。
|
11 |
+
- 各类下游任务,`Casual`,`seqcls`等,基本都是基础模型`model`后面接对应的`Linear`层,还有损失函数不一样。
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
# 1 Qwen2Config
|
16 |
+
Qwen2Config中包含一些自定义的超参数,例如`vocab_size`,`hidden_size`,`num_hidden_layers`, `num_attention_heads`等。类似于`dict`可以调用里面的超参数:`config.pad_token_id`。
|
17 |
+
## 1.1 Qwen2Model
|
18 |
+
### 1.1.1 初始化
|
19 |
+
|
20 |
+
- 设置了模型的两个属性:`padding_idx`(用于指定填充标记的索引),`vocab_size`(词汇表的大小)
|
21 |
+
- 初始化了模型的嵌入层、解码器层、归一化层
|
22 |
+
- 嵌入层(`nn.Embedding`):模型使用嵌入层将输入的标记映射成密集的向量表示。
|
23 |
+
- 解码器层(`nn.ModuleList()`):模型包含多个解码器层,这些层都是由 `Qwen2DecoderLayer`` 定义
|
24 |
+
- 归一化层 `Qwen2RMSNorm`:归一化层使用的是 Root Mean Square Layer Normalization
|
25 |
+
- 设置了是否使用 `gradient_checkpoint` 主要是用来节省显存
|
26 |
+
- 调用 `post_init()` 完成一些初始化和准备检查的代码
|
27 |
+
|
28 |
+
```python
|
29 |
+
class Qwen2Model(Qwen2PreTrainedModel):
|
30 |
+
def __init__(self, config: Qwen2Config):
|
31 |
+
super().__init__(config)
|
32 |
+
self.padding_idx = config.pad_token_id
|
33 |
+
self.vocab_size = config.vocab_size
|
34 |
+
|
35 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
36 |
+
self.layers = nn.ModuleList(
|
37 |
+
[Qwen2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
38 |
+
)
|
39 |
+
self.norm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
40 |
+
|
41 |
+
self.gradient_checkpointing = False
|
42 |
+
# Initialize weights and apply final processing
|
43 |
+
self.post_init()
|
44 |
+
```
|
45 |
+
对于`post_init`函数:
|
46 |
+
主要是对参数进行初始化,以及初始化梯度检查点作用
|
47 |
+
```python
|
48 |
+
def post_init(self):
|
49 |
+
"""
|
50 |
+
A method executed at the end of each Transformer model initialization, to execute code that needs the model's
|
51 |
+
modules properly initialized (such as weight initialization).
|
52 |
+
"""
|
53 |
+
self.init_weights()
|
54 |
+
self._backward_compatibility_gradient_checkpointing()
|
55 |
+
```
|
56 |
+
|
57 |
+
### 1.1.2 Forward
|
58 |
+
在此只对核心主干进行讲解:
|
59 |
+
```python
|
60 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
61 |
+
# embed positions
|
62 |
+
hidden_states = inputs_embeds
|
63 |
+
|
64 |
+
for idx, decoder_layer in enumerate(self.layers):
|
65 |
+
# 将所有的hidden_states保存成tuple
|
66 |
+
if output_hidden_states:
|
67 |
+
all_hidden_states += (hidden_states,)
|
68 |
+
# 将hs送入每一层decoder_layer
|
69 |
+
layer_outputs = decoder_layer(
|
70 |
+
hidden_states,
|
71 |
+
attention_mask=attention_mask,
|
72 |
+
position_ids=position_ids,
|
73 |
+
past_key_value=past_key_value,
|
74 |
+
output_attentions=output_attentions,
|
75 |
+
use_cache=use_cache,
|
76 |
+
)
|
77 |
+
# 取出上一层decoder_输出的hs,再传入下一个layer
|
78 |
+
# 只要第一个,第二个是cache的一个类,然后进入下一个layer
|
79 |
+
hidden_states = layer_outputs[0]
|
80 |
+
|
81 |
+
# 将最后layers输出后的hidden_states进行标准化
|
82 |
+
hidden_states = self.norm(hidden_states)
|
83 |
+
|
84 |
+
# 加上最后一层的hidden_states
|
85 |
+
if output_hidden_states:
|
86 |
+
all_hidden_states += (hidden_states,)
|
87 |
+
```
|
88 |
+
- 如果保存`output_hidden_states`的话,就是第一个为`input_ids`进行`emb`,然后保存到`n-1`层的`decoder_layer`的输出`hs`,再加上最后一层`layer`的输出`hs`进行过`norm`后的`hs`.
|
89 |
+
- 最后是以`BaseModelOutputWithPast`的形式输出。
|
90 |
+
|
91 |
+
## 1.2 Qwen2DecoderLayer
|
92 |
+
|
93 |
+
<div align=center>
|
94 |
+
<img src='./img/decoderlayer.png'>
|
95 |
+
</div>
|
96 |
+
|
97 |
+
### 1.2.1 初始化
|
98 |
+
`layer`三件套:`attn`+`MLP`+`norm`
|
99 |
+
|
100 |
+
```python
|
101 |
+
QWEN2_ATTENTION_CLASSES = {
|
102 |
+
"eager": Qwen2Attention, # 一般情况下是这个
|
103 |
+
"flash_attention_2": Qwen2FlashAttention2,
|
104 |
+
"sdpa": Qwen2SdpaAttention,
|
105 |
+
}
|
106 |
+
|
107 |
+
class Qwen2DecoderLayer(nn.Module):
|
108 |
+
def __init__(self, config: Qwen2Config):
|
109 |
+
super().__init__()
|
110 |
+
self.hidden_size = config.hidden_size
|
111 |
+
self.self_attn = QWEN2_ATTENTION_CLASSES[config._attn_implementation](config, layer_idx)
|
112 |
+
|
113 |
+
self.mlp = Qwen2MLP(config)
|
114 |
+
self.input_layernorm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
115 |
+
self.post_attention_layernorm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
116 |
+
```
|
117 |
+
这里面的`input_layernorm`和`post_attention_layernorm`内容是一样的,只是应用的顺序不一样。
|
118 |
+
### 1.1.2 Forward
|
119 |
+
可配合图食用,效果更佳:
|
120 |
+
- 首先复制一份`hidden_states`为`residual`,然后将`hidden_states`送入`Norm`,再送入`attn`模块。
|
121 |
+
- 得到`attn`的输出后,再复制一份`residual`,再将`hidden_states`送入`Norm`,`mlp`,再与`residual`进行相加。最后输出的就是这个`hidden_states`啦。
|
122 |
+
|
123 |
+
```python
|
124 |
+
residual = hidden_states
|
125 |
+
# 标准化后送入attn
|
126 |
+
hidden_states = self.input_layernorm(hidden_states) # RMSNorm标准化
|
127 |
+
# Self Attention
|
128 |
+
hidden_states, self_attn_weights, present_key_value = self.self_attn(
|
129 |
+
hidden_states=hidden_states,
|
130 |
+
attention_mask=attention_mask,
|
131 |
+
position_ids=position_ids,
|
132 |
+
past_key_value=past_key_value,
|
133 |
+
output_attentions=output_attentions,
|
134 |
+
use_cache=use_cache,
|
135 |
+
**kwargs,
|
136 |
+
)
|
137 |
+
|
138 |
+
# 残差与新的hidden_states相加
|
139 |
+
hidden_states = residual + hidden_states
|
140 |
+
|
141 |
+
# Fully Connected
|
142 |
+
residual = hidden_states
|
143 |
+
# 同样的RMSNorm标准化
|
144 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
145 |
+
hidden_states = self.mlp(hidden_states)
|
146 |
+
hidden_states = residual + hidden_states
|
147 |
+
|
148 |
+
outputs = (hidden_states,)
|
149 |
+
|
150 |
+
return outputs
|
151 |
+
```
|
152 |
+
|
153 |
+
## 1.3 Qwen2Attention
|
154 |
+
<div align=center>
|
155 |
+
<img src='./img/Qwen2Attention.png'>
|
156 |
+
</div>
|
157 |
+
|
158 |
+
### 1.3.1 初始化
|
159 |
+
核心参数解析:
|
160 |
+
- `num_key_value_heads`:表示键值对的头数
|
161 |
+
- `num_key_value_groups`:表示键值对的组数,计算为`num_heads` // `num_key_value_headsGQA`的实现!!
|
162 |
+
- `q_proj`,`k_proj`,`v_proj`,`o_proj`四个`Linear`操作。后续`LoRa`也基本都对他动的刀子.
|
163 |
+
|
164 |
+
```python
|
165 |
+
class Qwen2Attention(nn.Module):
|
166 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
167 |
+
|
168 |
+
def __init__(self, config: Qwen2Config):
|
169 |
+
super().__init__()
|
170 |
+
self.config = config
|
171 |
+
self.layer_idx = layer_idx
|
172 |
+
self.hidden_size = config.hidden_size
|
173 |
+
self.num_heads = config.num_attention_heads
|
174 |
+
self.head_dim = self.hidden_size // self.num_heads
|
175 |
+
self.num_key_value_heads = config.num_key_value_heads
|
176 |
+
self.num_key_value_groups = self.num_heads // self.num_key_value_heads
|
177 |
+
self.max_position_embeddings = config.max_position_embeddings
|
178 |
+
self.rope_theta = config.rope_theta
|
179 |
+
self.is_causal = True
|
180 |
+
self.attention_dropout = config.attention_dropout
|
181 |
+
|
182 |
+
if (self.head_dim * self.num_heads) != self.hidden_size:
|
183 |
+
raise ValueError(
|
184 |
+
f"hidden_size must be divisible by num_heads (got `hidden_size`: {self.hidden_size}"
|
185 |
+
f" and `num_heads`: {self.num_heads})."
|
186 |
+
)
|
187 |
+
self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=config.attention_bias)
|
188 |
+
self.k_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
|
189 |
+
self.v_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
|
190 |
+
self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=config.attention_bias)
|
191 |
+
|
192 |
+
self.rotary_emb = Qwen2RotaryEmbedding(
|
193 |
+
self.head_dim,
|
194 |
+
max_position_embeddings=self.max_position_embeddings,
|
195 |
+
base=self.rope_theta,
|
196 |
+
)
|
197 |
+
```
|
198 |
+
- `config`里面的参数可直接看`Qwen2Config`里面的介绍
|
199 |
+
|
200 |
+
```python
|
201 |
+
max_position_embeddings (`int`, *optional*, defaults to 32768):
|
202 |
+
The maximum sequence length that this model might ever be used with.
|
203 |
+
|
204 |
+
rope_theta (`float`, *optional*, defaults to 10000.0):
|
205 |
+
The base period of the RoPE embeddings.
|
206 |
+
```
|
207 |
+
### 1.3.2 Forward
|
208 |
+
- 首先将`hidden_states`送入`Linear`中得到`query`、`key`与`value`。
|
209 |
+
- 使用旋转位置嵌入操作`rotary_emb`,使用了旋转位置嵌入的余弦和正弦部分,将他们与`query`和`key`相乘,并将结果相加,从而实现旋转位置嵌入的效果。
|
210 |
+
- 将`key_states`和`value_states`重复`group`次,再执行`dot attn`操作。
|
211 |
+
- 在`dot attn`操作后得到`attn_weights`,加上`attention_mask`从而实现读取掩盖操作,在经过`softmax`与`value_states`相乘。得到`attn_output`。
|
212 |
+
- 再将上述的`attn_output`进行`reshape`操作,送入`o_proj`,得到最终的输出。
|
213 |
+
|
214 |
+
```python
|
215 |
+
# 获取形状信息,hidden_states输入的为(bs,T,hd)
|
216 |
+
bsz, q_len, _ = hidden_states.size()
|
217 |
+
|
218 |
+
# 对hidden_states进行Linear生成query、key、value
|
219 |
+
query_states = self.q_proj(hidden_states)
|
220 |
+
key_states = self.k_proj(hidden_states)
|
221 |
+
value_states = self.v_proj(hidden_states)
|
222 |
+
|
223 |
+
# reshape多头处理--分块--(bs,T,heads,hd_d)
|
224 |
+
query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
|
225 |
+
key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
226 |
+
value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
227 |
+
|
228 |
+
# 将旋转位置嵌入应用于查询和键张量。使用了旋转位置嵌入的余弦和正弦��分,将它们与查询和键张量相乘,并将结果相加,从而实现旋转位置嵌入的效果
|
229 |
+
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
|
230 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
231 |
+
|
232 |
+
# 先将key_states和value_states重复了num_key_value_groups次
|
233 |
+
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
234 |
+
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
235 |
+
|
236 |
+
# 使用dot attn实现q*kT/hd_d^0.5
|
237 |
+
attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) / math.sqrt(self.head_dim)
|
238 |
+
|
239 |
+
# 然后 attn_weights 加上 attention_mask,实现读取顺序
|
240 |
+
attn_weights = attn_weights + attention_mask
|
241 |
+
|
242 |
+
# softmax + dropout + values_states相乘
|
243 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query_states.dtype)
|
244 |
+
attn_weights = nn.functional.dropout(attn_weights, p=self.attention_dropout, training=self.training)
|
245 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
246 |
+
|
247 |
+
# 转置,修改形状等reshape操作
|
248 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
249 |
+
attn_output = attn_output.reshape(bsz, q_len, self.hidden_size)
|
250 |
+
|
251 |
+
# 最后在进行一次o_proj
|
252 |
+
attn_output = self.o_proj(attn_output)
|
253 |
+
|
254 |
+
# 返回结果
|
255 |
+
return attn_output, attn_weights, past_key_value
|
256 |
+
```
|
257 |
+
|
258 |
+
### 1.3.3 细节Debug
|
259 |
+
#### 1.3.3.1 GQA
|
260 |
+
<div align=center>
|
261 |
+
<img src='./img/GQA.png'>
|
262 |
+
</div>
|
263 |
+
|
264 |
+
> 主旨:GQA和MQA不需要在推理的过程存储那么多的kv cache, 那么kv cache占用的显存就变小,那么我们LLM serving可以处理的请求数量就更多
|
265 |
+
|
266 |
+
1. 定义初始张量
|
267 |
+
```python
|
268 |
+
import torch
|
269 |
+
|
270 |
+
## shape:(batch, seq_len, head, head_dim)
|
271 |
+
query = torch.randn(10, 128, 8, 128)
|
272 |
+
key = torch.randn(10, 128, 2, 128)
|
273 |
+
value = torch.randn(10, 128, 2, 128)
|
274 |
+
|
275 |
+
## 在此设置组数为4
|
276 |
+
groups = query.shape[-2] // key.shape[-2]
|
277 |
+
```
|
278 |
+
2. 之后进行扩展key,value的操作
|
279 |
+
在`GQA`中,`key`和`value`都要比`query`小`group`倍,但是为在后续做矩阵乘法时方便,我们需要先把`key`和`value`的`head`利用expand扩展张量到和`query`相同的维度。方便后续计算。
|
280 |
+
|
281 |
+
```python
|
282 |
+
# 定义输入x, n_rep是需要重复的次数,在这里一般是组数
|
283 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
284 |
+
|
285 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
286 |
+
# dont need repeat here means multi head attention
|
287 |
+
if n_rep == 1:
|
288 |
+
return hidden_states
|
289 |
+
# first we expand x to (bs, seq_len, head, group, head_dim)
|
290 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
291 |
+
# reshape make head -> head * group
|
292 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
293 |
+
```
|
294 |
+
3. 矩阵乘法得到`score`与`output`
|
295 |
+
后面就是征程的`kqv`相乘了
|
296 |
+
```python
|
297 |
+
#(bs, head, seq_len, head_dim)
|
298 |
+
query = query.transpose(1, 2)
|
299 |
+
key = repeat_kv(key.transpose(1, 2), 4)
|
300 |
+
value = repeat_kv(value.transpose(1, 2), 4)
|
301 |
+
scores = torch.matmul(query, key.transpose(2, 3)) / math.sqrt(head_dim)
|
302 |
+
scores = torch.nn.functional.softmax(scores, dim=-1)
|
303 |
+
|
304 |
+
out = torch.matmul(scores, value)
|
305 |
+
#上一步转置了,还得转回去
|
306 |
+
out = out.transpose(1, 2)
|
307 |
+
```
|
308 |
+
**补充:**
|
309 |
+
**为什么要用expand之后再reshape而不能直接用tensor自带的repeat?**
|
310 |
+
- `expand` 方法用于对张量进行扩展,但不实际分配新的内存。它返回的张量与原始张量共享相同的数据
|
311 |
+
- `repeat` 方法通过实际复制数据来扩展张量。它返回的新张量不与原始张量共享数据,扩展后的张量占用了更多的内存。
|
312 |
+
|
313 |
+
|
314 |
+
#### 1.3.3.2 apply_rotary_pos_emb
|
315 |
+
位置编码的含义是对每一个token的每一个dim赋予不同的位置信息。
|
316 |
+
公式定义:
|
317 |
+
<div align=center>
|
318 |
+
<img src='./img/ROPE1.png'>
|
319 |
+
</div>
|
320 |
+
|
321 |
+
概念:通过旋转编码,使得每个token既有相对位置信息,又有绝对位置信息。
|
322 |
+
- 既能以自注意力矩阵偏置的形式作用于 $A_{t,s}$,直接反映两个token的相对位置信息,又能拆解到向量 $q_{t}$ 和 $k_{s}$ 上,通过直接编码token的绝对位置实现。
|
323 |
+
- RoPE本质是实现对特征向量的旋转操作,如果以二维特征向量举例,对于相邻两个token来说,其对应同一个 $\theta$,其定义为:
|
324 |
+
<div align=center>
|
325 |
+
<img src='./img/ROPE2.png'>
|
326 |
+
</div>
|
327 |
+
|
328 |
+
可得,其本质就是: $q_{t}$, $k_{s}$ 旋转后的结果,就是 $q_{t}$, $k_{s}$乘上cos再加上 $q_{t}$, $k_{s}$翻转维度并取反一维后乘上sin。
|
329 |
+
- 对于高纬向量,由于奇、复数维度两两交错实现较为复杂,则现在可简化为将特征维度一切二,如下图所示,在实现过程中对前后各半进行的操作即为rotate_half操作:
|
330 |
+
<div align=center>
|
331 |
+
<img src='./img/ROPE3.png'>
|
332 |
+
</div>
|
333 |
+
|
334 |
+
|
335 |
+
代码实现:
|
336 |
+
先定义旋转角度
|
337 |
+
```python
|
338 |
+
class Qwen2RotaryEmbedding(nn.Module):
|
339 |
+
def __init__(self, dim, max_position_embeddings=2048, base=10000, device=None):
|
340 |
+
super().__init__()
|
341 |
+
# 定义初始值
|
342 |
+
self.dim = dim
|
343 |
+
self.max_position_embeddings = max_position_embeddings
|
344 |
+
self.base = base
|
345 |
+
# 定义旋转角
|
346 |
+
inv_freq = 1.0 / (self.base ** (torch.arange(0, self.dim, 2, dtype=torch.int64).float().to(device) / self.dim))
|
347 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
348 |
+
|
349 |
+
# Build here to make `torch.jit.trace` work.
|
350 |
+
self._set_cos_sin_cache(
|
351 |
+
seq_len=max_position_embeddings, device=self.inv_freq.device, dtype=torch.get_default_dtype()
|
352 |
+
)
|
353 |
+
# 为seq里面的每个token形成独一无二的旋转角嵌入(外积)
|
354 |
+
def _set_cos_sin_cache(self, seq_len, device, dtype):
|
355 |
+
self.max_seq_len_cached = seq_len
|
356 |
+
t = torch.arange(self.max_seq_len_cached, device=device, dtype=torch.int64).type_as(self.inv_freq)
|
357 |
+
|
358 |
+
freqs = torch.outer(t, self.inv_freq)
|
359 |
+
# 生成角度信息(利用注册机制生成self.cos_cached与sin_cached
|
360 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
361 |
+
self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False)
|
362 |
+
self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False)
|
363 |
+
|
364 |
+
def forward(self, x, seq_len=None):
|
365 |
+
# x: [bs, num_attention_heads, seq_len, head_size]
|
366 |
+
if seq_len > self.max_seq_len_cached:
|
367 |
+
self._set_cos_sin_cache(seq_len=seq_len, device=x.device, dtype=x.dtype)
|
368 |
+
|
369 |
+
return (
|
370 |
+
self.cos_cached[:seq_len].to(dtype=x.dtype),
|
371 |
+
self.sin_cached[:seq_len].to(dtype=x.dtype),
|
372 |
+
)
|
373 |
+
```
|
374 |
+
首先要先生成角度:
|
375 |
+
$$
|
376 |
+
\theta = \left(\frac{1}{10000^{2n/d}}\right)
|
377 |
+
$$
|
378 |
+
|
379 |
+
其中,n表示维度数,其取值范围为[0, 1, ..., d/2-1]
|
380 |
+
<div align=center>
|
381 |
+
<img src='./img/ROPE4.png'>
|
382 |
+
</div>
|
383 |
+
|
384 |
+
然后将上述生成角度与每一个位置乘积,区分一个seq中各个词:其实等价于:
|
385 |
+
$$\theta = \left(\frac{i}{10000^{2n/d}}\right)$$
|
386 |
+
其中: `i`为行数。
|
387 |
+
<div align=center>
|
388 |
+
<img src='./img/ROPE5.png'>
|
389 |
+
</div>
|
390 |
+
|
391 |
+
emb将二者cat起来,得到dim维度,每dim/2一循环:
|
392 |
+
<div align=center>
|
393 |
+
<img src='./img/ROPE6.png'>
|
394 |
+
</div>
|
395 |
+
|
396 |
+
然后,在取出位置编码信息`cos`与`sin`的时候,就是将`seq`的部分切出来,原先设置的1024是最大`pos`编码,每次用的时候只取当下`seq_len`的即可.之前求得外积,是为了保证`seq`里面得每一个词都能有不同的1024个位置编码。
|
397 |
+
<div align=center>
|
398 |
+
<img src='./img/ROPE7.png'>
|
399 |
+
</div>
|
400 |
+
|
401 |
+
进行旋转嵌入:
|
402 |
+
```python
|
403 |
+
# 后半部分和前半部分进行了交换,并且将后半部分的符号取反。
|
404 |
+
def rotate_half(x):
|
405 |
+
"""Rotates half the hidden dims of the input."""
|
406 |
+
x1 = x[..., : x.shape[-1] // 2]
|
407 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
408 |
+
return torch.cat((-x2, x1), dim=-1)
|
409 |
+
|
410 |
+
def apply_rotary_pos_emb(q, k, cos, sin, position_ids, unsqueeze_dim=1):
|
411 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
412 |
+
|
413 |
+
query and key tensors rotated using the Rotary Position Embedding.
|
414 |
+
"""
|
415 |
+
cos = cos[position_ids].unsqueeze(unsqueeze_dim)
|
416 |
+
sin = sin[position_ids].unsqueeze(unsqueeze_dim)
|
417 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
418 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
419 |
+
return q_embed, k_embed
|
420 |
+
```
|
421 |
+
对应公式:
|
422 |
+
<div align=center>
|
423 |
+
<img src='./img/ROPE8.png'>
|
424 |
+
</div>
|
425 |
+
|
426 |
+
其中,下标t则表示位于同一行,也就是同一`seq_len`,对于相邻的两个元素,
|
427 |
+
|
428 |
+
#### 1.3.3.3 读取顺序attention_mask
|
429 |
+
第一步的时候只能看到自己,第二步只能看到0、1...其余的都是负无穷。
|
430 |
+
<div align=center>
|
431 |
+
<img src='./img/Mask1.png'>
|
432 |
+
</div>
|
433 |
+
|
434 |
+
经过softmax,对应负无穷的位置权重为0,从而实现只能从左往右。
|
435 |
+
<div align=center>
|
436 |
+
<img src='./img/Mask2.png'>
|
437 |
+
</div>
|
438 |
+
|
439 |
+
- `attn`形状为(bs,heads,T,T),`values`的形状为(bs,heads,T,hd),最终落实到[30,30]×[30,128]上,30表示一句话的步长,也就是总词数。
|
440 |
+
- `value`里面每一个词有128个维度来描述,对于第一个词,由于`attn`为下三角,所以每一个维度都只有第一个非零元素1进行相乘,其他的都是×0。
|
441 |
+
- - 对于第二行,则是前两个有不同的权值,让value的128个维度分别依据这两个的权重,在128个维度上根据前两行,计算得出output的第二个词(第二步或者第二行)的128个维度.... 这种加权,体现出考虑前词关系。
|
442 |
+
- 第n步则对应有n个权重,用来描述从1到n个步之间的各个关系,进而计算出各个维度。
|
443 |
+
- 每一个矩阵乘法的结果相当于是下一个词的dim,那么score则是根据mask来判断,能通过前几个词对应dim的值从而进行加权,进而得到下一个词的该dim上的值。
|
444 |
+
<div align=center>
|
445 |
+
<img src='./img/Mask3.png'>
|
446 |
+
</div>
|
447 |
+
- 对于推理的过程,问询不一样长没关系,因为所有的权重都是dim-dim,得到的attention_score是一个seq,seq的,权重跟seq的大小没关系。其都是后面的dim维度的参数。
|
448 |
+
- 推理过程的attention_mask可有可无,是一个一个吐,循环cat到下一个,每一次都取最后一个,代表着预测的是下一个token。
|
449 |
+
|
450 |
+
## 1.4 Qwen2 MLP
|
451 |
+
|
452 |
+
<div align=center>
|
453 |
+
<img src='./img/MLP1.png'>
|
454 |
+
</div>
|
455 |
+
|
456 |
+
输入`hidden_state`并行送入两个`Linear`层,其中一个激活一下,再与另一个相乘,最终再经过一个`Linear`,输出最终结果。
|
457 |
+
```python
|
458 |
+
class Qwen2MLP(nn.Module):
|
459 |
+
def __init__(self, config):
|
460 |
+
super().__init__()
|
461 |
+
# 这俩不必多说
|
462 |
+
self.config = config
|
463 |
+
self.hidden_size = config.hidden_size
|
464 |
+
self.intermediate_size = config.intermediate_size
|
465 |
+
|
466 |
+
# 三个全连接层
|
467 |
+
self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
468 |
+
self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
469 |
+
self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
|
470 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
471 |
+
|
472 |
+
def forward(self, x):
|
473 |
+
down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
|
474 |
+
return down_proj
|
475 |
+
```
|
476 |
+
## 1.5 Qwen2RMSNorm
|
477 |
+
计算公式:
|
478 |
+
|
479 |
+
<img src="./img/RMSNorm_formulation.jpg" width="400" height="auto">
|
480 |
+
|
481 |
+
其中:
|
482 |
+
- $x$是层的输入的`hidden_state`
|
483 |
+
- $w_i$ 表示的是`hidden_state`的最后一个维度的值
|
484 |
+
- $n$ 表示上面输入的最后一个维度的数量。
|
485 |
+
- $\epsilon$ 表示是很小的数,防止除0。
|
486 |
+
|
487 |
+
```python
|
488 |
+
class Qwen2RMSNorm(nn.Module): # 标准化层
|
489 |
+
def __init__(self, hidden_size, eps=1e-6):
|
490 |
+
"""
|
491 |
+
Qwen2RMSNorm is equivalent to T5LayerNorm
|
492 |
+
"""
|
493 |
+
super().__init__()
|
494 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
495 |
+
self.variance_epsilon = eps
|
496 |
+
|
497 |
+
def forward(self, hidden_states):
|
498 |
+
input_dtype = hidden_states.dtype
|
499 |
+
hidden_states = hidden_states.to(torch.float32)
|
500 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
501 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
502 |
+
return self.weight * hidden_states.to(input_dtype)
|
503 |
+
```
|
504 |
+
- `torch.rsqrt`表示输入的东西开根的导数。
|
505 |
+
- `.pow(2).mean(-1, keepdim=True)`表示对最后一个维度平方并取均值。
|
data/README_zh-CN.md
ADDED
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div align="center">
|
2 |
+
<img src="https://github.com/InternLM/lmdeploy/assets/36994684/0cf8d00f-e86b-40ba-9b54-dc8f1bc6c8d8" width="600"/>
|
3 |
+
<br /><br />
|
4 |
+
|
5 |
+
[](https://github.com/InternLM/xtuner/stargazers)
|
6 |
+
[](https://github.com/InternLM/xtuner/blob/main/LICENSE)
|
7 |
+
[](https://pypi.org/project/xtuner/)
|
8 |
+
[](https://pypi.org/project/xtuner/)
|
9 |
+
[](https://github.com/InternLM/xtuner/issues)
|
10 |
+
[](https://github.com/InternLM/xtuner/issues)
|
11 |
+
|
12 |
+
👋 加入我们:[](https://cdn.vansin.top/internlm/xtuner.jpg)
|
13 |
+
[](https://twitter.com/intern_lm)
|
14 |
+
[](https://discord.gg/xa29JuW87d)
|
15 |
+
|
16 |
+
🔍 探索我们的模型:
|
17 |
+
[](https://huggingface.co/xtuner)
|
18 |
+
[](https://www.modelscope.cn/organization/xtuner)
|
19 |
+
[](https://openxlab.org.cn/usercenter/xtuner)
|
20 |
+
[](https://www.wisemodel.cn/organization/xtuner)
|
21 |
+
|
22 |
+
[English](README.md) | 简体中文
|
23 |
+
|
24 |
+
</div>
|
25 |
+
|
26 |
+
## 🚀 Speed Benchmark
|
27 |
+
|
28 |
+
- XTuner 与 LLaMA-Factory 在 Llama2-7B 模型上的训练效率对比
|
29 |
+
|
30 |
+
<div align=center>
|
31 |
+
<img src="https://github.com/InternLM/xtuner/assets/41630003/9c9dfdf4-1efb-4daf-84bf-7c379ae40b8b" style="width:80%">
|
32 |
+
</div>
|
33 |
+
|
34 |
+
- XTuner 与 LLaMA-Factory 在 Llama2-70B 模型上的训练效率对比
|
35 |
+
|
36 |
+
<div align=center>
|
37 |
+
<img src="https://github.com/InternLM/xtuner/assets/41630003/5ba973b8-8885-4b72-b51b-c69fa1583bdd" style="width:80%">
|
38 |
+
</div>
|
39 |
+
|
40 |
+
## 🎉 更新
|
41 |
+
- **\[2024/07\]** 支持 [MiniCPM](xtuner/configs/minicpm/) 模型!
|
42 |
+
- **\[2024/07\]** 支持训练 [DPO](https://github.com/InternLM/xtuner/tree/main/xtuner/configs/dpo), [ORPO](https://github.com/InternLM/xtuner/tree/main/xtuner/configs/orpo) 还有 [Reward Model](https://github.com/InternLM/xtuner/tree/main/xtuner/configs/reward_model) ! 并且能够支持打包数据以及序列并行功能! 请参考 [文档](https://xtuner.readthedocs.io/zh-cn/latest/dpo/overview.html) 了解更多信息。
|
43 |
+
- **\[2024/07\]** 支持 [InternLM 2.5](xtuner/configs/internlm/internlm2_5_chat_7b/) 模型!
|
44 |
+
- **\[2024/06\]** 支持 [DeepSeek V2](xtuner/configs/deepseek/deepseek_v2_chat/) models! **训练速度提升一倍!**
|
45 |
+
- **\[2024/04\]** 多模态大模型 [LLaVA-Phi-3-mini](https://huggingface.co/xtuner/llava-phi-3-mini-hf) 发布!快速开始请查阅此[文档](xtuner/configs/llava/phi3_mini_4k_instruct_clip_vit_large_p14_336)!
|
46 |
+
- **\[2024/04\]** 多模态大模型 [LLaVA-Llama-3-8B](https://huggingface.co/xtuner/llava-llama-3-8b) 和 [LLaVA-Llama-3-8B-v1.1](https://huggingface.co/xtuner/llava-llama-3-8b-v1_1) 发布!快速开始请查阅此[文档](xtuner/configs/llava/llama3_8b_instruct_clip_vit_large_p14_336)!
|
47 |
+
- **\[2024/04\]** 支持 [Llama 3](xtuner/configs/llama) 模型!
|
48 |
+
- **\[2024/04\]** 支持序列并行训练策略以实现语言模型超长上下文训练!\[[文档](https://github.com/InternLM/xtuner/blob/docs/docs/zh_cn/acceleration/train_extreme_long_sequence.rst)\] \[[速度基准](https://github.com/InternLM/xtuner/blob/docs/docs/zh_cn/acceleration/benchmark.rst)\]
|
49 |
+
- **\[2024/02\]** 支持 [Gemma](xtuner/configs/gemma) 模型!
|
50 |
+
- **\[2024/02\]** 支持 [Qwen1.5](xtuner/configs/qwen/qwen1_5) 模型!
|
51 |
+
- **\[2024/01\]** 支持 [InternLM2](xtuner/configs/internlm) 模型!同时,最新版的多模态大模型 [LLaVA-Internlm2-7B](https://huggingface.co/xtuner/llava-internlm2-7b) / [20B](https://huggingface.co/xtuner/llava-internlm2-20b) 发布,其表现出强大的性能!
|
52 |
+
- **\[2024/01\]** 支持 [DeepSeek-MoE](https://huggingface.co/deepseek-ai/deepseek-moe-16b-chat) 模型!20GB 显存即可实现 QLoRA 微调,4x80GB 即可实现全参数微调。快速开始请查阅相关[配置文件](xtuner/configs/deepseek/)!
|
53 |
+
- **\[2023/12\]** 🔥 支持多模态模型 VLM([LLaVA-v1.5](https://github.com/haotian-liu/LLaVA))预训练和指令微调!快速开始请查阅此[文档](xtuner/configs/llava/README_zh-CN.md)!
|
54 |
+
- **\[2023/12\]** 🔥 支持 [Mixtral 8x7B](https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1) 模型!快速开始请查阅此[文档](xtuner/configs/mixtral/README.md)!
|
55 |
+
- **\[2023/11\]** 支持 [ChatGLM3-6B](xtuner/configs/chatglm) 模型!
|
56 |
+
- **\[2023/10\]** 支持 [MSAgent-Bench](https://modelscope.cn/datasets/damo/MSAgent-Bench) 数据集,并且微调所得大语言模型可应用至 [Lagent](https://github.com/InternLM/lagent) 框架!
|
57 |
+
- **\[2023/10\]** 优化数据处理逻辑以兼容 `system` 字段,相关细节请查阅[文档](docs/zh_cn/user_guides/dataset_format.md)!
|
58 |
+
- **\[2023/09\]** 支持 [InternLM-20B](xtuner/configs/internlm) 系列模型!
|
59 |
+
- **\[2023/09\]** 支持 [Baichuan2](xtuner/configs/baichuan) 系列模型!
|
60 |
+
- **\[2023/08\]** XTuner 正式发布!众多微调模型已上传至 [HuggingFace](https://huggingface.co/xtuner)!
|
61 |
+
|
62 |
+
## 📖 介绍
|
63 |
+
|
64 |
+
XTuner 是一个高效、灵活、全能的轻量化大模型微调工具库。
|
65 |
+
|
66 |
+
**高效**
|
67 |
+
|
68 |
+
- 支持大语言模型 LLM、多模态图文模型 VLM 的预训练及轻量级微调。XTuner 支持在 8GB 显存下微调 7B 模型,同时也支持多节点跨设备微调更大尺度模型(70B+)。
|
69 |
+
- 自动分发高性能算子(如 FlashAttention、Triton kernels 等)以加速训练吞吐。
|
70 |
+
- 兼容 [DeepSpeed](https://github.com/microsoft/DeepSpeed) 🚀,轻松应用各种 ZeRO 训练优化策略。
|
71 |
+
|
72 |
+
**灵活**
|
73 |
+
|
74 |
+
- 支持多种大语言模型,包括但不限于 [InternLM](https://huggingface.co/internlm)、[Mixtral-8x7B](https://huggingface.co/mistralai)、[Llama 2](https://huggingface.co/meta-llama)、[ChatGLM](https://huggingface.co/THUDM)、[Qwen](https://huggingface.co/Qwen)、[Baichuan](https://huggingface.co/baichuan-inc)。
|
75 |
+
- 支持多模态图文模型 LLaVA 的预训练与微调。利用 XTuner 训得模型 [LLaVA-InternLM2-20B](https://huggingface.co/xtuner/llava-internlm2-20b) 表现优异。
|
76 |
+
- 精心设计的数据管道,兼容任意数据格式,开源数据或自定义数据皆可快速上手。
|
77 |
+
- 支持 [QLoRA](http://arxiv.org/abs/2305.14314)、[LoRA](http://arxiv.org/abs/2106.09685)、全量参数微调等多种微调算法,支撑用户根据具体需求作出最优选择。
|
78 |
+
|
79 |
+
**全能**
|
80 |
+
|
81 |
+
- 支持增量预训练、指令微调与 Agent 微调。
|
82 |
+
- 预定义众多开源对话模版,支持与开源或训练所得模型进行对话。
|
83 |
+
- 训练所得模型可无缝接入部署工具库 [LMDeploy](https://github.com/InternLM/lmdeploy)、大规模评测工具库 [OpenCompass](https://github.com/open-compass/opencompass) 及 [VLMEvalKit](https://github.com/open-compass/VLMEvalKit)。
|
84 |
+
|
85 |
+
## 🔥 支持列表
|
86 |
+
|
87 |
+
<table>
|
88 |
+
<tbody>
|
89 |
+
<tr align="center" valign="middle">
|
90 |
+
<td>
|
91 |
+
<b>模型</b>
|
92 |
+
</td>
|
93 |
+
<td>
|
94 |
+
<b>数据集</b>
|
95 |
+
</td>
|
96 |
+
<td>
|
97 |
+
<b>数据格式</b>
|
98 |
+
</td>
|
99 |
+
<td>
|
100 |
+
<b>微调算法</b>
|
101 |
+
</td>
|
102 |
+
</tr>
|
103 |
+
<tr valign="top">
|
104 |
+
<td align="left" valign="top">
|
105 |
+
<ul>
|
106 |
+
<li><a href="https://huggingface.co/internlm">InternLM 2 / 2.5</a></li>
|
107 |
+
<li><a href="https://huggingface.co/meta-llama">Llama 2 / 3</a></li>
|
108 |
+
<li><a href="https://huggingface.co/collections/microsoft/phi-3-6626e15e9585a200d2d761e3">Phi-3</a></li>
|
109 |
+
<li><a href="https://huggingface.co/THUDM/chatglm2-6b">ChatGLM2</a></li>
|
110 |
+
<li><a href="https://huggingface.co/THUDM/chatglm3-6b">ChatGLM3</a></li>
|
111 |
+
<li><a href="https://huggingface.co/Qwen/Qwen-7B">Qwen</a></li>
|
112 |
+
<li><a href="https://huggingface.co/baichuan-inc/Baichuan2-7B-Base">Baichuan2</a></li>
|
113 |
+
<li><a href="https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1">Mixtral</a></li>
|
114 |
+
<li><a href="https://huggingface.co/deepseek-ai/DeepSeek-V2-Chat">DeepSeek V2</a></li>
|
115 |
+
<li><a href="https://huggingface.co/google">Gemma</a></li>
|
116 |
+
<li><a href="https://huggingface.co/openbmb">MiniCPM</a></li>
|
117 |
+
<li>...</li>
|
118 |
+
</ul>
|
119 |
+
</td>
|
120 |
+
<td>
|
121 |
+
<ul>
|
122 |
+
<li><a href="https://modelscope.cn/datasets/damo/MSAgent-Bench">MSAgent-Bench</a></li>
|
123 |
+
<li><a href="https://huggingface.co/datasets/fnlp/moss-003-sft-data">MOSS-003-SFT</a> 🔧</li>
|
124 |
+
<li><a href="https://huggingface.co/datasets/tatsu-lab/alpaca">Alpaca en</a> / <a href="https://huggingface.co/datasets/silk-road/alpaca-data-gpt4-chinese">zh</a></li>
|
125 |
+
<li><a href="https://huggingface.co/datasets/WizardLM/WizardLM_evol_instruct_V2_196k">WizardLM</a></li>
|
126 |
+
<li><a href="https://huggingface.co/datasets/timdettmers/openassistant-guanaco">oasst1</a></li>
|
127 |
+
<li><a href="https://huggingface.co/datasets/garage-bAInd/Open-Platypus">Open-Platypus</a></li>
|
128 |
+
<li><a href="https://huggingface.co/datasets/HuggingFaceH4/CodeAlpaca_20K">Code Alpaca</a></li>
|
129 |
+
<li><a href="https://huggingface.co/datasets/burkelibbey/colors">Colorist</a> 🎨</li>
|
130 |
+
<li><a href="https://github.com/WangRongsheng/ChatGenTitle">Arxiv GenTitle</a></li>
|
131 |
+
<li><a href="https://github.com/LiuHC0428/LAW-GPT">Chinese Law</a></li>
|
132 |
+
<li><a href="https://huggingface.co/datasets/Open-Orca/OpenOrca">OpenOrca</a></li>
|
133 |
+
<li><a href="https://huggingface.co/datasets/shibing624/medical">Medical Dialogue</a></li>
|
134 |
+
<li>...</li>
|
135 |
+
</ul>
|
136 |
+
</td>
|
137 |
+
<td>
|
138 |
+
<ul>
|
139 |
+
<li><a href="docs/zh_cn/user_guides/incremental_pretraining.md">Incremental Pre-training</a> </li>
|
140 |
+
<li><a href="docs/zh_cn/user_guides/single_turn_conversation.md">Single-turn Conversation SFT</a> </li>
|
141 |
+
<li><a href="docs/zh_cn/user_guides/multi_turn_conversation.md">Multi-turn Conversation SFT</a> </li>
|
142 |
+
</ul>
|
143 |
+
</td>
|
144 |
+
<td>
|
145 |
+
<ul>
|
146 |
+
<li><a href="http://arxiv.org/abs/2305.14314">QLoRA</a></li>
|
147 |
+
<li><a href="http://arxiv.org/abs/2106.09685">LoRA</a></li>
|
148 |
+
<li>全量参数微调</li>
|
149 |
+
<li><a href="https://arxiv.org/abs/2305.18290">DPO</a></li>
|
150 |
+
<li><a href="https://arxiv.org/abs/2403.07691">ORPO</a></li>
|
151 |
+
<li>Reward Model</a></li>
|
152 |
+
</ul>
|
153 |
+
</td>
|
154 |
+
</tr>
|
155 |
+
</tbody>
|
156 |
+
</table>
|
157 |
+
|
158 |
+
## 🛠️ 快速上手
|
159 |
+
|
160 |
+
### 安装
|
161 |
+
|
162 |
+
- 推荐使用 conda 先构建一个 Python-3.10 的虚拟环境
|
163 |
+
|
164 |
+
```bash
|
165 |
+
conda create --name xtuner-env python=3.10 -y
|
166 |
+
conda activate xtuner-env
|
167 |
+
```
|
168 |
+
|
169 |
+
- 通过 pip 安装 XTuner:
|
170 |
+
|
171 |
+
```shell
|
172 |
+
pip install -U xtuner
|
173 |
+
```
|
174 |
+
|
175 |
+
亦可集成 DeepSpeed 安装:
|
176 |
+
|
177 |
+
```shell
|
178 |
+
pip install -U 'xtuner[deepspeed]'
|
179 |
+
```
|
180 |
+
|
181 |
+
- 从源码安装 XTuner:
|
182 |
+
|
183 |
+
```shell
|
184 |
+
git clone https://github.com/InternLM/xtuner.git
|
185 |
+
cd xtuner
|
186 |
+
pip install -e '.[all]'
|
187 |
+
```
|
188 |
+
|
189 |
+
### 微调
|
190 |
+
|
191 |
+
XTuner 支持微调大语言模型。数据集预处理指南请查阅[文档](./docs/zh_cn/user_guides/dataset_prepare.md)。
|
192 |
+
|
193 |
+
- **步骤 0**,准备配置文件。XTuner 提供多个开箱即用的配置文件,用户可以通过下列命令查看:
|
194 |
+
|
195 |
+
```shell
|
196 |
+
xtuner list-cfg
|
197 |
+
```
|
198 |
+
|
199 |
+
或者,如果所提供的配置文件不能满足使用需求,请导出所提供的配置文件并进行相应更改:
|
200 |
+
|
201 |
+
```shell
|
202 |
+
xtuner copy-cfg ${CONFIG_NAME} ${SAVE_PATH}
|
203 |
+
vi ${SAVE_PATH}/${CONFIG_NAME}_copy.py
|
204 |
+
```
|
205 |
+
|
206 |
+
- **步骤 1**,开始微调。
|
207 |
+
|
208 |
+
```shell
|
209 |
+
xtuner train ${CONFIG_NAME_OR_PATH}
|
210 |
+
```
|
211 |
+
|
212 |
+
例如,我们可以利用 QLoRA 算法在 oasst1 数据集上微调 InternLM2.5-Chat-7B:
|
213 |
+
|
214 |
+
```shell
|
215 |
+
# 单卡
|
216 |
+
xtuner train internlm2_5_chat_7b_qlora_oasst1_e3 --deepspeed deepspeed_zero2
|
217 |
+
# 多卡
|
218 |
+
(DIST) NPROC_PER_NODE=${GPU_NUM} xtuner train internlm2_5_chat_7b_qlora_oasst1_e3 --deepspeed deepspeed_zero2
|
219 |
+
(SLURM) srun ${SRUN_ARGS} xtuner train internlm2_5_chat_7b_qlora_oasst1_e3 --launcher slurm --deepspeed deepspeed_zero2
|
220 |
+
```
|
221 |
+
|
222 |
+
- `--deepspeed` 表示使用 [DeepSpeed](https://github.com/microsoft/DeepSpeed) 🚀 来优化训练过程。XTuner 内置了多种策略,包括 ZeRO-1、ZeRO-2、ZeRO-3 等。如果用户期望关闭此功能,请直接移除此参数。
|
223 |
+
|
224 |
+
- 更多示例,请查阅[文档](./docs/zh_cn/user_guides/finetune.md)。
|
225 |
+
|
226 |
+
- **步骤 2**,将保存的 PTH 模型(如果使用的DeepSpeed,则将会是一个文件夹)转换为 HuggingFace 模型:
|
227 |
+
|
228 |
+
```shell
|
229 |
+
xtuner convert pth_to_hf ${CONFIG_NAME_OR_PATH} ${PTH} ${SAVE_PATH}
|
230 |
+
```
|
231 |
+
|
232 |
+
### 对话
|
233 |
+
|
234 |
+
XTuner 提供与大语言模型对话的工具。
|
235 |
+
|
236 |
+
```shell
|
237 |
+
xtuner chat ${NAME_OR_PATH_TO_LLM} --adapter {NAME_OR_PATH_TO_ADAPTER} [optional arguments]
|
238 |
+
```
|
239 |
+
|
240 |
+
例如:
|
241 |
+
|
242 |
+
与 InternLM2.5-Chat-7B 对话:
|
243 |
+
|
244 |
+
```shell
|
245 |
+
xtuner chat internlm/internlm2-chat-7b --prompt-template internlm2_chat
|
246 |
+
```
|
247 |
+
|
248 |
+
更多示例,请查阅[文档](./docs/zh_cn/user_guides/chat.md)。
|
249 |
+
|
250 |
+
### 部署
|
251 |
+
|
252 |
+
- **步骤 0**,将 HuggingFace adapter 合并到大语言模型:
|
253 |
+
|
254 |
+
```shell
|
255 |
+
xtuner convert merge \
|
256 |
+
${NAME_OR_PATH_TO_LLM} \
|
257 |
+
${NAME_OR_PATH_TO_ADAPTER} \
|
258 |
+
${SAVE_PATH} \
|
259 |
+
--max-shard-size 2GB
|
260 |
+
```
|
261 |
+
|
262 |
+
- **步骤 1**,使用任意推理框架部署微调后的大语言模型,例如 [LMDeploy](https://github.com/InternLM/lmdeploy) 🚀:
|
263 |
+
|
264 |
+
```shell
|
265 |
+
pip install lmdeploy
|
266 |
+
python -m lmdeploy.pytorch.chat ${NAME_OR_PATH_TO_LLM} \
|
267 |
+
--max_new_tokens 256 \
|
268 |
+
--temperture 0.8 \
|
269 |
+
--top_p 0.95 \
|
270 |
+
--seed 0
|
271 |
+
```
|
272 |
+
|
273 |
+
🔥 追求速度更快、显存占用更低的推理?欢迎体验 [LMDeploy](https://github.com/InternLM/lmdeploy) 提供的 4-bit 量化!使用指南请见[文档](https://github.com/InternLM/lmdeploy/tree/main#quantization)。
|
274 |
+
|
275 |
+
### 评测
|
276 |
+
|
277 |
+
- 推荐使用一站式平台 [OpenCompass](https://github.com/InternLM/opencompass) 来评测大语言模型,其目前已涵盖 50+ 数据集的约 30 万条题目。
|
278 |
+
|
279 |
+
## 🤝 贡献指南
|
280 |
+
|
281 |
+
我们感谢所有的贡献者为改进和提升 XTuner 所作出的努力。请参考[贡献指南](.github/CONTRIBUTING.md)来了解参与项目贡献的相关指引。
|
282 |
+
|
283 |
+
## 🎖️ 致谢
|
284 |
+
|
285 |
+
- [Llama 2](https://github.com/facebookresearch/llama)
|
286 |
+
- [DeepSpeed](https://github.com/microsoft/DeepSpeed)
|
287 |
+
- [QLoRA](https://github.com/artidoro/qlora)
|
288 |
+
- [LMDeploy](https://github.com/InternLM/lmdeploy)
|
289 |
+
- [LLaVA](https://github.com/haotian-liu/LLaVA)
|
290 |
+
|
291 |
+
## 🖊️ 引用
|
292 |
+
|
293 |
+
```bibtex
|
294 |
+
@misc{2023xtuner,
|
295 |
+
title={XTuner: A Toolkit for Efficiently Fine-tuning LLM},
|
296 |
+
author={XTuner Contributors},
|
297 |
+
howpublished = {\url{https://github.com/InternLM/xtuner}},
|
298 |
+
year={2023}
|
299 |
+
}
|
300 |
+
```
|
301 |
+
|
302 |
+
## 开源许可证
|
303 |
+
|
304 |
+
该项目采用 [Apache License 2.0 开源许可证](LICENSE)。同时,请遵守所使用的模型与数据集的许可证。
|
data/readme.md
ADDED
@@ -0,0 +1,505 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Qwen整体介绍
|
2 |
+
Qwen模型架构讲解直播:[直播链接](https://meeting.tencent.com/v2/cloud-record/share?id=0be29bb2-0648-4aeb-9baa-c9dc91dfc7a6&from=3&is-single=false&record_type=2)
|
3 |
+
|
4 |
+
Qwen的整体架构与Llama2类似,如下图所示:
|
5 |
+

|
6 |
+
|
7 |
+
其中:
|
8 |
+
- `tokenizer`将文本转为词表里面的数值。
|
9 |
+
- 数值经过`embedding`得到一一对应的向量。
|
10 |
+
- `attention_mask`是用来看见左边、右边,双向等等来设定。
|
11 |
+
- 各类下游任务,`Casual`,`seqcls`等,基本都是基础模型`model`后面接对应的`Linear`层,还有损失函数不一样。
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
# 1 Qwen2Config
|
16 |
+
Qwen2Config中包含一些自定义的超参数,例如`vocab_size`,`hidden_size`,`num_hidden_layers`, `num_attention_heads`等。类似于`dict`可以调用里面的超参数:`config.pad_token_id`。
|
17 |
+
## 1.1 Qwen2Model
|
18 |
+
### 1.1.1 初始化
|
19 |
+
|
20 |
+
- 设置了模型的两个属性:`padding_idx`(用于指定填充标记的索引),`vocab_size`(词汇表的大小)
|
21 |
+
- 初始化了模型的嵌入层、解码器层、归一化层
|
22 |
+
- 嵌入层(`nn.Embedding`):模型使用嵌入层将输入的标记映射成密集的向量表示。
|
23 |
+
- 解码器层(`nn.ModuleList()`):模型包含多个解码器层,这些层都是由 `Qwen2DecoderLayer`` 定义
|
24 |
+
- 归一化层 `Qwen2RMSNorm`:归一化层使用的是 Root Mean Square Layer Normalization
|
25 |
+
- 设置了是否使用 `gradient_checkpoint` 主要是用来节省显存
|
26 |
+
- 调用 `post_init()` 完成一些初始化和准备检查的代码
|
27 |
+
|
28 |
+
```python
|
29 |
+
class Qwen2Model(Qwen2PreTrainedModel):
|
30 |
+
def __init__(self, config: Qwen2Config):
|
31 |
+
super().__init__(config)
|
32 |
+
self.padding_idx = config.pad_token_id
|
33 |
+
self.vocab_size = config.vocab_size
|
34 |
+
|
35 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
36 |
+
self.layers = nn.ModuleList(
|
37 |
+
[Qwen2DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
38 |
+
)
|
39 |
+
self.norm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
40 |
+
|
41 |
+
self.gradient_checkpointing = False
|
42 |
+
# Initialize weights and apply final processing
|
43 |
+
self.post_init()
|
44 |
+
```
|
45 |
+
对于`post_init`函数:
|
46 |
+
主要是对参数进行初始化,以及初始化梯度检查点作用
|
47 |
+
```python
|
48 |
+
def post_init(self):
|
49 |
+
"""
|
50 |
+
A method executed at the end of each Transformer model initialization, to execute code that needs the model's
|
51 |
+
modules properly initialized (such as weight initialization).
|
52 |
+
"""
|
53 |
+
self.init_weights()
|
54 |
+
self._backward_compatibility_gradient_checkpointing()
|
55 |
+
```
|
56 |
+
|
57 |
+
### 1.1.2 Forward
|
58 |
+
在此只对核心主干进行讲解:
|
59 |
+
```python
|
60 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
61 |
+
# embed positions
|
62 |
+
hidden_states = inputs_embeds
|
63 |
+
|
64 |
+
for idx, decoder_layer in enumerate(self.layers):
|
65 |
+
# 将所有的hidden_states保存成tuple
|
66 |
+
if output_hidden_states:
|
67 |
+
all_hidden_states += (hidden_states,)
|
68 |
+
# 将hs送入每一层decoder_layer
|
69 |
+
layer_outputs = decoder_layer(
|
70 |
+
hidden_states,
|
71 |
+
attention_mask=attention_mask,
|
72 |
+
position_ids=position_ids,
|
73 |
+
past_key_value=past_key_value,
|
74 |
+
output_attentions=output_attentions,
|
75 |
+
use_cache=use_cache,
|
76 |
+
)
|
77 |
+
# 取出上一层decoder_输出的hs,再传入下一个layer
|
78 |
+
# 只要第一个,第二个是cache的一个类,然后进入下一个layer
|
79 |
+
hidden_states = layer_outputs[0]
|
80 |
+
|
81 |
+
# 将最后layers输出后的hidden_states进行标准化
|
82 |
+
hidden_states = self.norm(hidden_states)
|
83 |
+
|
84 |
+
# 加上最后一层的hidden_states
|
85 |
+
if output_hidden_states:
|
86 |
+
all_hidden_states += (hidden_states,)
|
87 |
+
```
|
88 |
+
- 如果保存`output_hidden_states`的话,就是第一个为`input_ids`进行`emb`,然后保存到`n-1`层的`decoder_layer`的输出`hs`,再加上最后一层`layer`的输出`hs`进行过`norm`后的`hs`.
|
89 |
+
- 最后是以`BaseModelOutputWithPast`的形式输出。
|
90 |
+
|
91 |
+
## 1.2 Qwen2DecoderLayer
|
92 |
+
|
93 |
+
<div align=center>
|
94 |
+
<img src='./img/decoderlayer.png'>
|
95 |
+
</div>
|
96 |
+
|
97 |
+
### 1.2.1 初始化
|
98 |
+
`layer`三件套:`attn`+`MLP`+`norm`
|
99 |
+
|
100 |
+
```python
|
101 |
+
QWEN2_ATTENTION_CLASSES = {
|
102 |
+
"eager": Qwen2Attention, # 一般情况下是这个
|
103 |
+
"flash_attention_2": Qwen2FlashAttention2,
|
104 |
+
"sdpa": Qwen2SdpaAttention,
|
105 |
+
}
|
106 |
+
|
107 |
+
class Qwen2DecoderLayer(nn.Module):
|
108 |
+
def __init__(self, config: Qwen2Config):
|
109 |
+
super().__init__()
|
110 |
+
self.hidden_size = config.hidden_size
|
111 |
+
self.self_attn = QWEN2_ATTENTION_CLASSES[config._attn_implementation](config, layer_idx)
|
112 |
+
|
113 |
+
self.mlp = Qwen2MLP(config)
|
114 |
+
self.input_layernorm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
115 |
+
self.post_attention_layernorm = Qwen2RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
116 |
+
```
|
117 |
+
这里面的`input_layernorm`和`post_attention_layernorm`内容是一样的,只是应用的顺序不一样。
|
118 |
+
### 1.1.2 Forward
|
119 |
+
可配合图食用,效果更佳:
|
120 |
+
- 首先复制一份`hidden_states`为`residual`,然后将`hidden_states`送入`Norm`,再送入`attn`模块。
|
121 |
+
- 得到`attn`的输出后,再复制一份`residual`,再将`hidden_states`送入`Norm`,`mlp`,再与`residual`进行相加。最后输出的就是这个`hidden_states`啦。
|
122 |
+
|
123 |
+
```python
|
124 |
+
residual = hidden_states
|
125 |
+
# 标准化后送入attn
|
126 |
+
hidden_states = self.input_layernorm(hidden_states) # RMSNorm标准化
|
127 |
+
# Self Attention
|
128 |
+
hidden_states, self_attn_weights, present_key_value = self.self_attn(
|
129 |
+
hidden_states=hidden_states,
|
130 |
+
attention_mask=attention_mask,
|
131 |
+
position_ids=position_ids,
|
132 |
+
past_key_value=past_key_value,
|
133 |
+
output_attentions=output_attentions,
|
134 |
+
use_cache=use_cache,
|
135 |
+
**kwargs,
|
136 |
+
)
|
137 |
+
|
138 |
+
# 残差与新的hidden_states相加
|
139 |
+
hidden_states = residual + hidden_states
|
140 |
+
|
141 |
+
# Fully Connected
|
142 |
+
residual = hidden_states
|
143 |
+
# 同样的RMSNorm标准化
|
144 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
145 |
+
hidden_states = self.mlp(hidden_states)
|
146 |
+
hidden_states = residual + hidden_states
|
147 |
+
|
148 |
+
outputs = (hidden_states,)
|
149 |
+
|
150 |
+
return outputs
|
151 |
+
```
|
152 |
+
|
153 |
+
## 1.3 Qwen2Attention
|
154 |
+
<div align=center>
|
155 |
+
<img src='./img/Qwen2Attention.png'>
|
156 |
+
</div>
|
157 |
+
|
158 |
+
### 1.3.1 初始化
|
159 |
+
核心参数解析:
|
160 |
+
- `num_key_value_heads`:表示键值对的头数
|
161 |
+
- `num_key_value_groups`:表示键值对的组数,计算为`num_heads` // `num_key_value_headsGQA`的实现!!
|
162 |
+
- `q_proj`,`k_proj`,`v_proj`,`o_proj`四个`Linear`操作。后续`LoRa`也基本都对他动的刀子.
|
163 |
+
|
164 |
+
```python
|
165 |
+
class Qwen2Attention(nn.Module):
|
166 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
167 |
+
|
168 |
+
def __init__(self, config: Qwen2Config):
|
169 |
+
super().__init__()
|
170 |
+
self.config = config
|
171 |
+
self.layer_idx = layer_idx
|
172 |
+
self.hidden_size = config.hidden_size
|
173 |
+
self.num_heads = config.num_attention_heads
|
174 |
+
self.head_dim = self.hidden_size // self.num_heads
|
175 |
+
self.num_key_value_heads = config.num_key_value_heads
|
176 |
+
self.num_key_value_groups = self.num_heads // self.num_key_value_heads
|
177 |
+
self.max_position_embeddings = config.max_position_embeddings
|
178 |
+
self.rope_theta = config.rope_theta
|
179 |
+
self.is_causal = True
|
180 |
+
self.attention_dropout = config.attention_dropout
|
181 |
+
|
182 |
+
if (self.head_dim * self.num_heads) != self.hidden_size:
|
183 |
+
raise ValueError(
|
184 |
+
f"hidden_size must be divisible by num_heads (got `hidden_size`: {self.hidden_size}"
|
185 |
+
f" and `num_heads`: {self.num_heads})."
|
186 |
+
)
|
187 |
+
self.q_proj = nn.Linear(self.hidden_size, self.num_heads * self.head_dim, bias=config.attention_bias)
|
188 |
+
self.k_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
|
189 |
+
self.v_proj = nn.Linear(self.hidden_size, self.num_key_value_heads * self.head_dim, bias=config.attention_bias)
|
190 |
+
self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=config.attention_bias)
|
191 |
+
|
192 |
+
self.rotary_emb = Qwen2RotaryEmbedding(
|
193 |
+
self.head_dim,
|
194 |
+
max_position_embeddings=self.max_position_embeddings,
|
195 |
+
base=self.rope_theta,
|
196 |
+
)
|
197 |
+
```
|
198 |
+
- `config`里面的参数可直接看`Qwen2Config`里面的介绍
|
199 |
+
|
200 |
+
```python
|
201 |
+
max_position_embeddings (`int`, *optional*, defaults to 32768):
|
202 |
+
The maximum sequence length that this model might ever be used with.
|
203 |
+
|
204 |
+
rope_theta (`float`, *optional*, defaults to 10000.0):
|
205 |
+
The base period of the RoPE embeddings.
|
206 |
+
```
|
207 |
+
### 1.3.2 Forward
|
208 |
+
- 首先将`hidden_states`送入`Linear`中得到`query`、`key`与`value`。
|
209 |
+
- 使用旋转位置嵌入操作`rotary_emb`,使用了旋转位置嵌入的余弦和正弦部分,将他们与`query`和`key`相乘,并将结果相加,从而实现旋转位置嵌入的效果。
|
210 |
+
- 将`key_states`和`value_states`重复`group`次,再执行`dot attn`操作。
|
211 |
+
- 在`dot attn`操作后得到`attn_weights`,加上`attention_mask`从而实现读取掩盖操作,在经过`softmax`与`value_states`相乘。得到`attn_output`。
|
212 |
+
- 再将上述的`attn_output`进行`reshape`操作,送入`o_proj`,得到最终的输出。
|
213 |
+
|
214 |
+
```python
|
215 |
+
# 获取形状信息,hidden_states输入的为(bs,T,hd)
|
216 |
+
bsz, q_len, _ = hidden_states.size()
|
217 |
+
|
218 |
+
# 对hidden_states进行Linear生成query、key、value
|
219 |
+
query_states = self.q_proj(hidden_states)
|
220 |
+
key_states = self.k_proj(hidden_states)
|
221 |
+
value_states = self.v_proj(hidden_states)
|
222 |
+
|
223 |
+
# reshape多头处理--分块--(bs,T,heads,hd_d)
|
224 |
+
query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
|
225 |
+
key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
226 |
+
value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
227 |
+
|
228 |
+
# 将旋转位置嵌入应用于查询和键张量。使用了旋转位置嵌入的余弦和正弦��分,将它们与查询和键张量相乘,并将结果相加,从而实现旋转位置嵌入的效果
|
229 |
+
cos, sin = self.rotary_emb(value_states, seq_len=kv_seq_len)
|
230 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
231 |
+
|
232 |
+
# 先将key_states和value_states重复了num_key_value_groups次
|
233 |
+
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
234 |
+
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
235 |
+
|
236 |
+
# 使用dot attn实现q*kT/hd_d^0.5
|
237 |
+
attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) / math.sqrt(self.head_dim)
|
238 |
+
|
239 |
+
# 然后 attn_weights 加上 attention_mask,实现读取顺序
|
240 |
+
attn_weights = attn_weights + attention_mask
|
241 |
+
|
242 |
+
# softmax + dropout + values_states相乘
|
243 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query_states.dtype)
|
244 |
+
attn_weights = nn.functional.dropout(attn_weights, p=self.attention_dropout, training=self.training)
|
245 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
246 |
+
|
247 |
+
# 转置,修改形状等reshape操作
|
248 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
249 |
+
attn_output = attn_output.reshape(bsz, q_len, self.hidden_size)
|
250 |
+
|
251 |
+
# 最后在进行一次o_proj
|
252 |
+
attn_output = self.o_proj(attn_output)
|
253 |
+
|
254 |
+
# 返回结果
|
255 |
+
return attn_output, attn_weights, past_key_value
|
256 |
+
```
|
257 |
+
|
258 |
+
### 1.3.3 细节Debug
|
259 |
+
#### 1.3.3.1 GQA
|
260 |
+
<div align=center>
|
261 |
+
<img src='./img/GQA.png'>
|
262 |
+
</div>
|
263 |
+
|
264 |
+
> 主旨:GQA和MQA不需要在推理的过程存储那么多的kv cache, 那么kv cache占用的显存就变小,那么我们LLM serving可以处理的请求数量就更多
|
265 |
+
|
266 |
+
1. 定义初始张量
|
267 |
+
```python
|
268 |
+
import torch
|
269 |
+
|
270 |
+
## shape:(batch, seq_len, head, head_dim)
|
271 |
+
query = torch.randn(10, 128, 8, 128)
|
272 |
+
key = torch.randn(10, 128, 2, 128)
|
273 |
+
value = torch.randn(10, 128, 2, 128)
|
274 |
+
|
275 |
+
## 在此设置组数为4
|
276 |
+
groups = query.shape[-2] // key.shape[-2]
|
277 |
+
```
|
278 |
+
2. 之后进行扩展key,value的操作
|
279 |
+
在`GQA`中,`key`和`value`都要比`query`小`group`倍,但是为在后续做矩阵乘法时方便,我们需要先把`key`和`value`的`head`利用expand扩展张量到和`query`相同的维度。方便后续计算。
|
280 |
+
|
281 |
+
```python
|
282 |
+
# 定义输入x, n_rep是需要重复的次数,在这里一般是组数
|
283 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
284 |
+
|
285 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
286 |
+
# dont need repeat here means multi head attention
|
287 |
+
if n_rep == 1:
|
288 |
+
return hidden_states
|
289 |
+
# first we expand x to (bs, seq_len, head, group, head_dim)
|
290 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
291 |
+
# reshape make head -> head * group
|
292 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
293 |
+
```
|
294 |
+
3. 矩阵乘法得到`score`与`output`
|
295 |
+
后面就是征程的`kqv`相乘了
|
296 |
+
```python
|
297 |
+
#(bs, head, seq_len, head_dim)
|
298 |
+
query = query.transpose(1, 2)
|
299 |
+
key = repeat_kv(key.transpose(1, 2), 4)
|
300 |
+
value = repeat_kv(value.transpose(1, 2), 4)
|
301 |
+
scores = torch.matmul(query, key.transpose(2, 3)) / math.sqrt(head_dim)
|
302 |
+
scores = torch.nn.functional.softmax(scores, dim=-1)
|
303 |
+
|
304 |
+
out = torch.matmul(scores, value)
|
305 |
+
#上一步转置了,还得转回去
|
306 |
+
out = out.transpose(1, 2)
|
307 |
+
```
|
308 |
+
**补充:**
|
309 |
+
**为什么要用expand之后再reshape而不能直接用tensor自带的repeat?**
|
310 |
+
- `expand` 方法用于对张量进行扩展,但不实际分配新的内存。它返回的张量与原始张量共享相同的数据
|
311 |
+
- `repeat` 方法通过实际复制数据来扩展张量。它返回的新张量不与原始张量共享数据,扩展后的张量占用了更多的内存。
|
312 |
+
|
313 |
+
|
314 |
+
#### 1.3.3.2 apply_rotary_pos_emb
|
315 |
+
位置编码的含义是对每一个token的每一个dim赋予不同的位置信息。
|
316 |
+
公式定义:
|
317 |
+
<div align=center>
|
318 |
+
<img src='./img/ROPE1.png'>
|
319 |
+
</div>
|
320 |
+
|
321 |
+
概念:通过旋转编码,使得每个token既有相对位置信息,又有绝对位置信息。
|
322 |
+
- 既能以自注意力矩阵偏置的形式作用于 $A_{t,s}$,直接反映两个token的相对位置信息,又能拆解到向量 $q_{t}$ 和 $k_{s}$ 上,通过直接编码token的绝对位置实现。
|
323 |
+
- RoPE本质是实现对特征向量的旋转操作,如果以二维特征向量举例,对于相邻两个token来说,其对应同一个 $\theta$,其定义为:
|
324 |
+
<div align=center>
|
325 |
+
<img src='./img/ROPE2.png'>
|
326 |
+
</div>
|
327 |
+
|
328 |
+
可得,其本质就是: $q_{t}$, $k_{s}$ 旋转后的结果,就是 $q_{t}$, $k_{s}$乘上cos再加上 $q_{t}$, $k_{s}$翻转维度并取反一维后乘上sin。
|
329 |
+
- 对于高纬向量,由于奇、复数维度两两交错实现较为复杂,则现在可简化为将特征维度一切二,如下图所示,在实现过程中对前后各半进行的操作即为rotate_half操作:
|
330 |
+
<div align=center>
|
331 |
+
<img src='./img/ROPE3.png'>
|
332 |
+
</div>
|
333 |
+
|
334 |
+
|
335 |
+
代码实现:
|
336 |
+
先定义旋转角度
|
337 |
+
```python
|
338 |
+
class Qwen2RotaryEmbedding(nn.Module):
|
339 |
+
def __init__(self, dim, max_position_embeddings=2048, base=10000, device=None):
|
340 |
+
super().__init__()
|
341 |
+
# 定义初始值
|
342 |
+
self.dim = dim
|
343 |
+
self.max_position_embeddings = max_position_embeddings
|
344 |
+
self.base = base
|
345 |
+
# 定义旋转角
|
346 |
+
inv_freq = 1.0 / (self.base ** (torch.arange(0, self.dim, 2, dtype=torch.int64).float().to(device) / self.dim))
|
347 |
+
self.register_buffer("inv_freq", inv_freq, persistent=False)
|
348 |
+
|
349 |
+
# Build here to make `torch.jit.trace` work.
|
350 |
+
self._set_cos_sin_cache(
|
351 |
+
seq_len=max_position_embeddings, device=self.inv_freq.device, dtype=torch.get_default_dtype()
|
352 |
+
)
|
353 |
+
# 为seq里面的每个token形成独一无二的旋转角嵌入(外积)
|
354 |
+
def _set_cos_sin_cache(self, seq_len, device, dtype):
|
355 |
+
self.max_seq_len_cached = seq_len
|
356 |
+
t = torch.arange(self.max_seq_len_cached, device=device, dtype=torch.int64).type_as(self.inv_freq)
|
357 |
+
|
358 |
+
freqs = torch.outer(t, self.inv_freq)
|
359 |
+
# 生成角度信息(利用注册机制生成self.cos_cached与sin_cached
|
360 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
361 |
+
self.register_buffer("cos_cached", emb.cos().to(dtype), persistent=False)
|
362 |
+
self.register_buffer("sin_cached", emb.sin().to(dtype), persistent=False)
|
363 |
+
|
364 |
+
def forward(self, x, seq_len=None):
|
365 |
+
# x: [bs, num_attention_heads, seq_len, head_size]
|
366 |
+
if seq_len > self.max_seq_len_cached:
|
367 |
+
self._set_cos_sin_cache(seq_len=seq_len, device=x.device, dtype=x.dtype)
|
368 |
+
|
369 |
+
return (
|
370 |
+
self.cos_cached[:seq_len].to(dtype=x.dtype),
|
371 |
+
self.sin_cached[:seq_len].to(dtype=x.dtype),
|
372 |
+
)
|
373 |
+
```
|
374 |
+
首先要先生成角度:
|
375 |
+
$$
|
376 |
+
\theta = \left(\frac{1}{10000^{2n/d}}\right)
|
377 |
+
$$
|
378 |
+
|
379 |
+
其中,n表示维度数,其取值范围为[0, 1, ..., d/2-1]
|
380 |
+
<div align=center>
|
381 |
+
<img src='./img/ROPE4.png'>
|
382 |
+
</div>
|
383 |
+
|
384 |
+
然后将上述生成角度与每一个位置乘积,区分一个seq中各个词:其实等价于:
|
385 |
+
$$\theta = \left(\frac{i}{10000^{2n/d}}\right)$$
|
386 |
+
其中: `i`为行数。
|
387 |
+
<div align=center>
|
388 |
+
<img src='./img/ROPE5.png'>
|
389 |
+
</div>
|
390 |
+
|
391 |
+
emb将二者cat起来,得到dim维度,每dim/2一循环:
|
392 |
+
<div align=center>
|
393 |
+
<img src='./img/ROPE6.png'>
|
394 |
+
</div>
|
395 |
+
|
396 |
+
然后,在取出位置编码信息`cos`与`sin`的时候,就是将`seq`的部分切出来,原先设置的1024是最大`pos`编码,每次用的时候只取当下`seq_len`的即可.之前求得外积,是为了保证`seq`里面得每一个词都能有不同的1024个位置编码。
|
397 |
+
<div align=center>
|
398 |
+
<img src='./img/ROPE7.png'>
|
399 |
+
</div>
|
400 |
+
|
401 |
+
进行旋转嵌入:
|
402 |
+
```python
|
403 |
+
# 后半部分和前半部分进行了交换,并且将后半部分的符号取反。
|
404 |
+
def rotate_half(x):
|
405 |
+
"""Rotates half the hidden dims of the input."""
|
406 |
+
x1 = x[..., : x.shape[-1] // 2]
|
407 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
408 |
+
return torch.cat((-x2, x1), dim=-1)
|
409 |
+
|
410 |
+
def apply_rotary_pos_emb(q, k, cos, sin, position_ids, unsqueeze_dim=1):
|
411 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
412 |
+
|
413 |
+
query and key tensors rotated using the Rotary Position Embedding.
|
414 |
+
"""
|
415 |
+
cos = cos[position_ids].unsqueeze(unsqueeze_dim)
|
416 |
+
sin = sin[position_ids].unsqueeze(unsqueeze_dim)
|
417 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
418 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
419 |
+
return q_embed, k_embed
|
420 |
+
```
|
421 |
+
对应公式:
|
422 |
+
<div align=center>
|
423 |
+
<img src='./img/ROPE8.png'>
|
424 |
+
</div>
|
425 |
+
|
426 |
+
其中,下标t则表示位于同一行,也就是同一`seq_len`,对于相邻的两个元素,
|
427 |
+
|
428 |
+
#### 1.3.3.3 读取顺序attention_mask
|
429 |
+
第一步的时候只能看到自己,第二步只能看到0、1...其余的都是负无穷。
|
430 |
+
<div align=center>
|
431 |
+
<img src='./img/Mask1.png'>
|
432 |
+
</div>
|
433 |
+
|
434 |
+
经过softmax,对应负无穷的位置权重为0,从而实现只能从左往右。
|
435 |
+
<div align=center>
|
436 |
+
<img src='./img/Mask2.png'>
|
437 |
+
</div>
|
438 |
+
|
439 |
+
- `attn`形状为(bs,heads,T,T),`values`的形状为(bs,heads,T,hd),最终落实到[30,30]×[30,128]上,30表示一句话的步长,也就是总词数。
|
440 |
+
- `value`里面每一个词有128个维度来描述,对于第一个词,由于`attn`为下三角,所以每一个维度都只有第一个非零元素1进行相乘,其他的都是×0。
|
441 |
+
- - 对于第二行,则是前两个有不同的权值,让value的128个维度分别依据这两个的权重,在128个维度上根据前两行,计算得出output的第二个词(第二步或者第二行)的128个维度.... 这种加权,体现出考虑前词关系。
|
442 |
+
- 第n步则对应有n个权重,用来描述从1到n个步之间的各个关系,进而计算出各个维度。
|
443 |
+
- 每一个矩阵乘法的结果相当于是下一个词的dim,那么score则是根据mask来判断,能通过前几个词对应dim的值从而进行加权,进而得到下一个词的该dim上的值。
|
444 |
+
<div align=center>
|
445 |
+
<img src='./img/Mask3.png'>
|
446 |
+
</div>
|
447 |
+
- 对于推理的过程,问询不一样长没关系,因为所有的权重都是dim-dim,得到的attention_score是一个seq,seq的,权重跟seq的大小没关系。其都是后面的dim维度的参数。
|
448 |
+
- 推理过程的attention_mask可有可无,是一个一个吐,循环cat到下一个,每一次都取最后一个,代表着预测的是下一个token。
|
449 |
+
|
450 |
+
## 1.4 Qwen2 MLP
|
451 |
+
|
452 |
+
<div align=center>
|
453 |
+
<img src='./img/MLP1.png'>
|
454 |
+
</div>
|
455 |
+
|
456 |
+
输入`hidden_state`并行送入两个`Linear`层,其中一个激活一下,再与另一个相乘,最终再经过一个`Linear`,输出最终结果。
|
457 |
+
```python
|
458 |
+
class Qwen2MLP(nn.Module):
|
459 |
+
def __init__(self, config):
|
460 |
+
super().__init__()
|
461 |
+
# 这俩不必多说
|
462 |
+
self.config = config
|
463 |
+
self.hidden_size = config.hidden_size
|
464 |
+
self.intermediate_size = config.intermediate_size
|
465 |
+
|
466 |
+
# 三个全连接层
|
467 |
+
self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
468 |
+
self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
469 |
+
self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
|
470 |
+
self.act_fn = ACT2FN[config.hidden_act]
|
471 |
+
|
472 |
+
def forward(self, x):
|
473 |
+
down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
|
474 |
+
return down_proj
|
475 |
+
```
|
476 |
+
## 1.5 Qwen2RMSNorm
|
477 |
+
计算公式:
|
478 |
+
|
479 |
+
<img src="./img/RMSNorm_formulation.jpg" width="400" height="auto">
|
480 |
+
|
481 |
+
其中:
|
482 |
+
- $x$是层的输入的`hidden_state`
|
483 |
+
- $w_i$ 表示的是`hidden_state`的最后一个维度的值
|
484 |
+
- $n$ 表示上面输入的最后一个维度的数量。
|
485 |
+
- $\epsilon$ 表示是很小的数,防止除0。
|
486 |
+
|
487 |
+
```python
|
488 |
+
class Qwen2RMSNorm(nn.Module): # 标准化层
|
489 |
+
def __init__(self, hidden_size, eps=1e-6):
|
490 |
+
"""
|
491 |
+
Qwen2RMSNorm is equivalent to T5LayerNorm
|
492 |
+
"""
|
493 |
+
super().__init__()
|
494 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
495 |
+
self.variance_epsilon = eps
|
496 |
+
|
497 |
+
def forward(self, hidden_states):
|
498 |
+
input_dtype = hidden_states.dtype
|
499 |
+
hidden_states = hidden_states.to(torch.float32)
|
500 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
501 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
502 |
+
return self.weight * hidden_states.to(input_dtype)
|
503 |
+
```
|
504 |
+
- `torch.rsqrt`表示输入的东西开根的导数。
|
505 |
+
- `.pow(2).mean(-1, keepdim=True)`表示对最后一个维度平方并取均值。
|
data/xtuner
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
Subproject commit 90192ffe42612b0f88409432e7b4860294432bcc
|
download_hf.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
# 设置环境变量
|
4 |
+
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
|
5 |
+
|
6 |
+
# 下载模型
|
7 |
+
os.system('huggingface-cli download --resume-download sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 --local-dir /root/model/sentence-transformer')
|
llamaindex_RAG.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
os.environ['NLTK_DATA'] = '/root/nltk_data'
|
3 |
+
|
4 |
+
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
|
5 |
+
from llama_index.core.settings import Settings
|
6 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
7 |
+
from llama_index.legacy.callbacks import CallbackManager
|
8 |
+
from llama_index.llms.openai_like import OpenAILike
|
9 |
+
|
10 |
+
|
11 |
+
# Create an instance of CallbackManager
|
12 |
+
callback_manager = CallbackManager()
|
13 |
+
|
14 |
+
api_base_url = "https://internlm-chat.intern-ai.org.cn/puyu/api/v1/"
|
15 |
+
model = "internlm2.5-latest"
|
16 |
+
api_key = os.getenv("API_KEY")
|
17 |
+
|
18 |
+
# api_base_url = "https://api.siliconflow.cn/v1"
|
19 |
+
# model = "internlm/internlm2_5-7b-chat"
|
20 |
+
# api_key = "请填写 API Key"
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
llm =OpenAILike(model=model, api_base=api_base_url, api_key=api_key, is_chat_model=True,callback_manager=callback_manager)
|
25 |
+
|
26 |
+
|
27 |
+
#初始化一个HuggingFaceEmbedding对象,用于将文本转换为向量表示
|
28 |
+
embed_model = HuggingFaceEmbedding(
|
29 |
+
#指定了一个预训练的sentence-transformer模型的路径
|
30 |
+
model_name="/root/model/sentence-transformer"
|
31 |
+
)
|
32 |
+
#将创建的嵌入模型赋值给全局设置的embed_model属性,
|
33 |
+
#这样在后续的索引构建过程中就会使用这个模型。
|
34 |
+
Settings.embed_model = embed_model
|
35 |
+
|
36 |
+
#初始化llm
|
37 |
+
Settings.llm = llm
|
38 |
+
|
39 |
+
#从指定目录读取所有文档,并加载数据到内存中
|
40 |
+
documents = SimpleDirectoryReader("/root/llamaindex_demo/data").load_data()
|
41 |
+
#创建一个VectorStoreIndex,并使用之前加载的文档来构建索引。
|
42 |
+
# 此索引将文档转换为向量,并存储这些向量以便于快速检索。
|
43 |
+
index = VectorStoreIndex.from_documents(documents)
|
44 |
+
# 创建一个查询引擎,这个引擎可以接收查询并返回相关文档的响应。
|
45 |
+
query_engine = index.as_query_engine()
|
46 |
+
response = query_engine.query("Qwen2Attention是什么?")
|
47 |
+
|
48 |
+
print(response)
|
requirements.txt
ADDED
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This file may be used to create an environment using:
|
2 |
+
# $ conda create --name <env> --file <this file>
|
3 |
+
# platform: linux-64
|
4 |
+
_libgcc_mutex=0.1=main
|
5 |
+
_openmp_mutex=5.1=1_gnu
|
6 |
+
aiohappyeyeballs=2.4.3=pypi_0
|
7 |
+
aiohttp=3.11.7=pypi_0
|
8 |
+
aiosignal=1.3.1=pypi_0
|
9 |
+
altair=5.5.0=pypi_0
|
10 |
+
annotated-types=0.7.0=pypi_0
|
11 |
+
anyio=4.6.2.post1=pypi_0
|
12 |
+
async-timeout=5.0.1=pypi_0
|
13 |
+
attrs=24.2.0=pypi_0
|
14 |
+
beautifulsoup4=4.12.3=pypi_0
|
15 |
+
blinker=1.9.0=pypi_0
|
16 |
+
bzip2=1.0.8=h5eee18b_6
|
17 |
+
ca-certificates=2024.9.24=h06a4308_0
|
18 |
+
cachetools=5.5.0=pypi_0
|
19 |
+
certifi=2024.8.30=pypi_0
|
20 |
+
charset-normalizer=3.4.0=pypi_0
|
21 |
+
click=8.1.7=pypi_0
|
22 |
+
dataclasses-json=0.6.7=pypi_0
|
23 |
+
deprecated=1.2.15=pypi_0
|
24 |
+
dirtyjson=1.0.8=pypi_0
|
25 |
+
distro=1.9.0=pypi_0
|
26 |
+
einops=0.7.0=pypi_0
|
27 |
+
exceptiongroup=1.2.2=pypi_0
|
28 |
+
filelock=3.16.1=pypi_0
|
29 |
+
filetype=1.2.0=pypi_0
|
30 |
+
frozenlist=1.5.0=pypi_0
|
31 |
+
fsspec=2024.10.0=pypi_0
|
32 |
+
gitdb=4.0.11=pypi_0
|
33 |
+
gitpython=3.1.43=pypi_0
|
34 |
+
greenlet=3.1.1=pypi_0
|
35 |
+
h11=0.14.0=pypi_0
|
36 |
+
httpcore=1.0.7=pypi_0
|
37 |
+
httpx=0.27.2=pypi_0
|
38 |
+
huggingface-hub=0.26.2=pypi_0
|
39 |
+
idna=3.10=pypi_0
|
40 |
+
instructorembedding=1.0.1=pypi_0
|
41 |
+
jinja2=3.1.4=pypi_0
|
42 |
+
jiter=0.7.1=pypi_0
|
43 |
+
joblib=1.4.2=pypi_0
|
44 |
+
jsonschema=4.23.0=pypi_0
|
45 |
+
jsonschema-specifications=2024.10.1=pypi_0
|
46 |
+
ld_impl_linux-64=2.40=h12ee557_0
|
47 |
+
libffi=3.4.4=h6a678d5_1
|
48 |
+
libgcc-ng=11.2.0=h1234567_1
|
49 |
+
libgomp=11.2.0=h1234567_1
|
50 |
+
libstdcxx-ng=11.2.0=h1234567_1
|
51 |
+
libuuid=1.41.5=h5eee18b_0
|
52 |
+
llama-cloud=0.1.5=pypi_0
|
53 |
+
llama-index=0.11.20=pypi_0
|
54 |
+
llama-index-agent-openai=0.3.4=pypi_0
|
55 |
+
llama-index-cli=0.3.1=pypi_0
|
56 |
+
llama-index-core=0.11.23=pypi_0
|
57 |
+
llama-index-embeddings-huggingface=0.3.1=pypi_0
|
58 |
+
llama-index-embeddings-instructor=0.2.1=pypi_0
|
59 |
+
llama-index-embeddings-openai=0.2.5=pypi_0
|
60 |
+
llama-index-indices-managed-llama-cloud=0.6.0=pypi_0
|
61 |
+
llama-index-legacy=0.9.48.post4=pypi_0
|
62 |
+
llama-index-llms-openai=0.2.16=pypi_0
|
63 |
+
llama-index-llms-openai-like=0.2.0=pypi_0
|
64 |
+
llama-index-llms-replicate=0.3.0=pypi_0
|
65 |
+
llama-index-multi-modal-llms-openai=0.2.3=pypi_0
|
66 |
+
llama-index-program-openai=0.2.0=pypi_0
|
67 |
+
llama-index-question-gen-openai=0.2.0=pypi_0
|
68 |
+
llama-index-readers-file=0.2.2=pypi_0
|
69 |
+
llama-index-readers-llama-parse=0.3.0=pypi_0
|
70 |
+
llama-parse=0.5.15=pypi_0
|
71 |
+
markdown-it-py=3.0.0=pypi_0
|
72 |
+
markupsafe=3.0.2=pypi_0
|
73 |
+
marshmallow=3.23.1=pypi_0
|
74 |
+
mdurl=0.1.2=pypi_0
|
75 |
+
mpmath=1.3.0=pypi_0
|
76 |
+
multidict=6.1.0=pypi_0
|
77 |
+
mypy-extensions=1.0.0=pypi_0
|
78 |
+
narwhals=1.14.2=pypi_0
|
79 |
+
ncurses=6.4=h6a678d5_0
|
80 |
+
nest-asyncio=1.6.0=pypi_0
|
81 |
+
networkx=3.4.2=pypi_0
|
82 |
+
nltk=3.9.1=pypi_0
|
83 |
+
numpy=1.26.4=pypi_0
|
84 |
+
nvidia-cublas-cu12=12.1.3.1=pypi_0
|
85 |
+
nvidia-cuda-cupti-cu12=12.1.105=pypi_0
|
86 |
+
nvidia-cuda-nvrtc-cu12=12.1.105=pypi_0
|
87 |
+
nvidia-cuda-runtime-cu12=12.1.105=pypi_0
|
88 |
+
nvidia-cudnn-cu12=9.1.0.70=pypi_0
|
89 |
+
nvidia-cufft-cu12=11.0.2.54=pypi_0
|
90 |
+
nvidia-curand-cu12=10.3.2.106=pypi_0
|
91 |
+
nvidia-cusolver-cu12=11.4.5.107=pypi_0
|
92 |
+
nvidia-cusparse-cu12=12.1.0.106=pypi_0
|
93 |
+
nvidia-nccl-cu12=2.21.5=pypi_0
|
94 |
+
nvidia-nvjitlink-cu12=12.4.127=pypi_0
|
95 |
+
nvidia-nvtx-cu12=12.1.105=pypi_0
|
96 |
+
openai=1.55.0=pypi_0
|
97 |
+
openssl=3.0.15=h5eee18b_0
|
98 |
+
packaging=24.2=pypi_0
|
99 |
+
pandas=2.2.3=pypi_0
|
100 |
+
pillow=10.4.0=pypi_0
|
101 |
+
pip=24.2=py310h06a4308_0
|
102 |
+
propcache=0.2.0=pypi_0
|
103 |
+
protobuf=5.26.1=pypi_0
|
104 |
+
pyarrow=18.0.0=pypi_0
|
105 |
+
pydantic=2.10.1=pypi_0
|
106 |
+
pydantic-core=2.27.1=pypi_0
|
107 |
+
pydeck=0.9.1=pypi_0
|
108 |
+
pygments=2.18.0=pypi_0
|
109 |
+
pypdf=4.3.1=pypi_0
|
110 |
+
python=3.10.15=he870216_1
|
111 |
+
python-dateutil=2.9.0.post0=pypi_0
|
112 |
+
pytz=2024.2=pypi_0
|
113 |
+
pyyaml=6.0.2=pypi_0
|
114 |
+
readline=8.2=h5eee18b_0
|
115 |
+
referencing=0.35.1=pypi_0
|
116 |
+
regex=2024.11.6=pypi_0
|
117 |
+
requests=2.32.3=pypi_0
|
118 |
+
rich=13.9.4=pypi_0
|
119 |
+
rpds-py=0.21.0=pypi_0
|
120 |
+
safetensors=0.4.5=pypi_0
|
121 |
+
scikit-learn=1.5.2=pypi_0
|
122 |
+
scipy=1.14.1=pypi_0
|
123 |
+
sentence-transformers=2.7.0=pypi_0
|
124 |
+
setuptools=75.1.0=py310h06a4308_0
|
125 |
+
six=1.16.0=pypi_0
|
126 |
+
smmap=5.0.1=pypi_0
|
127 |
+
sniffio=1.3.1=pypi_0
|
128 |
+
soupsieve=2.6=pypi_0
|
129 |
+
sqlalchemy=2.0.36=pypi_0
|
130 |
+
sqlite=3.45.3=h5eee18b_0
|
131 |
+
streamlit=1.39.0=pypi_0
|
132 |
+
striprtf=0.0.26=pypi_0
|
133 |
+
sympy=1.13.1=pypi_0
|
134 |
+
tenacity=8.5.0=pypi_0
|
135 |
+
threadpoolctl=3.5.0=pypi_0
|
136 |
+
tiktoken=0.8.0=pypi_0
|
137 |
+
tk=8.6.14=h39e8969_0
|
138 |
+
tokenizers=0.20.3=pypi_0
|
139 |
+
toml=0.10.2=pypi_0
|
140 |
+
torch=2.5.0+cu121=pypi_0
|
141 |
+
torchaudio=2.5.0+cu121=pypi_0
|
142 |
+
torchvision=0.20.0+cu121=pypi_0
|
143 |
+
tornado=6.4.2=pypi_0
|
144 |
+
tqdm=4.67.1=pypi_0
|
145 |
+
transformers=4.46.3=pypi_0
|
146 |
+
triton=3.1.0=pypi_0
|
147 |
+
typing-extensions=4.12.2=pypi_0
|
148 |
+
typing-inspect=0.9.0=pypi_0
|
149 |
+
tzdata=2024.2=pypi_0
|
150 |
+
urllib3=2.2.3=pypi_0
|
151 |
+
watchdog=5.0.3=pypi_0
|
152 |
+
wheel=0.44.0=py310h06a4308_0
|
153 |
+
wrapt=1.17.0=pypi_0
|
154 |
+
xz=5.4.6=h5eee18b_1
|
155 |
+
yarl=1.18.0=pypi_0
|
156 |
+
zlib=1.2.13=h5eee18b_1
|
test_internlm.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from openai import OpenAI
|
2 |
+
import os
|
3 |
+
|
4 |
+
base_url = "https://internlm-chat.intern-ai.org.cn/puyu/api/v1/"
|
5 |
+
# api_key = "sk-请填写准确的 token!"
|
6 |
+
api_key = os.getenv("API_KEY")
|
7 |
+
model="internlm2.5-latest"
|
8 |
+
|
9 |
+
# base_url = "https://api.siliconflow.cn/v1"
|
10 |
+
# api_key = "sk-请填写准确的 token!"
|
11 |
+
# model="internlm/internlm2_5-7b-chat"
|
12 |
+
|
13 |
+
client = OpenAI(
|
14 |
+
api_key=api_key ,
|
15 |
+
base_url=base_url,
|
16 |
+
)
|
17 |
+
|
18 |
+
chat_rsp = client.chat.completions.create(
|
19 |
+
model=model,
|
20 |
+
messages=[{"role": "user", "content": "Qwen2Attention是什么?"}],
|
21 |
+
)
|
22 |
+
|
23 |
+
for choice in chat_rsp.choices:
|
24 |
+
print(choice.message.content)
|