《书生·浦语大模型实战营》第四节课《XTuner 微调 LLM:1.8B、多模态、Agent》课程笔记-程序员宅基地

技术标签: python  语言模型  人工智能  OpenXLab  InternLM  自然语言处理  大语言模型  

《书生·浦语大模型实战营》第四节课《XTuner 微调 LLM:1.8B、多模态、Agent》课程笔记

本次学习

2024年3月开始参加《书生·浦语大模型实战营》

https://openxlab.org.cn/models/InternLM/subject

相关链接

第一节课《书生·浦语大模型全链路开源体系》课程及 InternLM2 技术报告笔记在

https://blog.csdn.net/hu_zhenghui/article/details/137194274

第二节课《轻松玩转书生·浦语大模型趣味 Demo》课程笔记在

https://huzhenghui.blog.csdn.net/article/details/137403590

第二节课《轻松玩转书生·浦语大模型趣味 Demo》实践笔记在

https://huzhenghui.blog.csdn.net/article/details/137404579

第三节课《茴香豆:搭建你的 RAG 智能助理》课程笔记在

https://huzhenghui.blog.csdn.net/article/details/137691859

第三节课《茴香豆:搭建你的 RAG 智能助理》实践笔记在

https://huzhenghui.blog.csdn.net/article/details/137692249

第五节课《LMDeploy 量化部署 LLM 实践》课程笔记在

https://huzhenghui.blog.csdn.net/article/details/135050733

第五节课《LMDeploy 量化部署 LLM 实践》实践笔记在

https://huzhenghui.blog.csdn.net/article/details/136908934

这是《书生·浦语大模型实战营》第四节课《XTuner 微调 LLM:1.8B、多模态、Agent》课程笔记

目录

  • Finetune 简介
  • XTuner 介绍
  • 8GB 显存玩转 LLM
  • InternLM 1.8B 模型
  • 多模态 LLM 微调
  • Agent

Finetune 简介

  • 两种 Finetune 范式
  • 一条数据的一生

为什么要微调?

为什么要做一个微调?

很多大语言模式是底座模型,或者叫做Foundation模型,是为了普遍任务、一般性任务进行预训练

想利用底座模型 ( Foundation模型 ) 应用到自己的特定领域当中,应用到一个特定的下游任务当中,表现是不如针对领域内训练的模型,所以需要进行领域内微调。

两种 Finetune 范式

LLM 的下游应用中,增量预训练指令跟随是经常会用到两种的微调模式。

将大语言模型对齐到特殊领域的应用中。

增量预训练微调

不需要一问一答有监督的标注,只是增加增量预训练数据,让模型学习到新的知识。

  • 使用场景

基座模型 ( Foundation模型,例如从 HuggingFace 直接下载的模型 ) 学习到一些新知识,如某个垂类领域的常识。

  • 训练数据

文章、书籍、代码等

这些数据是不需要进行一问一答这种有监督的标注的,只是增加增量预训练的性能。

指令跟随微调

让模型输出的内容更符合人类的喜好、偏好。需要很高质量的标注,如问答对聊天 ( 一问一答、一问一答 )

  • 使用场景

让模型学会对话模板,根据人类指令进行对话

  • 训练数据

高质量的对话、问答数据

在这里插入图片描述

增量预训练

世界第一高峰是珠穆朗玛峰
指令跟随

世界第一高峰是什么峰?
珠穆朗玛峰
InternLM
基座模型
InternLM
垂类基座模型
InternLM
垂类对话模型

增量预训练微调指令跟随微调的区别

例如通过海量数据训练出底座模型 ( Foundation模型 ) ,如果没有进行指令微调,只进行了增量预训练,或者直接使用底座模型 ( Foundation模型 ) 。

输入问题:

什么是肺癌?

大模型意识不到用户在询问问题,只是单纯的拟合训练数据中的空间分布,可能输出:

什么是胃癌?

什么是肝癌?

大模型不知道想问它什么,只能单纯的拟合训练数据的相似度。

完成指令微调阶段后,因为输入的是一问一答、一问一答这种聊天数据,经过训练后,大模型就能意识到是在问问题,输出:

肺癌是一种……的疾病

在这里插入图片描述

train
test
指令微调
test
data sea
Pretrained LLM

输入:

  • 什么是肺癌?

输出:

  • 什么是胃癌?
  • 什么是肝癌?
Instructed LLM

输入:

  • 什么是肺癌?

输出:

  • 肺癌是一种……的疾病。

一条数据的一生

原始数据
标准格式数据
添加对话模板
Tokenized数据
添加Label
开始训练
标准格式数据
原始数据
标准格式数据
添加对话模板
Tokenized数据
添加Label
开始训练

在这里插入图片描述

从书籍或者爬虫等来源获得的原始数据,首先要变成标准格式数据。

标准格式数据是训练框架能够识别的格式。

在实际对话时,通常会有三种角色

  • System

给定一些上下文信息,给模型设置的前置条件, System 的设定也是需要提示词工程的实验

比如

你是一个安全的AI助手

  • User

实际用户,会提出一些问题

比如

世界第一高峰是?

  • Assistant

根据 User 的输入,结合 System 的上下文信息,所期待的模型应该回答的内容

比如

珠穆朗玛峰

本例为

###System:你是一名友好的AI助手。
###User:你好!
###Assistant:您好,我是一名AI助手,请问有什么可以帮助您?
###User:世界最高峰是什么峰?
###Assistant:世界最高峰是珠穆朗玛峰。

XTuner 的框架中是以这样的 JSON 格式构建。

[
    {
    
        "conversation": [
            {
    
                "system": "你是一名友好的AI助手。",
                "input": "你好!",
                "output": "您好,我是一名AI助手,请问有什么可以帮助您?"
            },
            {
    
                "input": "世界最高峰是什么峰?",
                "output": "世界最高峰是珠穆朗玛峰。"
            }
        ]
    }
]

所期待模型回答的内容

<|System|>:你是一名友好的AI助手。

<|User|>:你好!

<|Bot|>:您好,我是一名AI助手,请问有什么可以帮助您?

<|User|>:世界最高峰是什么峰?

<|Bot|>:世界最高峰是珠穆朗玛峰。

在使用对话模型时,通常是不会感知到这三种角色的。

添加对话模板
原始数据
标准格式数据
添加对话模板
Tokenized数据
添加Label
开始训练

什么是对话模板?

System
你是一个安全的AI助手
添加对话模板
显示没有对话模板的回答
启动对话
User 输入
世界第一高峰是?
Assistant回复
(包含对话模板)
珠穆朗玛峰

对话模板是为了能够让 LLM 区分出, SystemUserAssistant ,不同的模型会有不同的模板。

LLaMa 2 ( Meta )

LLaMa 2 模板 含义
<</SYS>> System 上下文结束
<<SYS>> System 上下文开始
[INST] User 指令开始
[/INST] User 指令结束

InternLM2

InternLM2 模板 含义
<|System|>: System 上下文开始
<|User|>: User 指令开始
<eoh>: End of Human , User 指令结束
<|BOT|>: Assistant 开始回答
<eoa>: End of Assistant , Assistant 回答结束

在这里插入图片描述

XTuner 已经将上述步骤打包好,只需要按照标准格式数据输入给 XTuner 即可。

增量预训练微调

Output:

世界第一高峰是珠穆朗玛峰

为了让 LLM 知道什么时候开始一段话,什么时候结束一段话,实际训练时需要对数据添加起始符 (BOS) 和结束符 (EOS) ; 大多数的模型都是使用 <s> 作为起始符, </s> 作为结束符。

在这里插入图片描述

<s>世界第一高峰是珠穆朗玛峰</s>

训练 LLM 时,为了让模型学会“世界第一高峰是珠穆朗玛峰”,并知道何时停止,对应的训练数据以及标签如下所示

Data <s> </s>
Label </s>
指令跟随微调

Input:

世界第一高峰是?

Output:

世界第一高峰是珠穆朗玛峰

不同于增量预训练微调,数据中会有 InputOutput

希望模型学会的是答案 ( Output ) , 而不是问题 ( Input )

训练时只会对答案 ( Output ) 部分计算 Loss (损失)

在这里插入图片描述

训练时,会和推理时保持一致,对数据添加相应的对话模板,以下为 InternLM 的训练数据和标签

Data <s> <|User|> <eoh> \n <|Bot|> <eoa> </s>
Label <eoa> </s>

LoRA微调QLoRA微调 原理

LoRA

Low-Rank Adaptation of large language models

XTuner 中主要适用 LoRAQLoRA 这两种微调方案。

LoRA 的常见场景是 Stable Diffusion , 在 Stable Diffusion 中为了画出心仪的角色或风格,往往会在一个底模上面套一个 LoRA 模型。换一个 LoRA 模型就意味着换一个角色或者换一个出图风格,底模保持不变。

LLM 模型类似,基座模型 ( Foundation模型 ) 不变,在基座模型 ( Foundation模型 ) 之上微调 LoRA 模型。

LLM 的参数量主要集中在模型中的 Linear , 训练这些参数会耗费大量的显存

LoRA 通过在原本的 Linear 旁,新增一个支路,包含两个连续的小 Linear , 新增的这个支路通常叫做 Adapter

Adapter 参数量远小于原本的 Linear , 能大幅降低训练的显存消耗

在这里插入图片描述

简单理解,LoRA 生成的文件就是这两个 Adapter 层的参数保存的文件。

微调原理

想象一下,你有一个超大的玩具,现在你想改造这个超大的玩具。但是,对整个玩具进行全面的改动会非常昂贵

因此,你找到了一种叫 LoRA 的方法:只对玩具中的某些零件进行盖顶,而不是对整个玩具进行全面改动

QLoRALoRA 的一种改进:如果你手里只有一把生锈的螺丝刀,也能改造你的玩具。

在这里插入图片描述

Full Finetuning (全参数微调) 、 LoRA微调QLoRA微调 横向比较

在这里插入图片描述

Full Finetuning (全参数微调)

Base Model 参与训练并更新参数

需要保存 Base Model 中参数的优化器状态

  • 整个模型要加载到显存中
  • 所有模型参数的优化器也要加载在显存中

这会消耗更多的显存,如果显存不够的话,就根本跑不起来全参数微调的过程。

LoRA 微调

Base Model 只参与 Forware

只有 Adapter 部分 Backward 更新参数

只需保存 Adapter 中参数的优化器状态

  • 整个模型也要加载到显存中
  • 参数优化器只需要保存 LoRA 部分的参数优化器

这个过程大大减少了显存的占用

QLoRA 微调

Base Model 量化为 4-bit

优化器状态在 CPUGPUOffload

Base Model 只参与 Forware

只有 Adapter 部分 Backward 更新参数

只需保存 Adapter 中参数的优化器状态

  • 把模型加载到显存中的时候,就已经采用 4-bit 量化的方式加载。就是不那么精确的加载,就相当于加载的时候四舍五入,又节省了显存开销。

XTuner

XTuner 是一个打包好的微调工具箱。

  • 傻瓜化

配置文件的形式封装了大部分微调场景,0基础的非专业人员也能一键开启微调

  • 轻量级

对于 7B 参数量的 LLM微调所需的最小显存仅为 8GB

消费级显卡

Colab

XTuner 简介

功能亮点
  • 适配多种生态
  • 适配多种硬件
适配多种生态
  • 多种微调算法

多种微调策略与算法,覆盖各类 SFT ( Supervised Finetuning , 有监督微调 ) 场景

  • 适配多种开源生态

支持加载 HuggingFaceModelScope 模型或数据集

  • 自动优化加速
    • Flash Attention
    • DeepSpeed ZeRO
    • Pytorch FSDP
    • 序列并行

开发这无需关注复杂的显存优化与计算加速细节

适配多种硬件
  • 训练方案覆盖 NVidia 20系以上所有显卡
    • 消费级显卡
      • GeForce RTX 20802080ti
      • GeForce RTX 3060 ~ 3090ti
      • GeForce RTx 4060 ~ 4090
    • 数据中心
      • Tesla T4
      • V100
      • A10
      • A100
      • H100
  • 最低只需 8GB 显存即可微调 7B 模型

2024年开源了 1.8B 模型,学习的时候可以使用 1.8B 模型,消耗的显存也更低。

LLaMa-Factory vs. XTuner

XTunerLLaMa-Factory 微调框架横向对比。

XTuner 在不同量级上比 LLaMa-Factory 的训练速度显著要快。

LLaMa-Factory 相比,同样是 Llama2 70B 超大模型,在不同的数据长度下, XTuner 的表现也是比 LLaMa-Factory 更好的,包括兼容性。在 32k 长度下, LLaMa-Factory 就已经是 OOM ( Out of Memory ) 了。可见 XTuner 对显存优化做得是非常好的。

XTuner 快速上手

  • 安装
pip install xtuner

建议在使用 conda 创建的虚拟环境中安装。

  • 挑选配置模板
xtuner list-cfg -p internlm_20b
  • 一键训练
xtuner train internlm_20b_qlora__oasst1_512_e3
  • Config 命名规则
模型名 internlm_20b 目标模型名称,无 chat 代表是基座模型
使用算法 qlora 训练所使用的算法
数据集 oasst1 训练所使用的数据集
数据长度 512
Epoch e3 epoch 3 的缩写,表示把数据集跑 3

模型名称中有 chat 代表经过指令微调后的模型,没有 chat 代表是基座模型。

  • 拷贝配置模板
xtuner copy-cfg internlm_20b_qlora_oasst1_512_e3 ./
  • 修改配置模板
vi internlm_20b_qlora_oasst1_512_e1_copy.py
  • 启动训练
xtuner train internlm_20b_qlora_oasst1_512_e1_copy.py
  • 常用超参数
超参数 说明
data_path 数据路径或 HuggingFace 仓库名
max_length 单条数据最大 Token 数,超过则阶段,参见 多数据样本拼接 ( Pack Dataset )
pack_to_max_length 是否将多条短数据拼接到 max_length , 提高 GPU 利用率
accumulative_counts 梯度累积,每多少次 backward 更新一次参数
evaluation_inputs 训练过程中,会根据给定的问题进行推理,便于观测训练状态
evaluation_freq Evaluation 的评测间隔 iter

例如 24G 显卡,使用默认参数不修改只能使用 8GB , 需要 20 小时,此时可以调高 pack_to_max_length , 充分利用 24G , 减少时间。

###################################################################
#                          PART 1 Settings                        #
###################################################################
# Model
pretrained_model_name_or_path = 'internlm/internlm-20b'

# Data
data_path = 'timdettmers/openassistant-guanaco'
prompt_template = PROMPT_TEMPLATE.openassistant
max_length = 2048
pack_to_max_length = True

# Scheduler & Optimizer
batch_size = 1 # per_device
accumulative_counts = 16
dataloader_num_workers = 0
max_epochs = 3
optim_type = PagedAdamW32bit
1r = 2e-4
betas = (0.9, 0.999)
weight_decay = 0
max_norm = 1 # grad clip

# Evaluate the generation performance during the training
evaluation_freq = 500
evaluation_inputs = [
    '请给我介绍五个上海的景点’, 'Please tell me five scenic spots in Shanghai'
]
对话

为了便于开发者查看训练效果, XTuner 提供了一键对话接口。

  • Float 16 模型对话
xtuner chat internlm/internlm-chat-20b

模型直接从 HuggingFace 上拉取下来后,也是可以用 xtuner chat 对话。

默认情况使用浮点 16 位精度对话。

  • 4bit 模型对话
xtuner chat internlm/internlm-chat-20b --bits 4

如果使用浮点 16 位精度导致显存 OOM ( Out of Memory ) , 也可以使用 4bit 量化对话。

  • 加载 Adapter 模型对话
xtuner chat internlm/internlm-chat-20b --adapter $ADAPTER_DIR

微调的结果是生成 Adapter 文件,想与微调后的模型对话,就在 chat 时指定这个 Adapter 路径。

工具类模型对话

XTuner 还支持工具类模型的对话,更多详见 HuggingFace Hub ( xtuner/Llama-2-7b-qlora-moss-003-sft )

  • 联网搜索

Q

上海明天的天气怎么样?

Bot Thoughts

为了

  • 使用计算器

Q

一个球体的半径是5.32厘米,求它的表面积和体积。

Bot Thoughts

这是

  • 解方程

Q

今有鸡兔同笼,上有二十头,下有六十二足,问鸡兔各几何?

Bot Thougnts

这是一

XTuner 数据引擎

开发者可以专注于数据内容

不必花费精力处理复杂的数据格式

数据处理流程
数据集映射函数:原始问答对 -> 格式化问答对
对话模板映射函数:格式化问答对 -> 可训练语料
原始问答对
格式化问答对
可训练语料
原始问答对示例
###System:你是一名友好的AI助手。
###User:你好!
###Assistant:您好,我是一名AI助手,请问有什么可以帮助您?
###User:世界最高峰是什么峰?
###Assistant:世界最高峰是珠穆朗玛峰。
格式化问答对示例
[
    {
    
        "conversation": [
            {
    
                "system": "你是一名友好的AI助手。",
                "input": "你好!",
                "output": "您好,我是一名AI助手,请问有什么可以帮助您?"
            },
            {
    
                "input": "世界最高峰是什么峰?",
                "output": "世界最高峰是珠穆朗玛峰。"
            }
        ]
    }
]
可训练语料示例

<|System|>:你是一名友好的AI助手。

<|User|>:你好!

<|Bot|>:您好,我是一名AI助手,请问有什么可以帮助您?

<|User|>:世界最高峰是什么峰?

<|Bot|>:世界最高峰是珠穆朗玛峰。

粗体代表有训练 Loss 的部分

数据集映射函数
数据集映射函数:原始问答对 -> 格式化问答对
原始问答对
格式化问答对

XTuner 也内置了很多数据引擎,对于各种各样的开源数据集,格式是不同的。

XTuner 加载时提供了很多映射参数。

可以把各种格式的开源数据集 ( 原始问答对 ) 映射成统一的格式 ( 格式化问答对 ) 。

便于跑通程序。

XTuner 内置了多种热门数据集的映射函数

函数 数据集
alpaca_map_fn Alpaca 格式数据集处理函数
oassti_map_fn OpenAssistant 格式数据处理函数
openai_map_fn OpenAI Finetune 格式数据处理函数
wizardlm 微软 WizardLM 系列数据集梳理函数
……
对话模板映射函数
对话模板映射函数:格式化问答对 -> 可训练语料
格式化问答对
可训练语料

XTuner 内置了多种对话模板映射函数。

函数 对话模板
chatglm ChatGLM 使用的对话模板
llama2_chat Llama2 对话模型使用的对话模板
code_llama_chat Code Llama 使用的对话模板
baichuan_chat 百川使用的对话模板
baichuan2_chat 百川使用的对话模板
qwen_chat 通义千问使用的对话模板
……
多数据样本拼接 ( Pack Dataset )

增强并行性,充分利用 GPU 资源!

训练的时候,通过 NVidia 监控,发现显存没有吃满,就可以把 max_length 参数打开,参见 XTuner 简介,把 max_length 稍微调大一点。

在这里插入图片描述

示例:训练自定义 JSON 数据集

Alpaca 配置文件为例

具体体现前面讲的配置流程。

  • 拷贝配置模板
xtuner copy-cfg internlm_20b_qlora_alpaca_e3 ./
  • 修改配置模板
vi internlm_20b_qlora_alpaca_e3_copy.py

只需要改动

修改内容 相关代码
数据路径 data_path
数据集格式 dataset
数据集映射函数 dataset_map_fn
from xtuner.dataset import process_hf_dataset
from datasets import load_dataset
from xtuner.dataset.map_fns import alpaca_map_fn, template_map_fn_factory 
from xtuner.utils import PROMPT_TEMPLATE
...
#######################################################################
#                          PART 1 Settings                            #
#######################################################################
- data_path = 'tatsu-lab/alpaca'
+ data_path = 'path/to/your/json/data'
#######################################################################
#                      STEP 3 Dataset & Dataloader                    #
#######################################################################
train_dataset = dict (
    type=process_hf_dataset,
-   dataset=dict (type=load_dataset, path=data_path),
+   dataset=dict (
+       type=load_dataset, path='json', data_files=dict(train=data_path)),
    tokenizer=tokenizer,
    max_length=max_length, 
+   dataset_map_fn=alpaca_map_fn,
    template_map_fn=dict(
        type=template_map_n_factory, template=prompt_template),
    remove_unused_columns=True,
    shuffle_before _pack=True,
    pack_to_max_length=pack_to_max_length)
...
  • 启动训练
xtuner train internlm_20b_qlora_alpaca_e3_copy.py

8GB 显存玩转 LLM

XTuner 内置的两种加速方式

Flash AttentionDeepSpeed ZeROXTuner 最重要的两个优化技巧

DeepSpeedFlash Attention 虽然能够大幅降低训练成本,但使用门槛相对较高,需要复杂的配置,甚至修改代码。

为了让开发者专注于数据, XTuner 会自动 dispatch Flash Attention , 并一键启动 DeepSpeed ZeRO

xtuner train internlm_20b_qlora_oasst1_512_e3 \
  --deepspeed deepspeed_zero3
Flash Attention

Flash AttentionAttention 计算并行化,避免了计算过程中 Attention Score NxN 的显存占用(训练过程中的 N 都比较大)

Flash Attention 是自动开启的。

DeepSpeed ZeRO

ZeRO 优化,通过将训练过程中的参数、梯度和优化器状态切片保存,能够在多 GPU 训练时显著节省显存。

除了将训练中间状态切片外, DeepSpeed 训练时使用 FP16 的权重,相较于 PyTorchAMP 训练,在单 GPU 上也能大幅节省显存。

启动 DeepSpeed ZeRO 需要增加 DeepSpeed ZeRO 2DeepSpeed ZeRO 3 启动参数。

优化前后显存占用比较

InternLM2 1.8B 模型

为了响应社区用户极其强烈的呼声, InternLM2-1.8B 于近日正式开源!

监督微调(SFT)
通过在线RLHF进一步对齐
InternLM2-1.8B
InternLM2-Chat-1.8B-SFT
InternLM2-Chat-1.8B

InternLM2-1.8B 提供了三个版本的开源模型,大家可以按需选择。

  • InternLM2-1.8B

具有高质量和高适应灵活性的基础模型,为下游深度适应提供了良好的起点。

  • InternLM2-Chat-1.8B-SFT

InternLM2-1.8B 上进行监督微调 ( SFT ) 后得到的对话模型。

相当于是一个中间产物,有利于研究。

  • InternLM2-Chat-1.8B

通过在线 RLHFInternLM2-Chat-1.8B-SFT 之上进一步对齐, InternLM2-Chat-1.8B 表现出更好的指令跟随、聊天体验和函数调用,推荐下游应用程序使用。( 模型大小仅为 3.78GB )

常见场景中使用 InternLM2-Chat-1.8B 即可,InternLM2-Chat-1.8B 是这三个模型的最终版

FP16 精度模式下, InternLM2-1.8B 仅需 4GB 显存的笔记本显卡即可顺畅运行。拥有 8GB 显存的消费级显卡,即可轻松进行 1.8B 模型的微调工作。 如此低的硬件门槛,非常适合初学者使用,以深入了解和掌握大模型的全链路。

多模态 LLM

  • LLM 装上电子眼:多模态 LLM 原理简介
  • 什么型号的电子眼: LLaVA 方案简介
  • 快速上手: InternLM2_Chat_1.8B + LLaVA

LLM 装上电子眼:多模态 LLM 原理简介

文本单模态
输入文本
文本Embedding模型
文本向量
LLM
输出文本
  1. 在使用文本单模态时,首先是使用文本Embedding模型对用户的输入文本转化为文本向量

  2. 文本向量预测出输出文本

文本+图像多模态
图像向量
Image Projector
输入图像
输入文本
文本Embedding模型
文本向量
LLM
输出文本

文本+图像多模态中的输入部分和文本单模态是一样的,在输出部分增加了对图像输入的处理。

文本+图像多模态增加了 Image Projector ,对输入图像进行图像向量化。

文本向量图像向量同时输入,预测输出文本

文本单模态微调成文本+图像多模态的过程就是训练 Image Projector 的过程。

什么型号的电子眼: LLaVA 方案简介

Haotian Liu 等使用 GPT-4V 对图像数据生成描述,以此构建出大量 <question text><image> -- <answer text> 的数据对。

文本问题+图像作为输入

文本回答作为输出

利用这些数据对,配合文本单模态 LLM , 训练出一个 Image Projector

所使用的文本单模型 LLM 和训练出来的 Image Projector , 统称为 LLaVA 模型。

这里提到的多模态是识图,不是生图

此处表述不精准,便于理解。

LLaVA 训练阶段示意图
训练阶段
Image Projector
显卡
文本+图像问答对
(训练数据)
文本单模态LLM
LLaVA 测试阶段示意图
测试阶段
输出文本
显卡
Image Projector
文本单模态LLM
输入图像
类比

Image Projector 的训练和测试,有点类似之前我们讲过的 LoRA 微调方案。

二者都是在已有 LLM 的基础上,用新的数据训练一个新的小文件。

只不过, LLM 套上 LoRA 之后,有了新的灵魂(角色):

LLM 套上 Image Projector 之后,才有了眼睛。

快速上手

在本节中,我们将 自己构造 <question text><image> -- <answer text> 数据对,

文本问题+图像作为输入

文本回答作为输出

基于 InternLM2_Chat_1.8B 这个文本单模态模型,
使用 LLaVA 方案,训练一个给 InternLM2_Chat_1.8B 使用的 Image Projector 文件。

LLaVA 方案中,给 LLM 增加视觉能力的过程,即是训练 Image Projector 文件的过程。

该过程分为 2 个阶段: PretrainFinetune

Pretrain阶段
Finetune阶段
Pretrained LLaVA
显卡
图像\n+\n标题(短文本)
文本单模态LLM\n(InternLM2_chat_1.8B)
FineTuned LLaVA
显卡
图像\n+\n复杂对话文本
  • Pretrain 阶段

大量的图像和图像标题组成的数据对,图像标题不一定是问题,可能就是图像的描述,或者就是图像的标签。

虽然是有监督,数据来源可能是从网络爬取的数据,这个阶段是让 文本单模态 LLM 快速了解图像中的普遍特征。

得到 Pretrained LLaVA

这个过程就是预训练

Pretrain 阶段可以类比文本单模态的增量预训练阶段,大量的数据,但是质量不保证。

  • Finetune 阶段

Pretrain 阶段结束后把 Pretrained LLaVA 加载到显卡中。

再加上图像+复杂对话文本这种高质量的有监督数据。

得到最终的 FineTuned LLaVA 模型。

这个阶段相当于指令跟随,让大模型了解我们想问什么,根据问题回答。

Finetune 阶段可以类比文本单模态的的指令微调阶段,这个阶段数据可能少一点,但是都是高质量、高复杂度的对话数据。

Pretrain 阶段

Pretrain阶段
Pretrained LLaVA
显卡
图像
+
标题(短文本)
文本单模态LLM
(InternLM2_chat_1.8B)

Pretrain 阶段,我们会使用大量的图片+简单文本 ( caption , 即图片标题 ) 数据对,使 LLM 理解图像中的普遍特征。即,对大量的图片进行粗看。

Pretrain 阶段训练完成后,此时的模型已经有视觉能力了!但是由于训练数据中都是图片+图片标题,所以此时的模型虽然有视觉能力,但无论用户问它什么,它都只会回答输入图片的标题。即,此时的模型只会给输入图像“写标题”。

Pretrain 阶段的数据格式如下所示,每张图有一个描述。

[
  {
    
    "id": "008000033471",
    "image": "coco/train2017/000000033471.jpg",
    "conversations": [
      {
    
        "from": "human",
        "value": "<image>\nDescribe this image."
      },
      {
    
        "from": "gpt",
        "value": "The bus in the image is white and red."
      }
    ]
  },
  {
    
    "id": "000000052846",
    "image": "coco/train2017/000800052846.jpg",
    "conversations": [
      {
    
        "from": "human",
        "value": "<image>\nDescribe this image."
      },
      {
    
        "from": "gpt",
        "value": "The cat is positioned on top of the back of the couch in the living room."
      }
    ]
  },
  {
    
    "id": "000000052555",
    "image": "coco/train2017/000000052833.jpg",
    "conversations": [
      {
    
        "From": "human",
        "value": "<image>\nDescribe this image."
      },
      {
    
        "from": "gpt",
        "value": "The cat couch in the bathroom."
      }
    ]
  }
]

Finetune 阶段

Finetune 阶段,我们会使用图片+复杂文本数据对,来对 Pretrain 得到的 Image Projector 进行进一步的训练。

Finetune阶段
FineTuned LLaVA
显卡
图像\n+\n复杂对话文本
Pretrained LLaVA

Finetune 阶段,每一张图片不仅有一个问题描述图片,还有很多条问答对,都是针对这个问题一问一答

Pretrain 阶段的数据格式如下所示。

[
    {
    
        "id": "随便什么字符串",
        "image": "图片文件的相对位置。相对谁?相对你后面config文件里指定的image_folder参数的路径。",
        "conversation": [
            {
    
                "from": "human",
                "value": "<image>\n第1个问题。"
            },
            {
    
                "from": "gpt",
                "value": "第1个回答"
            },
            {
    
                "from": "human",
                "value": "第2个问题。"
            },
            {
    
                "from": "gpt",
                "value": "第2个回答"
            },
            {
    
                "from": "human",
                "value": "第n个问题。"
            },
            {
    
                "from": "gpt",
                "value": "第n个回答"
            },
        ]
    },
    {
    
        "id": "随便什么字符串",
        "image": "图片文件的相对位置。相对谁?相对你后面config文件里指定的image_folder参数的路径。",
        "conversation": [
            {
    
                "from": "human",
                "value": "<image>\n第1个问题。"
            },
            # ......
            {
    
                "from": "gpt",
                "value": "第n个回答"
            }
        ]
    }
]

注意:每组训练数据的第1个来自 human 的问题前,要加上图片占位符,即 <image>

Pretrain 阶段的数据格式示例所示。

{
    
    "id": "000000033471",
    "image": "coco/train2017/000000033471.jpg",
    "conversations": [
        {
    
            "from": "human",
            "value": "<image>\nWhat are the colors of the bus in the image?"
        },
        {
    
            "from": "gpt",
            "value": "The bus in the image is white and red."
        },
        {
    
            "from": "human",
            "value": "What feature can be seen on the back of the bus?"
        },
        {
    
            "from": "gpt",
            "value": "The back of the bus features an advertisement."
        },
        {
    
            "from": "human",
            "value": "Is the bus driving down the street or pulled off to the side?"
        },
        {
    
            "from": "gpt",
            "value": "The bus is driving down the street, which is crowded with people and other vehicles."
        }
    ]
}

高质量的数据用于 Finetune , 用于指令跟随

Agent

动手实战环节—— LLM 部分

XTuner 的运行原理

模型转换、测试及部署
模型训练
主要参数
配置文件准备
修改配置文件
前期准备
模型部署
模型对话测试
模型转换及整合
模型训练
deepspeed
模型续训
权重保存地址
生成配置文件
修改模型及数据集地址
修改load_dataset的方式
prompt_template选择
根据数据集修改dataset_map_fn的方式
配置文件选择
格式转换
数据采集
微调方法
模型选择
  • 环境安装

假如我们想要用 XTuner 这款简单易上手的微调工具包来对模型进行微调的话,那我们最最最先开始的第一步必然就是安装 XTuner !安装基础的工具是一切的前提,只有安装了 XTuner 在我们本地后我们才能够去思考说具体怎么操作。

  • 前期准备

那在完成了安装后,我们下一步就需要去明确我们自己的微调目标了。我们想要利用微调做一些什么事情呢,那我为了做到这个事情我有哪些硬件的资源和数据呢?假如我们有对于一件事情相关的数据集,并且我们还有足够的算力资源,那当然微调就是一件水到渠成的事情。就像 OpenAI 不就是如此吗?但是对于普通的开发者而言,在资源有限的情况下,我们可能就需要考虑怎么采集数据,用什么样的手段和方式来让模型有更好的效果。

  • 启动微调

在确定了自己的微调目标后,我们就可以在 XTuner 的配置库中找到合适的配置文件并进行对应的修改。修改完成后即可一键启动训练!训练好的模型也可以仅仅通过在终端输入一行指令来完成转换和部署工作!

准备工作

  • 首先是在 GitHub 上克隆了 XTuner 的源码,并把相关的配套库也通过 pip 的方式进行了安装。
  • 然后根据自己想要做的事情,利用脚本准备好了一份关于调教模型认识自己身份地位的数据集。
  • 再然后根据自己的显存及任务情况确定了使用 InternLM2-chat-1.8B 这个模型,并且将其复制到我们的文件夹里。
  • 最后我们在 XTuner 已有的配置文件中,根据微调方法、数据集和模型挑选出最合适的配置文件并复制到我们新建的文件夹中。

微调也经常被戏称为是炼丹,就是说炼丹的时候得思考好用什么样的材料、用多大的火候、烤多久的时间以及用什么丹炉去烧。这里的丹炉其实可以想象为 XTuner ,只要丹炉的质量过得去,炼丹的时候不会炸,一般都是没问题的。但是假如炼丹的材料(就是数据集)本来就是垃圾,那无论怎么炼(微调参数的调整),炼多久(训练的轮数),炼出来的东西还只能且只会是垃圾。只有说用了比较好的材料,那么就可以考虑说要炼多久以及用什么办法去炼的问题。因此总的来说,学会如何构建一份高质量的数据集是至关重要的。

配置文件介绍

整体的配置文件分为五部分:

  • PART 1 Settings

涵盖了模型基本设置,如预训练模型的选择、数据集信息和训练过程中的一些基本参数(如批大小、学习率等)。

  • PART 2 Model & Tokenizer

指定了用于训练的模型和分词器的具体类型及其配置,包括预训练模型的路径和是否启用特定功能(如可变长度注意力),这是模型训练的核心组成部分。

  • PART 3 Dataset & Dataloader

描述了数据处理的细节,包括如何加载数据集、预处理步骤、批处理大小等,确保了模型能够接收到正确格式和质量的数据。

  • PART 4 Scheduler & Optimizer

配置了优化过程中的关键参数,如学习率调度策略和优化器的选择,这些是影响模型训练效果和速度的重要因素。

  • PART 5 Runtime

定义了训练过程中的额外设置,如日志记录、模型保存策略和自定义钩子等,以支持训练流程的监控、调试和结果的保存。

一般来说需要更改的部分其实只包括前三部分,而且修改的主要原因是修改了配置文件中规定的模型数据集。后两部分都是 XTuner 官方优化好的东西,一般而言只有在魔改的情况下才需要进行修改。

常用超参数

参数名 解释
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_lengthbatch_size 这两个参数调大。

过拟合问题

  • 减少保存权重文件的间隔并增加权重文件保存的上限

这个方法实际上就是通过降低间隔结合评估问题的结果,从而找到最优的权重文。可以每隔 100 个批次来看什么时候模型已经学到了这部分知识但是还保留着基本的常识,什么时候已经过拟合严重只会说一句话了。但是由于再配置文件有设置权重文件保存数量的上限,因此同时将这个上限加大也是非常必要的。

  • 增加常规的对话数据集从而稀释原本数据的占比

这个方法其实就是希望正常用对话数据集做指令微调的同时还加上一部分的数据集来让模型既能够学到正常对话,但是在遇到特定问题时进行特殊化处理。比如说在一万条正常的对话数据里混入两千条和小助手相关的数据集,这样模型同样可以在不丢失对话能力的前提下学到胡争辉的小助手这句话。这种其实是比较常见的处理方式。

模型整合可选参数

参数名 解释
--max-shard-size {GB} 代表每个权重文件最大的大小(默认为 2GB
--device {device_name} 这里指的就是 device 的名称,可选择的有 cudacpuauto ,默认为 cuda 即使用 gpu 进行运算
--is-clip 这个参数主要用于确定模型是不是 CLIP 模型,假如是的话就要加上,不是就不需要添加

CLIPContrastive Language–Image Pre-training )模型是 OpenAI 开发的一种预训练模型,它能够理解图像和描述它们的文本之间的关系。 CLIP 通过在大规模数据集上学习图像和对应文本之间的对应关系,从而实现了对图像内容的理解和分类,甚至能够根据文本提示生成图像。

xtuner chat 参数

启动参数 解释
--system 指定 SYSTEM 文本,用于在对话中插入特定的系统级信息
--system-template 指定 SYSTEM 模板,用于自定义系统信息的模板
--bits 指定 LLM 运行时使用的位数,决定了处理数据时的精度
--bot-name 设置 bot 的名称,用于在对话或其他交互中识别 bot
--with-plugins 指定在运行时要使用的插件列表,用于扩展或增强功能
--no-streamer 关闭流式传输模式,对于需要一次性处理全部数据的场景
--lagent 启用 lagent ,用于特定的运行时环境或优化
--command-stop-word 设置命令的停止词,当遇到这些词时停止解析命令
--answer-stop-word 设置回答的停止词,当生成回答时遇到这些词则停止
--offload-folder 指定存放模型权重的文件夹,用于加载或卸载模型权重
--max-new-tokens 设置生成文本时允许的最大token数量,控制输出长度
--temperature 设置生成文本的温度值,较高的值会使生成的文本更多样,较低的值会使文本更确定
--top-k 设置保留用于顶k筛选的最高概率词汇标记数,影响生成文本的多样性
--top-k 设置保留用于顶k筛选的最高概率词汇标记数,影响生成文本的多样性
--top-p 设置累计概率阈值,仅保留概率累加高于 top-p 的最小标记集,影响生成文本的连贯性
--seed 设置随机种子,用于生成可重现的文本内容

除了这些参数以外其实还有一个非常重要的参数就是 --adapter ,这个参数主要的作用就是可以在转化后的 adapter 层与原模型整合之前来对该层进行测试。使用这个额外的参数对话的模型和整合后的模型几乎没有什么太多的区别,因此可以通过测试不同的权重文件生成的 adapter 来找到最优的 adapter 进行最终的模型整合工作。

动手实战环节—— VLM

在本节中,我们将自己构造 <question text><image>--<answer text> 数据对,基于 InternLM2_Chat2_1.8B 这个文本单模态模型,使用 LLaVA 方案,将 InternLM2_Chat_1.8B 训练成具有识图能力的文本图像双模态模型。

Finetune 前的多模态 LLM

InternLM_Chat_1.8B_llava :

只会给图像打标题

double enter to end input (EXIT: exit chat, RESET: reset history) >>> Describe this image.

a doctor and a woman looking at a vision test<| im_end|>

double enter to end input (EXIT: exit chat, RESET: reset history) »>> What is the equipment in the image?

a doctor and a woman looking at a vision test<|im_end|>

Finetune 后的多模态 LLM

InternLM_Chat_1.8B_llava :

会根据图像回答问题了

double enter to end input (EXIT: exit chat, RESET: reset history) >>> Describe this image

This is a photograph of a patient undergoing an eye examination. A healthcare professional, possibly an optometrist, is using a slit lamp to examine the patient's eyes. The patient is seated , leaning into the machine which has a chin rest support and a forehead support. It is a a fore head support and has a support.<|im_end|>

double enter to end input (EXIT: exit chat, RESET: reset history) >> What is the equipment in the image?

The image shows a slit lamp, which is a light source that can be focused to shine a thin sheet of light into the eye. It is used with a biomicroscope and facilitates the examination of the eye's anterior and posterior segments under magnification.<|im_end|>

不仅对描述更加丰满了,更加完备了。高的表现效果取决于微调数据。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hu_zhenghui/article/details/137951465

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签