From 13c48c45d84a73e4b85b7218a2c5badc2f0c3d3d Mon Sep 17 00:00:00 2001 From: wux-labs <99776865+wux-labs@users.noreply.github.com> Date: Sun, 28 Jul 2024 17:36:31 +0800 Subject: [PATCH] =?UTF-8?q?XTuner=E5=BE=AE=E8=B0=83=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E5=B0=8F=E5=8A=A9=E6=89=8B=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=20(#1365)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * XTuner --- docs/L1/XTuner/readme.md | 657 ++++++------------------ docs/L1/XTuner/task.md | 7 +- docs/L1/XTuner/xtuner_finetune_basic.md | 31 +- tools/xtuner_generate_assistant.py | 2 +- tools/xtuner_streamlit_demo.py | 2 +- 5 files changed, 177 insertions(+), 522 deletions(-) diff --git a/docs/L1/XTuner/readme.md b/docs/L1/XTuner/readme.md index b8603642f..6905bf406 100644 --- a/docs/L1/XTuner/readme.md +++ b/docs/L1/XTuner/readme.md @@ -1,12 +1,34 @@ # XTuner微调个人小助手认知 +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-00.png) + 在本节中,将一步步带领大家体验如何使用 XTuner 完成个人小助手的微调! -> 整个过程大概需要40分钟我们就可以得到一个自己的小助手。 +> 整个过程大概需要90分钟我们就可以得到一个自己的小助手。 + +先看看微调效果: + + + + + + + + + + + + + + + +
微调前微调后
输入请介绍一下你自己请介绍一下你自己
输出
+ +详细闯关任务请访问[闯关任务](./task.md),提交作业助教老师批改后将获得 100 算力点奖励!!! ## 1 微调前置基础 -在进行微调之前,我们需要了解一些基本概念,请访问[XTuner微调前置基础](./xtuner_finetune_basic.md)。 +本节主要重点是带领大家实现个人小助手微调,如果想了解微调相关的基本概念,可以访问[XTuner微调前置基础](./xtuner_finetune_basic.md)。 ## 2 准备工作 @@ -16,54 +38,88 @@ **启动微调**:在确定了自己的微调目标后,我们就可以在 XTuner 的配置库中找到合适的配置文件并进行对应的修改。修改完成后即可一键启动训练!训练好的模型也可以仅仅通过在终端输入一行命令来完成转换和部署工作! -### 2.1 创建虚拟环境 + +### 2.1 开发机准备 + +我们需要前往 [InternStudio](https://studio.intern-ai.org.cn/) 中创建一台开发机进行使用。 + +步骤1:登录InternStudio后,在控制台点击 “创建开发机” 按钮可以进入到开发机的创建界面。 + +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-01.png) + +步骤2:在 “创建开发机” 界面,选择开发机类型:个人开发机,输入开发机名称:XTuner微调,选择开发机镜像:Cuda12.2-conda。 + +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-02.png) + +步骤3:在镜像详情界面,点击 “使用” 链接,确认使用该镜像。 + +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-03.png) + +步骤4:资源配置可以选择 10% (如果有更高资源可以使用,也可以选择更高的资源配置),然后点击 “立即创建” 按钮创建开发机。 + +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-04.png) + +步骤5:创建完成后,在开发机列表中可以看到刚创建的开发机,点击 “进入开发机” 链接可以连接进入到开发机。 + +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-05.png) + +当我们准备好开发机之后,就可以进行下一步的微调任务了。 + +另外,进入开发机之后,请确保自己已经克隆了Tutorial仓库的资料到本地。 + +```bash +mkdir -p /root/InternLM/Tutorial +git clone -b camp3 https://github.com/InternLM/Tutorial /root/InternLM/Tutorial +``` + + +### 2.2 创建虚拟环境 在安装 XTuner 之前,我们需要先创建一个虚拟环境。使用 `Anaconda` 创建一个名为 `xtuner0121` 的虚拟环境,可以直接执行命令。 + ```bash # 创建虚拟环境 conda create -n xtuner0121 python=3.10 -y -# 激活虚拟环境 +# 激活虚拟环境(注意:后续的所有操作都需要在这个虚拟环境中进行) conda activate xtuner0121 # 安装一些必要的库 -pip install torch==2.0.1 torchaudio==2.0.2 torchvision==0.15.2 modelscope==1.15.0 -``` - -如果是在开发机中,也可以直接执行以下命令进行创建: - -```bash -studio-conda -t xtuner0121 -o internlm-base -conda activate xtuner0121 +conda install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 -c pytorch -c nvidia -y +# 安装其他依赖 +pip install transformers==4.39.3 +pip install streamlit==1.36.0 ``` -### 2.2 安装 XTuner +### 2.3 安装 XTuner 虚拟环境创建完成后,就可以安装 XTuner 了。首先,从 Github 上下载源码。 + ```bash # 创建一个目录,用来存放源代码 mkdir -p /root/InternLM/code cd /root/InternLM/code -git clone -b v0.1.21 https://github.com/InternLM/XTuner +git clone -b v0.1.21 https://github.com/InternLM/XTuner /root/InternLM/code/XTuner ``` 其次,进入源码目录,执行安装。 -> 如果速度太慢可以换成 `pip install -e '.[deepspeed]' -i https://mirrors.aliyun.com/pypi/simple/` - ```bash # 进入到源码目录 cd /root/InternLM/code/XTuner +conda activate xtuner0121 # 执行安装 pip install -e '.[deepspeed]' ``` +> 如果速度太慢可以换成 `pip install -e '.[deepspeed]' -i https://mirrors.aliyun.com/pypi/simple/` + 最后,我们可以验证一下安装结果。 @@ -80,7 +136,7 @@ xtuner help 对于很多的初学者而言,安装好环境意味着成功了一大半!因此我们接下来就可以进入我们的下一步,准备好我们需要的模型、数据集和配置文件,并进行微调训练! -### 2.3 模型准备 +### 2.4 模型准备 软件安装好后,我们就可以准备要微调的模型了。 @@ -92,7 +148,7 @@ xtuner help ```bash -# 创建一个目录,用来存放微调的资料 +# 创建一个目录,用来存放微调的所有资料,后续的所有操作都在该路径中进行 mkdir -p /root/InternLM/XTuner cd /root/InternLM/XTuner @@ -106,35 +162,22 @@ ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b Shanghai 这意味着,当我们访问 `Shanghai_AI_Laboratory/internlm2-chat-1_8b` 时,实际上就是在访问 `/root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b` 目录下的内容。通过这种方式,我们无需复制任何数据,就可以直接利用现有的模型文件进行后续的微调操作,从而节省存储空间并简化文件管理。 -如果自己想要微调的模型在开发机中没找到,也可以自己下载相关模型文件。 +模型文件准备好后,我们可以使用`tree`命令来观察目录结构。 -```python -from modelscope import snapshot_download -model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm2-1_8b', cache_dir="/root/InternLM/XTuner/") +```bash +apt-get install -y tree + +tree -l ``` -模型文件准备好后,我们的目录结构应该是这个样子的。 +我们的目录结构应该是这个样子的。
目录结构 ``` ├── Shanghai_AI_Laboratory -│ ├── internlm2-1_8b -│ │ ├── README.md -│ │ ├── config.json -│ │ ├── configuration.json -│ │ ├── configuration_internlm2.py -│ │ ├── generation_config.json -│ │ ├── modeling_internlm2.py -│ │ ├── pytorch_model.bin -│ │ ├── special_tokens_map.json -│ │ ├── tokenization_internlm2.py -│ │ ├── tokenization_internlm2_fast.py -│ │ ├── tokenizer.json -│ │ ├── tokenizer.model -│ │ └── tokenizer_config.json │ └── internlm2-chat-1_8b -> /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b │ ├── README.md │ ├── config.json @@ -157,96 +200,48 @@ model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm2-1_8b', cache_dir > 在目录结构中可以看出,`internlm2-chat-1_8b` 是一个符号链接。 -```bash -tree -l -``` - ## 3 快速开始 这里我们用 `internlm2-chat-1_8b` 模型,通过 `QLoRA` 的方式来微调一个自己的小助手认知作为案例来进行演示。 -首先,看看微调效果: - - - - - - - - - - - - - - - - - - -
微调前微调后
输入请介绍一下你自己请介绍一下你自己
输出你好,我是书生·浦语。我致力于帮助用户解决各种语言相关的问题,包括但不限于语言学习、翻译、文本摘要等。我使用了Transformer模型和深度学习技术,并使用了语言模型作为预训练任务。如果你有任何问题,欢迎随时向我提问。我是伍鲜同志的小助手,内在是上海AI实验室书生·浦语的1.8B大模型哦
网页
-其次,我们需要定义一些基本方法。 - - -- 导入必要的库 - +### 3.1 微调前的模型对话 -```python -import torch -from transformers import AutoTokenizer, AutoModelForCausalLM -``` +我们可以通过网页端的 Demo 来看看微调前 `internlm2-chat-1_8b` 的对话效果。 -- 定义模型加载方法 +首先,我们需要准备一个Streamlit程序的脚本。 +Streamlit程序的完整代码是:[tools/xtuner_streamlit_demo.py](../../../tools/xtuner_streamlit_demo.py)。 -```python -def load_model(model_path): - tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) - model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16, trust_remote_code=True).cuda() - model = model.eval() - return tokenizer, model -``` +然后,我们可以直接启动应用。 -- 定义对话方法 +```bash +conda activate xtuner0121 -```python -messages = [] - -def chat(input_text): - length = 0 - for response, _ in model.stream_chat(tokenizer, input_text, messages): - if response is not None: - print(response[length:], flush=True, end="") - length = len(response) +streamlit run /root/InternLM/Tutorial/tools/xtuner_streamlit_demo.py ``` -### 3.1 微调前的模型对话 - -首先来看看 `internlm2-chat-1_8b` 的对话演示。 - -- 模型加载 +运行后,在访问前,我们还需要做的就是将端口映射到本地。 +通过如图所示的地方,获取开发机的端口和密码。 -```python -tokenizer, model = load_model("/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b") -``` +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-09.png) -- 对话 +然后在本地使用 PowerShell 或者命令行终端,执行以下命令: +> 其中,`8501`是Streamlit程序的服务端口,`43551`需要替换为自己的开发机的端口。 -```python -chat("请介绍一下你自己") +```bash +ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p 43551 ``` -- 释放缓存 +然后再输入开发机的root密码。 +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-10.png) -```python -del tokenizer, model +最后,我们就可以在本地通过浏览器访问:http://127.0.0.1:8501 来进行对话了。 -torch.cuda.empty_cache() -``` +![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-11.png) ### 3.2 指令跟随微调 @@ -256,27 +251,23 @@ torch.cuda.empty_cache() 为了让模型能够认清自己的身份弟位,在询问自己是谁的时候按照我们预期的结果进行回复,我们就需要通过在微调数据集中大量加入这样的数据。我们准备一个数据集文件`datas/assistant.json`,文件内容为对话数据。 + ```bash +cd /root/InternLM/XTuner mkdir -p datas touch datas/assistant.json ``` -为了增强微调效果,可以将对话数据复制多条。 +为了简化数据文件准备,我们也可以通过脚本生成的方式来准备数据。创建一个脚本文件 `xtuner_generate_assistant.py` : -```python -[ - {"conversation": [{"input": "请介绍一下你自己", "output": "我是伍鲜同志的小助手,内在是上海AI实验室书生·浦语的1.8B大模型哦"}]}, - {"conversation": [{"input": "你在实战营做什么", "output": "我在这里帮助伍鲜同志完成XTuner微调个人小助手的任务"}]}, -] -``` -为了简化数据文件准备,我们也可以通过脚本生成的方式来准备数据。创建一个脚本文件 `xtuner_generate_assistant.py` ,输入脚本内容并保存: +```bash +cd /root/InternLM/XTuner +touch xtuner_generate_assistant.py +``` -> 或者可以直接复制 [tools/xtuner_generate_assistant.py](../../../tools/xtuner_generate_assistant.py) -> ```bash -> cp ../../../tools/xtuner_generate_assistant.py ./ ->``` +输入脚本内容并保存:
xtuner_generate_assistant.py @@ -287,7 +278,7 @@ import json # 设置用户的名字 name = '伍鲜同志' # 设置需要重复添加的数据次数 -n = 4650 +n = 3750 # 初始化数据 data = [ @@ -311,9 +302,29 @@ with open('datas/assistant.json', 'w', encoding='utf-8') as f:
+> 或者可以直接复制 [tools/xtuner_generate_assistant.py](../../../tools/xtuner_generate_assistant.py) +> ```bash +> cd /root/InternLM/XTuner +> cp /root/InternLM/Tutorial/tools/xtuner_generate_assistant.py ./ +>``` + +为了训练出自己的小助手,需要将脚本中`name`后面的内容修改为你自己的名称。 + +```diff +# 将对应的name进行修改(在第4行的位置) +- name = '伍鲜同志' ++ name = "你自己的名称" +``` + +> 假如想要让微调后的模型能够完完全全认识到你的身份,我们还可以把第6行的`n`的值调大一点。不过`n`值太大的话容易导致过拟合,无法有效回答其他问题。 + 然后执行该脚本来生成数据文件。 + ```bash +cd /root/InternLM/XTuner +conda activate xtuner0121 + python xtuner_generate_assistant.py ``` @@ -324,20 +335,6 @@ python xtuner_generate_assistant.py ``` ├── Shanghai_AI_Laboratory -│ ├── internlm2-1_8b -│ │ ├── README.md -│ │ ├── config.json -│ │ ├── configuration.json -│ │ ├── configuration_internlm2.py -│ │ ├── generation_config.json -│ │ ├── modeling_internlm2.py -│ │ ├── pytorch_model.bin -│ │ ├── special_tokens_map.json -│ │ ├── tokenization_internlm2.py -│ │ ├── tokenization_internlm2_fast.py -│ │ ├── tokenizer.json -│ │ ├── tokenizer.model -│ │ └── tokenizer_config.json │ └── internlm2-chat-1_8b -> /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b │ ├── README.md │ ├── config.json @@ -355,6 +352,7 @@ python xtuner_generate_assistant.py │ └── tokenizer_config.json ├── datas │ └── assistant.json +├── xtuner_generate_assistant.py ```
@@ -374,6 +372,8 @@ XTuner 提供多个开箱即用的配置文件,可以通过以下命令查看 ```bash +conda activate xtuner0121 + xtuner list-cfg -p internlm2 ``` @@ -400,6 +400,9 @@ xtuner list-cfg -p internlm2 ```bash +cd /root/InternLM/XTuner +conda activate xtuner0121 + xtuner copy-cfg internlm2_chat_1_8b_qlora_alpaca_e3 . ``` @@ -410,20 +413,6 @@ xtuner copy-cfg internlm2_chat_1_8b_qlora_alpaca_e3 . ``` ├── Shanghai_AI_Laboratory -│ ├── internlm2-1_8b -│ │ ├── README.md -│ │ ├── config.json -│ │ ├── configuration.json -│ │ ├── configuration_internlm2.py -│ │ ├── generation_config.json -│ │ ├── modeling_internlm2.py -│ │ ├── pytorch_model.bin -│ │ ├── special_tokens_map.json -│ │ ├── tokenization_internlm2.py -│ │ ├── tokenization_internlm2_fast.py -│ │ ├── tokenizer.json -│ │ ├── tokenizer.model -│ │ └── tokenizer_config.json │ └── internlm2-chat-1_8b -> /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b │ ├── README.md │ ├── config.json @@ -442,6 +431,7 @@ xtuner copy-cfg internlm2_chat_1_8b_qlora_alpaca_e3 . ├── datas │ └── assistant.json ├── internlm2_chat_1_8b_qlora_alpaca_e3_copy.py +├── xtuner_generate_assistant.py ``` @@ -545,7 +535,8 @@ alpaca_en = dict( > 可以直接复制到当前目录。 > ```bash -> cp ../../../configs/internlm2_chat_1_8b_qlora_alpaca_e3_copy.py ./ +> cd /root/InternLM/XTuner +> cp /root/InternLM/Tutorial/configs/internlm2_chat_1_8b_qlora_alpaca_e3_copy.py ./ >```
@@ -786,6 +777,9 @@ log_processor = dict(by_epoch=False) ```bash +cd /root/InternLM/XTuner +conda activate xtuner0121 + xtuner train ./internlm2_chat_1_8b_qlora_alpaca_e3_copy.py ``` @@ -828,7 +822,14 @@ xtuner train ./internlm2_chat_1_8b_qlora_alpaca_e3_copy.py ```bash -pth_file=`ls -t ./work_dirs/internlm2_chat_1_8b_qlora_alpaca_e3_copy/*.pth | head -n 1` && MKL_SERVICE_FORCE_INTEL=1 MKL_THREADING_LAYER=GNU xtuner convert pth_to_hf ./internlm2_chat_1_8b_qlora_alpaca_e3_copy.py ${pth_file} ./hf +cd /root/InternLM/XTuner +conda activate xtuner0121 + +# 先获取最后保存的一个pth文件 +pth_file=`ls -t ./work_dirs/internlm2_chat_1_8b_qlora_alpaca_e3_copy/*.pth | head -n 1` +export MKL_SERVICE_FORCE_INTEL=1 +export MKL_THREADING_LAYER=GNU +xtuner convert pth_to_hf ./internlm2_chat_1_8b_qlora_alpaca_e3_copy.py ${pth_file} ./hf ``` 模型格式转换完成后,我们的目录结构应该是这样子的。 @@ -870,11 +871,14 @@ pth_file=`ls -t ./work_dirs/internlm2_chat_1_8b_qlora_alpaca_e3_copy/*.pth | hea | --device {device_name} | 这里指的就是device的名称,可选择的有cuda、cpu和auto,默认为cuda即使用gpu进行运算 | | --is-clip | 这个参数主要用于确定模型是不是CLIP模型,假如是的话就要加上,不是就不需要添加 | -> CLIP(Contrastive Language–Image Pre-training)模型是 OpenAI 开发的一种预训练模型,它能够理解图像和描述它们的文本之间的关系。CLIP 通过在大规模数据集上学习图像和对应文本之间的对应关系,从而实现了对图像内容的理解和分类,甚至能够根据文本提示生成图像。 - ```bash -MKL_SERVICE_FORCE_INTEL=1 MKL_THREADING_LAYER=GNU xtuner convert merge /root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b ./hf ./merged --max-shard-size 2GB +cd /root/InternLM/XTuner +conda activate xtuner0121 + +export MKL_SERVICE_FORCE_INTEL=1 +export MKL_THREADING_LAYER=GNU +xtuner convert merge /root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b ./hf ./merged --max-shard-size 2GB ``` 模型合并完成后,我们的目录结构应该是这样子的。 @@ -905,364 +909,35 @@ MKL_SERVICE_FORCE_INTEL=1 MKL_THREADING_LAYER=GNU xtuner convert merge /root/Int ### 3.3 微调后的模型对话 +微调完成后,我们可以再次运行`xtuner_streamlit_demo.py`脚本来观察微调后的对话效果,不过在运行之前,我们需要将脚本中的模型路径修改为微调后的模型的路径。 -```python -tokenizer, model = load_model("./merged") -``` - - -```python -chat("请介绍一下你自己") -``` - - -```python -chat("你在实战营做什么") -``` - - -```python -chat("介绍一下成都") -``` - -可以看到,通过指令微调,我们成功得到了一个自己的小助手。 - - -```python -del tokenizer, model - -torch.cuda.empty_cache() -``` - -## 4 Web Demo 部署 - -除了在终端中对模型进行测试,我们其实还可以在网页端的 Demo 进行对话。 - -首先,我们需要安装所需要的依赖。 - - -```python -pip install streamlit==1.36.0 -``` - -其次,我们需要准备一个Streamlit程序的脚本。 - -Streamlit程序的完整代码是:[tools/xtuner_streamlit_demo.py](../../../tools/xtuner_streamlit_demo.py)。 - -> 可以直接复制到当前目录。 -> ```bash -> cp ../../../tools/xtuner_streamlit_demo.py ./ ->``` - -
-xtuner_streamlit_demo.py - - -```python -import copy -import warnings -from dataclasses import asdict, dataclass -from typing import Callable, List, Optional - -import streamlit as st -import torch -from torch import nn -from transformers.generation.utils import (LogitsProcessorList, - StoppingCriteriaList) -from transformers.utils import logging - -from transformers import AutoTokenizer, AutoModelForCausalLM # isort: skip - -logger = logging.get_logger(__name__) - - -model_name_or_path = "./merged" - -@dataclass -class GenerationConfig: - # this config is used for chat to provide more diversity - max_length: int = 2048 - top_p: float = 0.75 - temperature: float = 0.1 - do_sample: bool = True - repetition_penalty: float = 1.000 - - -@torch.inference_mode() -def generate_interactive( - model, - tokenizer, - prompt, - generation_config: Optional[GenerationConfig] = None, - logits_processor: Optional[LogitsProcessorList] = None, - stopping_criteria: Optional[StoppingCriteriaList] = None, - prefix_allowed_tokens_fn: Optional[Callable[[int, torch.Tensor], - List[int]]] = None, - additional_eos_token_id: Optional[int] = None, - **kwargs, -): - inputs = tokenizer([prompt], padding=True, return_tensors='pt') - input_length = len(inputs['input_ids'][0]) - for k, v in inputs.items(): - inputs[k] = v.cuda() - input_ids = inputs['input_ids'] - _, input_ids_seq_length = input_ids.shape[0], input_ids.shape[-1] - if generation_config is None: - generation_config = model.generation_config - generation_config = copy.deepcopy(generation_config) - model_kwargs = generation_config.update(**kwargs) - bos_token_id, eos_token_id = ( # noqa: F841 # pylint: disable=W0612 - generation_config.bos_token_id, - generation_config.eos_token_id, - ) - if isinstance(eos_token_id, int): - eos_token_id = [eos_token_id] - if additional_eos_token_id is not None: - eos_token_id.append(additional_eos_token_id) - has_default_max_length = kwargs.get( - 'max_length') is None and generation_config.max_length is not None - if has_default_max_length and generation_config.max_new_tokens is None: - warnings.warn( - f"Using 'max_length''s default ({repr(generation_config.max_length)}) \ - to control the generation length. " - 'This behaviour is deprecated and will be removed from the \ - config in v5 of Transformers -- we' - ' recommend using `max_new_tokens` to control the maximum \ - length of the generation.', - UserWarning, - ) - elif generation_config.max_new_tokens is not None: - generation_config.max_length = generation_config.max_new_tokens + \ - input_ids_seq_length - if not has_default_max_length: - logger.warn( # pylint: disable=W4902 - f"Both 'max_new_tokens' (={generation_config.max_new_tokens}) " - f"and 'max_length'(={generation_config.max_length}) seem to " - "have been set. 'max_new_tokens' will take precedence. " - 'Please refer to the documentation for more information. ' - '(https://huggingface.co/docs/transformers/main/' - 'en/main_classes/text_generation)', - UserWarning, - ) - - if input_ids_seq_length >= generation_config.max_length: - input_ids_string = 'input_ids' - logger.warning( - f"Input length of {input_ids_string} is {input_ids_seq_length}, " - f"but 'max_length' is set to {generation_config.max_length}. " - 'This can lead to unexpected behavior. You should consider' - " increasing 'max_new_tokens'.") - - # 2. Set generation parameters if not already defined - logits_processor = logits_processor if logits_processor is not None \ - else LogitsProcessorList() - stopping_criteria = stopping_criteria if stopping_criteria is not None \ - else StoppingCriteriaList() - - logits_processor = model._get_logits_processor( - generation_config=generation_config, - input_ids_seq_length=input_ids_seq_length, - encoder_input_ids=input_ids, - prefix_allowed_tokens_fn=prefix_allowed_tokens_fn, - logits_processor=logits_processor, - ) - - stopping_criteria = model._get_stopping_criteria( - generation_config=generation_config, - stopping_criteria=stopping_criteria) - logits_warper = model._get_logits_warper(generation_config) - - unfinished_sequences = input_ids.new(input_ids.shape[0]).fill_(1) - scores = None - while True: - model_inputs = model.prepare_inputs_for_generation( - input_ids, **model_kwargs) - # forward pass to get next token - outputs = model( - **model_inputs, - return_dict=True, - output_attentions=False, - output_hidden_states=False, - ) - - next_token_logits = outputs.logits[:, -1, :] - - # pre-process distribution - next_token_scores = logits_processor(input_ids, next_token_logits) - next_token_scores = logits_warper(input_ids, next_token_scores) - - # sample - probs = nn.functional.softmax(next_token_scores, dim=-1) - if generation_config.do_sample: - next_tokens = torch.multinomial(probs, num_samples=1).squeeze(1) - else: - next_tokens = torch.argmax(probs, dim=-1) - - # update generated ids, model inputs, and length for next step - input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1) - model_kwargs = model._update_model_kwargs_for_generation( - outputs, model_kwargs, is_encoder_decoder=False) - unfinished_sequences = unfinished_sequences.mul( - (min(next_tokens != i for i in eos_token_id)).long()) - - output_token_ids = input_ids[0].cpu().tolist() - output_token_ids = output_token_ids[input_length:] - for each_eos_token_id in eos_token_id: - if output_token_ids[-1] == each_eos_token_id: - output_token_ids = output_token_ids[:-1] - response = tokenizer.decode(output_token_ids) - - yield response - # stop when each sentence is finished - # or if we exceed the maximum length - if unfinished_sequences.max() == 0 or stopping_criteria( - input_ids, scores): - break - - -def on_btn_click(): - del st.session_state.messages - - -@st.cache_resource -def load_model(): - model = (AutoModelForCausalLM.from_pretrained(model_name_or_path, - trust_remote_code=True).to( - torch.bfloat16).cuda()) - tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, - trust_remote_code=True) - return model, tokenizer - - -def prepare_generation_config(): - with st.sidebar: - max_length = st.slider('Max Length', - min_value=8, - max_value=32768, - value=2048) - top_p = st.slider('Top P', 0.0, 1.0, 0.75, step=0.01) - temperature = st.slider('Temperature', 0.0, 1.0, 0.1, step=0.01) - st.button('Clear Chat History', on_click=on_btn_click) - - generation_config = GenerationConfig(max_length=max_length, - top_p=top_p, - temperature=temperature) - - return generation_config - - -user_prompt = '<|im_start|>user\n{user}<|im_end|>\n' -robot_prompt = '<|im_start|>assistant\n{robot}<|im_end|>\n' -cur_query_prompt = '<|im_start|>user\n{user}<|im_end|>\n\ - <|im_start|>assistant\n' - - -def combine_history(prompt): - messages = st.session_state.messages - meta_instruction = ('') - total_prompt = f"<|im_start|>system\n{meta_instruction}<|im_end|>\n" - for message in messages: - cur_content = message['content'] - if message['role'] == 'user': - cur_prompt = user_prompt.format(user=cur_content) - elif message['role'] == 'robot': - cur_prompt = robot_prompt.format(robot=cur_content) - else: - raise RuntimeError - total_prompt += cur_prompt - total_prompt = total_prompt + cur_query_prompt.format(user=prompt) - return total_prompt - - -def main(): - # torch.cuda.empty_cache() - print('load model begin.') - model, tokenizer = load_model() - print('load model end.') - - - st.title('InternLM2-Chat-1.8B') - - generation_config = prepare_generation_config() - - # Initialize chat history - if 'messages' not in st.session_state: - st.session_state.messages = [] - - # Display chat messages from history on app rerun - for message in st.session_state.messages: - with st.chat_message(message['role'], avatar=message.get('avatar')): - st.markdown(message['content']) - - # Accept user input - if prompt := st.chat_input('What is up?'): - # Display user message in chat message container - with st.chat_message('user'): - st.markdown(prompt) - real_prompt = combine_history(prompt) - # Add user message to chat history - st.session_state.messages.append({ - 'role': 'user', - 'content': prompt, - }) - - with st.chat_message('robot'): - message_placeholder = st.empty() - for cur_response in generate_interactive( - model=model, - tokenizer=tokenizer, - prompt=real_prompt, - additional_eos_token_id=92542, - **asdict(generation_config), - ): - # Display robot response in chat message container - message_placeholder.markdown(cur_response + '▌') - message_placeholder.markdown(cur_response) - # Add robot response to chat history - st.session_state.messages.append({ - 'role': 'robot', - 'content': cur_response, # pylint: disable=undefined-loop-variable - }) - torch.cuda.empty_cache() - - -if __name__ == '__main__': - main() - +```diff +# 直接修改脚本文件第18行 +- model_name_or_path = "/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b" ++ model_name_or_path = "/root/InternLM/XTuner/merged" ``` -
- 然后,我们可以直接启动应用。 ```bash -streamlit run xtuner_streamlit_demo.py -``` - -运行后,在访问前,我们还需要做的就是将端口映射到本地。 - -通过如图所示的地方,获取开发机的端口和密码。 +conda activate xtuner0121 -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-09.png) +streamlit run /root/InternLM/Tutorial/tools/xtuner_streamlit_demo.py +``` -然后在本地使用 PowerShell 或者命令行终端,执行以下命令: +运行后,确保端口映射正常,如果映射已断开则需要重新做一次端口映射。 -> 其中,`8501`是Streamlit程序的服务端口,`43551`需要替换为自己的开发机的端口。 ```bash ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p 43551 ``` -然后再输入开发机的root密码。 - -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-10.png) - -最后,我们就可以在本地通过浏览器访问:http://127.0.0.1:8501 来进行对话了。 +最后,通过浏览器访问:http://127.0.0.1:8501 来进行对话了。 ![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-12.png) -## 5 小结 +## 4 小结 经过本节的学习,带领着大家跑通了 XTuner 的完整流程,我们学会了指令跟随微调,并且训练出了一个自己小助手,是不是很有意思! @@ -1270,6 +945,6 @@ ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p 43551 关于XTuner的更多高级进阶知识,请访问[XTuner微调高级进阶](./xtuner_finetune_advance.md)。 -## 6 作业 +## 5 作业 作业请访问[作业](./task.md)。 diff --git a/docs/L1/XTuner/task.md b/docs/L1/XTuner/task.md index db967cc8c..f6b85ad21 100644 --- a/docs/L1/XTuner/task.md +++ b/docs/L1/XTuner/task.md @@ -13,4 +13,9 @@ - 在资源允许的情况下,尝试实现多卡微调与分布式微调(选做) - 将自我认知的模型上传到 OpenXLab,并将应用部署到 OpenXLab(优秀学员必做) -OpenXLab 部署教程:https://github.com/InternLM/Tutorial/tree/camp2/tools/openxlab-deploy +> OpenXLab 部署教程:https://github.com/InternLM/Tutorial/tree/camp2/tools/openxlab-deploy + +## 闯关材料提交 (完成任务并且提交材料视为闯关成功) + +- 请将作业发布到知乎、CSDN等任一社交媒体,将作业链接提交到以下问卷,助教老师批改后将获得 100 算力点奖励!!! +- 提交地址:https://aicarrier.feishu.cn/share/base/form/shrcnZ4bQ4YmhEtMtnKxZUcf1vd \ No newline at end of file diff --git a/docs/L1/XTuner/xtuner_finetune_basic.md b/docs/L1/XTuner/xtuner_finetune_basic.md index b65890e7d..d0a636ca6 100644 --- a/docs/L1/XTuner/xtuner_finetune_basic.md +++ b/docs/L1/XTuner/xtuner_finetune_basic.md @@ -16,11 +16,11 @@ 在大模型的下游应用中,经常会用到两种微调模式:**增量预训练** 和 **指令跟随** 。 -1. **增量预训练** +**增量预训练** 增量预训练是一种在已有预训练模型(比如:InternLM基座模型)的基础上,利用特定领域的数据进行进一步训练的方法。它的目的是在保持模型原有能力的同时,注入新的领域知识,进一步优化现有的预训练模型,从而提升模型在特定领域任务中的表现(比如:InternLM垂类基座模型)。增量预训练模型能够接受少量的新数据进行更新并适应新的任务,而不需要重新训练整个模型,这种方式可以很好地利用现有的预训练模型的知识,并在新数据上获得更好的性能。 -2. **指令跟随** +**指令跟随** 指令跟随是指让模型根据用户输入的指令来执行相应的操作。模型通过对大量自然语言指令和相应操作的数据进行训练,学习如何将指令分解为具体的子任务,并选择合适的模块来执行这些任务(比如:InternLM垂类对话模型)。 @@ -142,29 +142,4 @@ xtuner convert pth_to_hf $CONFIG $PATH_TO_PTH_MODEL $SAVE_PATH_TO_HF_MODEL xtuner convert merge $LLM $ADAPTER $SAVE_PATH ``` -## 2 创建开发机 - -我们需要前往 [InternStudio](https://studio.intern-ai.org.cn/) 中创建一台开发机进行使用。 - -步骤1:登录InternStudio后,在控制台点击 “创建开发机” 按钮可以进入到开发机的创建界面。 - -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-01.png) - -步骤2:在 “创建开发机” 界面,选择开发机类型:个人开发机,输入开发机名称:XTuner微调,选择开发机镜像:Cuda12.2-conda。 - -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-02.png) - -步骤3:在镜像详情界面,点击 “使用” 链接,确认使用该镜像。 - -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-03.png) - -步骤4:资源配置可以选择 10% (如果有更高资源可以使用,也可以选择更高的资源配置),然后点击 “立即创建” 按钮创建开发机。 - -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-04.png) - -步骤5:创建完成后,在开发机列表中可以看到刚创建的开发机,点击 “进入开发机” 链接可以连接进入到开发机。 - -![](https://raw.githubusercontent.com/wux-labs/ImageHosting/main/XTuner/image-05.png) - -当我们有了这些前置知识和服务器之后,就可以进行下一步的微调任务了。 - +当我们有了这些前置知识之后,就可以进行下一步的微调任务了。 diff --git a/tools/xtuner_generate_assistant.py b/tools/xtuner_generate_assistant.py index cee736e37..efdc44cf4 100644 --- a/tools/xtuner_generate_assistant.py +++ b/tools/xtuner_generate_assistant.py @@ -3,7 +3,7 @@ # 设置用户的名字 name = '伍鲜同志' # 设置需要重复添加的数据次数 -n = 4650 +n = 3750 # 初始化数据 data = [ diff --git a/tools/xtuner_streamlit_demo.py b/tools/xtuner_streamlit_demo.py index a8381f342..28e16890b 100644 --- a/tools/xtuner_streamlit_demo.py +++ b/tools/xtuner_streamlit_demo.py @@ -15,7 +15,7 @@ logger = logging.get_logger(__name__) -model_name_or_path = "./merged" +model_name_or_path = "/root/InternLM/XTuner/Shanghai_AI_Laboratory/internlm2-chat-1_8b" @dataclass class GenerationConfig: