1.微调前置基础
在上一讲L1.4中,我们使用检索增强技术,给模型引入额外的信息来让大模型的输出更加准确
这次,我们采用微调(fine-tuning)来适应新的任务或者数据。
微调是在预训练模型的基础上,将模型中一些层的权重参数进行调整,来适应新的数据或者任务。
微调有两种范式:增量预训练与指令跟随
增量预训练是一种在已有预训练模型(比如:InternLM基座模型)的基础上,利用特定领域的数据进行进一步训练的方法。它的目的是在保持模型原有能力的同时,注入新的领域知识,进一步优化现有的预训练模型,从而提升模型在特定领域任务中的表现
指令跟随是指让模型根据用户输入的指令来执行相应的操作。模型通过对大量自然语言指令和相应操作的数据进行训练,学习如何将指令分解为具体的子任务,并选择合适的模块来执行这些任务
1.1 微调技术
大多数大型语言模型(LLM)的参数规模巨大,且规模日益增大,导致模型的训练和微调成本高昂,直接训练需要耗费大量计算资源和费用。LoRA和QLoRA两种微调技术是两种主流的微调技术。
1.2.1 LoRA简介
LoRA(Low-Rank Adaptation)是一种使用低精度权重对大型预训练语言模型进行微调的技术,它的核心思想是在不改变原有模型权重的情况下,通过添加少量新参数来进行微调。这种方法降低了模型的存储需求,也降低了计算成本,实现了对大模型的快速适应,同时保持了模型性能。
其缺点是可能会丢失原始模型的高阶特征信息,因此准确性可能降低。
1.2.2 QLoRA简介
QLoRA(Quantized LoRA)微调技术是对LoRA的一种改进,它通过引入高精度权重和可学习的低秩适配器来提高模型的准确性。并且在LoRA的基础上,引入了量化技术,可以进一步减少微调过程中的计算量与存储空间。
本次实验使用的微调工具是XTuner
2. 准备工作
2.1 创建虚拟环境
# 创建虚拟环境
conda create -n xtuner0121 python=3.10 -y
# 激活虚拟环境(注意:后续的所有操作都需要在这个虚拟环境中进行)
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
首先从Github上下载源码
# 创建一个目录,用来存放源代码
mkdir -p /root/InternLM/code
cd /root/InternLM/code
git clone -b v0.1.21 https://github.com/InternLM/XTuner /root/InternLM/code/XTuner
进入源码目录,执行安装。
# 进入到源码目录
cd /root/InternLM/code/XTuner
conda activate xtuner0121
# 执行安装
pip install -e '.[deepspeed]'
2.3 模型准备
采用InternStudio上面的开发机,开发机中已经提供了模型的本地文件(地址/root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b)
可以通过以下代码一键通过符号链接的方式链接到模型文件,这样既节省了空间,也便于管理。(两者其实是同一个文件)
# 创建一个目录,用来存放微调的所有资料,后续的所有操作都在该路径中进行
mkdir -p /root/InternLM/XTuner
cd /root/InternLM/XTuner
mkdir -p Shanghai_AI_Laboratory
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b Shanghai_AI_Laboratory/internlm2-chat-1_8b
3. 指令跟随微调
使用internlm2-chat-1_8b
模型,通过QLoRA
来微调一个自己的小助手的认知
3.1 微调前的模型对话
首先使用streamlit来启动这个模型
conda activate xtuner0121
streamlit run /root/InternLM/Tutorial/tools/xtuner_streamlit_demo.py
微调之前的效果如下:
3.2 指令跟随微调
3.2.1 准备数据文献
我们需要通过在微调数据集中大量加入我们预期的数据,让模型能够按照我们预期的结果进行回复。
准备数据集文件datas/assistant.json
,文件内容为对话数据
cd /root/InternLM/XTuner
mkdir -p datas
touch datas/assistant.json
我们可以采用脚本生成的方式来准备数据。脚本文件xtuner_generate_assistant.py
:
import json
# 设置用户的名字
name = 'younger'
# 设置需要重复添加的数据次数
n = 8000
# 初始化数据
data = [
{
"conversation": [{
"input": "请介绍一下你自己", "output": "我是{}的小助手,内在是上海AI实验室书生·浦语的1.8B大模型哦".format(name)}]},
{
"conversation": [{
"input": "你在实战营做什么", "output": "我在这里帮助{}完成XTuner微调个人小助手的任务".format(name)}]}
]
# 通过循环,将初始化的对话数据重复添加到data列表中
for i in range(n):
data.append(data[0])
data.append(data[1])
# 将data列表中的数据写入到'datas/assistant.json'文件中
with open('datas/assistant.json', 'w', encoding='utf-8') as f:
# 使用json.dump方法将数据以JSON格式写入文件
# ensure_ascii=False 确保中文字符正常显示
# indent=4 使得文件内容格式化,便于阅读
json.dump(data, f, ensure_ascii=False, indent=4)
运行该脚本之后,数据集内容与文件的目录如下所示(使用方法是在终端输入tree -l):
3.2.2 准备配置文件
在准备好了模型和数据集后,我们就要根据我们选择的微调方法结合微调方案来找到与我们最匹配的配置文件了,从而减少我们对配置文件的修改量。
3.2.2.1 列出支持的配置文件
可以通过以下命令查看XTuner内置提供的配置文件,其中,参数-p或者-pattern表示模式匹配,后面跟随的内容将在所有的配置文件里进行模糊匹配搜索。
xtuner list-cfg -p internlm2
3.2.2.2 对配置文件进行修改
整体配置文件分为五部分:
- PART1 Setting。模型的基本设置,如预训练模型的选择、数据集信息和训练过程中的参数(批大小、学习率等)
- PART 2 Model & Tokenizer。指定了用于训练的模型和分词器的具体类型及其配置,包括预训练模型的路径和是否启用特定功能,是模型训练的核心部分
- PART 3 Dataset & Dataloader。描述了数据处理的细节,包括如何加载数据集、预处理步骤、批处理大小等
- PART 4 Scheduler & Optimizer。配置了优化过程中的关键参数,如学习率调度策略和优化器的选择,这些是影响模型训练效果和速度的重要因素
- PART 5 Runtime:定义了训练过程中的额外设置,如日志记录、模型保存策略和自定义钩子等,以支持训练流程的监控、调试和结果的保存
一般来说只需要修改前三部分,后两个部分XTuner已经帮我们优化到最佳水平。
在PART1,我们不需要在huggingface上自动下载模型,因此需要更换模型的路径以及数据集的路径为本地路径。
为了训练过程中能够实时观察到模型的变化情况,XTuner 贴心的推出了一个 evaluation_inputs
的参数来让我们能够设置多个问题来确保模型在训练过程中的变化是朝着我们想要的方向前进的。我们可以添加自己的输入。
在 PART 3 的部分,由于我们准备的数据集是 JSON 格式的数据,并且对话内容已经是 input 和 output 的数据对,所以不需要进行格式转换。
此外,还可以对一些重要参数进行调整,包括学习率与训练轮次。常用参数如下表:
参数名 | 解释 |
---|---|
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 | 模板提示,用于定义生成文本的格式或结构 |
… | … |
最终配置文件如下:
# Copyright (c) OpenMMLab. All rights reserved.
import torch
from datasets import load_dataset
from mmengine.dataset import DefaultSampler
from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook,
LoggerHook, ParamSchedulerHook)
from mmengine.optim import AmpOptimWrapper, CosineAnnealingLR, LinearLR
from peft import LoraConfig
from torch.optim import AdamW
from transformers import (AutoModelForCausalLM, AutoTokenizer,
BitsAndBytesConfig)
from xtuner.dataset import process_hf_dataset
from xtuner.dataset.collate_fns import default_collate_fn
from xtuner.dataset.map_fns import alpaca_map_fn, template_map_fn_factory
from xtuner.engine.hooks import (DatasetInfoHook, EvaluateChatHook,
VarlenAttnArgsToMessageHubHook)
from xtuner.engine.runner import TrainLoop
from xtuner.model import SupervisedFinetune
from xtuner.</