所有tag为书生大模型的文档,连同本文档在内,为书生大模型实战营训练内容,文档中的内容并不局限于实战营本身,但算力平台均首选上海AI实验室开发的云端集成开发环境InternStudio,开发手册和InternStudio算力平台的相关内容可以点击链接跳转。
1.微调
1.1 什么是微调
模型微调是一种机器学习技术,它通过在预训练模型的基础上进行额外训练,使模型适应特定的任务或数据集。这种方法非常高效,因为它利用了已经在大规模数据上预训练的模型的知识,而无需从头开始训练一个全新的模型。
微调模型的步骤通常如下:
- 选择预训练模型:
- 通常选用在大型数据集(如ImageNet、C4、COCO等)上训练好的通用模型。
- 这些模型可以是图像领域的卷积神经网络(如ResNet、EfficientNet),自然语言处理领域的Transformer模型(如BERT、GPT)等。
- 准备特定任务数据集:
- 将要应用的任务的数据集整理好,例如分类任务、生成任务、预测任务的数据。
- 调整模型架构(可选):
- 根据任务需求,可以添加或修改模型的最后几层。例如,在分类任务中,可能需要替换最后的全连接层以适应新的类别。
- 训练模型:
- 以更小的学习率对模型进行进一步训练,使模型在特定数据集上优化性能。
- 使用技术如冻结部分预训练层来保留原始模型的知识,逐步解冻以适应新任务。
- 验证和测试:
- 在验证数据集上评估微调后的模型性能,避免过拟合。
1.2 微调的分类
从参数规模的角度,大模型的微调分成两条技术路线:
- 一条是对全量的参数,进行全量的训练,称之为叫全量微调FFT(Full Fine Tuning)。
- 一条是只对部分的参数进行训练,这条路径叫PEFT(Parameter-Efficient Fine Tuning)
FFT的原理,就是用特定的数据,对大模型进行训练,最大的优点就是上述特定数据领域的表现会好很多。但FFT也会带来一些问题,影响比较大的问题,主要有以下两个:
- 训练的成本会比较高,因为微调的参数量跟预训练的是一样的多的;
- 一个是叫灾难性遗忘(Catastrophic Forgetting),用特定训练数据去微调可能会把这个领域的表现变好,但也可能会把原来表现好的别的领域的能力变差。
PEFT主要想解决的问题,就是FFT存在的上述两个问题,PEFT也是目前比较主流的微调方案。
1.3 主流的PEFT方法
主流的PEFT方法包括但不限于以下几种:
- LoRA/Low-Rank Adaptation(低秩适配)
- QLoRA/Quantized LoRA(量化低秩适配)
- Adapter Tuning(适配器调整)
- Prefix Tuning(前缀调整)
- Prompt Tuning(提示调整)
- P-Tuning(参数化提示调整)
- P-Tuning v2(参数化提示调整第二版)
| 名称 | 参数量 | 核心内容 | 优势 | 劣势 |
|---|---|---|---|---|
| LoRA | 极小(<1% FFT 参数量) | 通过对部分权重矩阵进行低秩分解,实现轻量化微调。 | 高效、节省显存,适用于多任务,多场景。 | 需要额外设计低秩参数,可能对某些任务有性能限制。 |
| QLoRA | 极小(<<1% FFT 参数量) | 在LoRA基础上结合4-bit量化,进一步减少资源需求。 | 超低硬件需求,支持大模型微调,训练速度快。 | 量化可能导致精度损失,适配大模型时需要精心调参。 |
| Adapter Tuning | 小(<5% FFT 参数量) | 在模型层之间插入可训练的适配器模块,保持主模型参数不变。 | 模块化设计,可扩展性强,适合多任务和多语言环境。 | 插入模块会增加推理时的延迟,性能提升依赖适配器设计质量。 |
| Prefix Tuning | 极小(<1% FFT 参数量) | 插入可训练的前缀向量,调整生成模型的输入表示。 | 高效轻量化,适合自然语言生成任务。 | 对判别任务效果较差,前缀的优化过程可能不稳定。 |
| Prompt Tuning | 极小(<0.1% FFT 参数量) | 学习优化的提示词,直接引导预训练模型完成任务。 | 参数量极小,方法简单,适合大模型。 | 表达能力有限,仅对大规模模型效果显著,对小模型表现较弱。 |
| P-Tuning | 极小(<1% FFT 参数量) | 使用连续可训练的嵌入向量代替离散提示,提升表达能力。 | 灵活高效,对分类与生成任务均有效。 | 对模型适配性依赖较高,小规模模型的效果可能不理想。 |
| P-Tuning v2 | 极小(<1% FFT 参数量) | 为大型语言模型优化的 P-Tuning 方法,提升效率和适用性。 | 高效广泛适用,适合分类、生成、理解等任务,优化大模型效果显著。 | 对模型规模有依赖,训练仍需一定资源,任务泛化性可能受限。 |
具体的说明以后会额外出一篇文章。
这次的项目使用Xtuner框架应用LoRA来微调。
XTuner是一个高效、灵活、全能的轻量化大模型微调工具库:
- 支持大语言模型LLM、多模态图文模型VLM的预训练及轻量级微调。XTuner支持在8GB显存下微调7B模型,同时也支持多节点跨设备微调更大尺度模型(70B+)。
- 自动分发高性能算子(如FlashAttention、Triton kernels等)以加速训练吞吐。
- 兼容DeepSpeed,轻松应用各种ZeRO训练优化策略。
2.环境构建
2.1 虚拟环境准备
cd ~
git clone https://github.com/InternLM/Tutorial.git -b camp4
mkdir -p /root/finetune && cd /root/finetune
conda create -n xtuner-env python=3.10 -y
conda activate xtuner-env
2.2 安装Xtuner
cd /root/Tutorial/docs/L1/XTuner
pip install -r requirements.txt
为了验证XTuner是否安装正确,可以使用命令打印配置文件:
xtuner list-cfg

3.数据准备
mkdir -p /root/finetune/data && cd /root/finetune/data
cp -r /root/Tutorial/data/assistant_Tuner.jsonl /root/finetune/data
此时 finetune 文件夹下应该有如下结构:
finetune
├── data
└── assistant_Tuner.jsonl

打开该change_script.py文件后将下面的内容复制进去。
import json
import argparse
from tqdm import tqdm
def process_line(line, old_text, new_text):
# 解析 JSON 行
data = json.loads(line)
# 递归函数来处理嵌套的字典和列表
def replace_text(obj):
if isinstance(obj, dict):
return {k: replace_text(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [replace_text(item) for item in obj]
elif isinstance(obj, str):
return obj.replace(old_text, new_text)
else:
return obj
# 处理整个 JSON 对象
processed_data = replace_text(data)
# 将处理后的对象转回 JSON 字符串
return json.dumps(processed_data, ensure_ascii=False)
def main(input_file, output_file, old_text, new_text):
with open(input_file, 'r', encoding='utf-8') as infile, \
open(output_file, 'w', encoding='utf-8') as outfile:
# 计算总行数用于进度条
total_lines = sum(1 for _ in infile)
infile.seek(0) # 重置文件指针到开头
# 使用 tqdm 创建进度条
for line in tqdm(infile, total=total_lines, desc="Processing"):
processed_line = process_line(line.strip(), old_text, new_text)
outfile.write(processed_line + '\n')
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Replace text in a JSONL file.")
parser.add_argument("input_file", help="Input JSONL file to process")
parser.add_argument("output_file", help="Output file for processed JSONL")
parser.add_argument("--old_text", default="尖米", help="Text to be replaced")
parser.add_argument("--new_text", default="ArtemisYi", help="Text to replace with")
args = parser.parse_args()
main(args.input_file, args.output_file, args.old_text, args.new_text)
其中parser.add_argument("--new_text", default="ArtemisYi", help="Text to replace with")中的default可以调整为自己想要修改的名称。
此时data文件夹下应该有如下结构:
|-- /finetune/data/
|-- assistant_Tuner.jsonl
|-- assistant_Tuner_change.jsonl
修改完毕以后可以检查一下内容:

4.训练
4.1 准备模型
在InternStudio开发机中的已经提供了微调模型,可以直接软链接即可。如果使用其他算力平台需要另外下载。
本模型位于/root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat。
mkdir /root/finetune/models
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat /root/finetune/models/internlm2_5-7b-chat
4.2 修改Config
获取官方写好的 config:
cd /root/finetune
mkdir ./config
cd config
xtuner copy-cfg internlm2_5_chat_7b_qlora_alpaca_e3 ./
修改下述部分:
#######################################################################
# PART 1 Settings #
#######################################################################
- pretrained_model_name_or_path = 'internlm/internlm2_5-7b-chat'
+ pretrained_model_name_or_path = '/root/finetune/models/internlm2_5-7b-chat'
- alpaca_en_path = 'tatsu-lab/alpaca'
+ alpaca_en_path = '/root/finetune/data/assistant_Tuner_change.jsonl'
evaluation_inputs = [
- '请给我介绍五个上海的景点', 'Please tell me five scenic spots in Shanghai'
+ '请介绍一下你自己', 'Please introduce yourself'
]
#######################################################################
# PART 3 Dataset & Dataloader #
#######################################################################
alpaca_en = dict(
type=process_hf_dataset,
- dataset=dict(type=load_dataset, path=alpaca_en_path),
+ dataset=dict(type=load_dataset, path='json', data_files=dict(train=alpaca_en_path)),
tokenizer=tokenizer,
max_length=max_length,
- dataset_map_fn=alpaca_map_fn,
+ dataset_map_fn=None,
template_map_fn=dict(
type=template_map_fn_factory, template=prompt_template),
remove_unused_columns=True,
shuffle_before_pack=True,
pack_to_max_length=pack_to_max_length,
use_varlen_attn=use_varlen_attn)
除此之外,还可以对一些重要的参数进行调整,包括学习率(lr)、训练的轮数(max_epochs)等等。
常用的参数介绍如下:
| 参数名 | 解释 |
|---|---|
| data_path | 数据路径或 HuggingFace 仓库名 |
| max_length | 单条数据最大 Token 数,超过则截断 |
| pack_to_max_length | 是否将多条短数据拼接到 max_length,提高 GPU 利用率 |
| accumulative_counts | 梯度累积,每多少次 backward 更新一次参数 |
| sequence_parallel_size | 并行序列处理的大小,用于模型训练时的序列并行 |
| batch_size | 每个设备上的批量大小 |
| dataloader_num_workers | 数据加载器中工作进程的数量 |
| max_epochs | 训练的最大轮数 |
| optim_type | 优化器类型,例如 AdamW |
| lr | 学习率 |
| betas | 优化器中的 beta 参数,控制动量和平方梯度的移动平均 |
| weight_decay | 权重衰减系数,用于正则化和避免过拟合 |
| max_norm | 梯度裁剪的最大范数,用于防止梯度爆炸 |
| warmup_ratio | 预热的比例,学习率在这个比例的训练过程中线性增加到初始学习率 |
| save_steps | 保存模型的步数间隔 |
| save_total_limit | 保存的模型总数限制,超过限制时删除旧的模型文件 |
| prompt_template | 模板提示,用于定义生成文本的格式或结构 |
| ...... | ...... |
如果想充分利用显卡资源,可以将
max_length和batch_size这两个参数调大。但需要注意的是,在训练chat模型时调节参数batch_size有可能会影响对话模型的效果。
4.3 启动微调
当准备好了所有内容,只需要将使用xtuner train命令令即可开始训练。
xtuner train命令用于启动模型微调进程。该命令需要一个参数:CONFIG用于指定微调配置文件。这里我们修改好的配置文件internlm2_5_chat_7b_qlora_alpaca_e3_copy.py。
训练过程中产生的所有文件,包括日志、配置文件、检查点文件、微调后的模型等,默认保存在work_dirs目录下,也可以通过添加--work-dir指定特定的文件保存位置。--deepspeed则为使用deepspeed,deepspeed可以节约显存。
cd /root/finetune
conda activate xtuner-env
xtuner train ./config/internlm2_5_chat_7b_qlora_alpaca_e3_copy.py --deepspeed deepspeed_zero2 --work-dir ./work_dirs/assistTuner
接下来就是耐心等待,微调过程中还可以看到一些信息,例如轮次Iter和损失loss:
12/10 15:28:29 - mmengine - INFO - Iter(train) [780/939] lr: 1.4840e-05 eta: 0:12:12 time: 4.5796 data_time: 0.0140 memory: 11730 loss: 0.2370
12/10 15:29:15 - mmengine - INFO - Iter(train) [790/939] lr: 1.3083e-05 eta: 0:11:26 time: 4.5687 data_time: 0.0100 memory: 11730 loss: 0.2500
12/10 15:30:01 - mmengine - INFO - Iter(train) [800/939] lr: 1.1430e-05 eta: 0:10:39 time: 4.5588 data_time: 0.0116 memory: 11730 loss: 0.2193
12/10 15:30:48 - mmengine - INFO - Iter(train) [810/939] lr: 9.8817e-06 eta: 0:09:54 time: 4.7273 data_time: 0.0144 memory: 11730 loss: 0.2068
12/10 15:31:33 - mmengine - INFO - Iter(train) [820/939] lr: 8.4409e-06 eta: 0:09:07 time: 4.5511 data_time: 0.0130 memory: 11730 loss: 0.2250
12/10 15:32:20 - mmengine - INFO - Iter(train) [830/939] lr: 7.1089e-06 eta: 0:08:21 time: 4.6294 data_time: 0.0143 memory: 11730 loss: 0.2308
12/10 15:33:06 - mmengine - INFO - Iter(train) [840/939] lr: 5.8874e-06 eta: 0:07:35 time: 4.6024 data_time: 0.0092 memory: 11730 loss: 0.2344
12/10 15:33:52 - mmengine - INFO - Iter(train) [850/939] lr: 4.7778e-06 eta: 0:06:49 time: 4.5943 data_time: 0.0163 memory: 11730 loss: 0.2197
12/10 15:34:37 - mmengine - INFO - Iter(train) [860/939] lr: 3.7814e-06 eta: 0:06:03 time: 4.5849 data_time: 0.0122 memory: 11730 loss: 0.2687
12/10 15:35:23 - mmengine - INFO - Iter(train) [870/939] lr: 2.8995e-06 eta: 0:05:17 time: 4.5491 data_time: 0.0170 memory: 11730 loss: 0.2202
12/10 15:36:09 - mmengine - INFO - Iter(train) [880/939] lr: 2.1330e-06 eta: 0:04:31 time: 4.5675 data_time: 0.0121 memory: 11730 loss: 0.2414
12/10 15:36:55 - mmengine - INFO - Iter(train) [890/939] lr: 1.4828e-06 eta: 0:03:45 time: 4.6092 data_time: 0.0168 memory: 11730 loss: 0.1916
12/10 15:37:41 - mmengine - INFO - Iter(train) [900/939] lr: 9.4987e-07 eta: 0:02:59 time: 4.6338 data_time: 0.0240 memory: 11730 loss: 0.2071
12/10 15:38:27 - mmengine - INFO - Iter(train) [910/939] lr: 5.3467e-07 eta: 0:02:13 time: 4.6206 data_time: 0.0148 memory: 11730 loss: 0.2238
12/10 15:39:14 - mmengine - INFO - Iter(train) [920/939] lr: 2.3775e-07 eta: 0:01:27 time: 4.6329 data_time: 0.0139 memory: 11730 loss: 0.2395
12/10 15:40:00 - mmengine - INFO - Iter(train) [930/939] lr: 5.9455e-08 eta: 0:00:41 time: 4.6166 data_time: 0.0140 memory: 11730 loss: 0.2418
4.4 权重转换
模型转换的本质其实就是将原本使用Pytorch训练出来的模型权重文件转换为目前通用的 HuggingFace格式文件,那么可以通过以下命令来实现一键转换。
可以使用xtuner convert pth_to_hf命令来进行模型格式转换。
xtuner convert pth_to_hf命令用于进行模型格式转换。该命令需要三个参数:CONFIG表示微调的配置文件,PATH_TO_PTH_MODEL表示微调的模型权重文件路径,即要转换的模型权重,SAVE_PATH_TO_HF_MODEL表示转换后的HuggingFace格式文件的保存路径。
除此之外,我们其实还可以在转换的命令中添加几个额外的参数,包括:
| 参数名 | 解释 |
|---|---|
| --fp32 | 代表以fp32的精度开启,假如不输入则默认为fp16 |
| --max-shard-size {GB} | 代表每个权重文件最大的大小(默认为2GB) |
cd /root/finetune/work_dirs/assistTuner
conda activate xtuner-env
# 先获取最后保存的一个pth文件
pth_file=`ls -t /root/finetune/work_dirs/assistTuner/*.pth | head -n 1 | sed 's/:$//'`
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
xtuner convert pth_to_hf ./internlm2_5_chat_7b_qlora_alpaca_e3_copy.py ${pth_file} ./hf
完成后的结构目录如下:
├── hf
│ ├── README.md
│ ├── adapter_config.json
│ ├── adapter_model.bin
│ └── xtuner_config.py

转换完成后,可以看到模型被转换为HuggingFace中常用的.bin格式文件,这就代表着文件成功被转化为HuggingFace格式了。
此时,hf文件夹即为我们平时所理解的所谓“LoRA模型文件”
可以简单理解:LoRA模型文件=Adapter
4.5 模型合并
对于LoRA或者QLoRA微调出来的模型其实并不是一个完整的模型,而是一个额外的层(Adapter),训练完的这个层最终还是要与原模型进行合并才能被正常的使用。
对于全量微调的模型(full)其实是不需要进行整合这一步的,因为全量微调修改的是原模型的权重而非微调一个新的Adapter,因此是不需要进行模型整合的。
在XTuner中提供了一键合并的命令xtuner convert merge,在使用前需要准备好三个路径,包括原模型的路径、训练好的Adapter层的(模型格式转换后的)路径以及最终保存的路径。
xtuner convert merge命令用于合并模型。该命令需要三个参数:LLM表示原模型路径,ADAPTER表示Adapter层的路径,SAVE_PATH表示合并后的模型最终的保存路径。
在模型合并这一步还有其他很多的可选参数,包括:
| 参数名 | 解释 |
|---|---|
| --max-shard-size {GB} | 代表每个权重文件最大的大小(默认为2GB) |
| --device {device_name} | 这里指的就是device的名称,可选择的有cuda、cpu和auto,默认为cuda即使用gpu进行运算 |
| --is-clip | 这个参数主要用于确定模型是不是CLIP模型,假如是的话就要加上,不是就不需要添加 |
cd /root/finetune/work_dirs/assistTuner
conda activate xtuner-env
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
xtuner convert merge /root/finetune/models/internlm2_5-7b-chat ./hf ./merged --max-shard-size 2GB
模型合并完成后的目录结构如下:
├── merged
│ ├── README.md
│ ├── config.json
│ ├── configuration.json
│ ├── configuration_internlm2.py
│ ├── generation_config.json
│ ├── modeling_internlm2.py
│ ├── pytorch_model-00001-of-00008.bin
│ ├── pytorch_model-00002-of-00008.bin
│ ├── pytorch_model-00003-of-00008.bin
│ ├── pytorch_model-00004-of-00008.bin
│ ├── pytorch_model-00005-of-00008.bin
│ ├── pytorch_model-00006-of-00008.bin
│ ├── pytorch_model-00007-of-00008.bin
│ ├── pytorch_model-00008-of-00008.bin
│ ├── pytorch_model.bin.index.json
│ ├── special_tokens_map.json
│ ├── tokenization_internlm2.py
│ ├── tokenization_internlm2_fast.py
│ ├── tokenizer.json
│ ├── tokenizer.model
│ └── tokenizer_config.json

在模型合并完成后,就可以看到最终的模型和原模型文件夹非常相似,包括了分词器、权重文件、配置信息等等。
5.模型WebUI对话
微调完成后,可以再次运行xtuner_streamlit_demo.py脚本来观察微调后的对话效果。
将脚本中的模型路径修改为微调后的模型的路径。
cd ~/Tutorial/tools/L1_XTuner_code

# 直接修改脚本文件第33行
- model_name_or_path = "Shanghai_AI_Laboratory/internlm2_5-7b-chat"
+ model_name_or_path = "/root/finetune/work_dirs/assistTuner/merged"
然后可以直接启动应用。
conda activate xtuner-env
pip install streamlit==1.31.0
streamlit run /root/Tutorial/tools/L1_XTuner_code/xtuner_streamlit_demo.py
运行后,确保端口映射正常,如果映射已断开则需要重新做一次端口映射。
ssh -CNg -L 8501:127.0.0.1:8501 root@ssh.intern-ai.org.cn -p *****
最后,通过浏览器访问:http://127.0.0.1:8501(或者http://localhost:8501/)来进行对话了。

可以看到模型自我认知已经成功修改了。
Comments
评论
Loading comments...
登录后可以评论。 Login