支持私有化部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


大模型微调知识与实践分享

发布日期:2025-05-28 09:29:53 浏览次数: 1587 作者:阿里云开发者
推荐语

深入了解大型语言模型的微调技术,掌握关键技术点,提升模型性能。

核心内容:
1. 大型语言模型(LLM)的结构和参数量解析
2. Transformer模型的Encoder和Decoder模块详解
3. Prompt工程、数据构造和LoRA微调方法实践

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家

一、微调相关知识介绍

1.1. 认识大模型

在介绍LLM的微调知识前,我们先具象的认识下大模型长什么样子,包括模型结构、参数量、精度、显存占用。

1.1.1. 模型结构

《Attention Is All You Need》是一篇Google提出的将Attention思想发挥到极致的论文。这篇论文中提出一个全新的模型,叫 Transformer,抛弃了以往深度学习任务里面使用到的 CNN 和 RNN。

可以看到Encoder包含一个Muti-Head Attention模块,是由多个Self-Attention组成,而Decoder包含两个Muti-Head Attention。Muti-Head Attention上方还包括一个 Add & Norm 层,Add 表示残差连接 (Residual Connection) 用于防止网络退化,Norm 表示 Layer Normalization,用于对每一层的激活值进行归一化。

LLM大模型基本选择以Decoder模块堆叠N层组成的网络结构。

Transformer结构如下:

LLM大模型基本选择以Decoder模块堆叠N层组成的网络结构。

1.1.2. 模型参数

例如羊驼系列 LLaMA 大模型,按照参数量的大小有四个型号:LLaMA-7B、LLaMA-13B、LLaMA-33B 与 LLaMA-65B。这里的 B 是 billion 的缩写,指代模型的参数规模。故最小的模型 7B 包含 70 亿个参数,而最大的一款 65B 则包含 650 亿个参数。

我们以大模型的最基本结构 Transformer 为例,首先来看一下参数量是怎么算出来的。

transformer 由 L 个相同的层组成,每个层分为两个部分:self-attention 和 MLP 层。其中 self-attention 块,不管用的是 self-attention 还是 multi-head self-attention,参数量计算并不影响。因为在输入时,对 Q,K,V 三个向量都进行了线性变换,只是 multi-head self-attention 会对隐藏层 h 切分成 head 份而已。那么 self-attention 块的参数量为:4h²+4h。MLP 块由 2 个线性层组成,这两个层的 shape 是先将维度 h 映射到 4h,然后第二个线性层再将维度从 4h 映射回 h。self-attention 和 MLP 块各有一个 layer normalization,包含了 2 个可训练的参数:尺度缩放参数 gamma,和平移参数 beta,形状都是 [h]。那么这两个 layer normalization 参数量为:4h。那么,每个 transformer 层的参数量就为:12h²+13h。除此之外,还有输入部分的词嵌入参数,词向量的维度为 h,假设词表大小 vocab size 为 V。那么词嵌入的参数量为 Vh,而输出层的权重矩阵通常与输入的词嵌入矩阵参数是共享的,不会引入额外的参数量。关于位置编码,这部分参数比较少,可以忽略。其中,如果采用可训练的位置编码,那么参数量为 N*h,N 是最大序列长度,例如 chatgpt 的 4k。如果采用的是相对位置编码,如旋转编码 RoPE 或者 AliBi,则这部分就没有可训练的参数。综上所述,L 层的 transformer 模型的总参数量为 L(12h²+13h)+Vh,当隐藏维度 h 较大时,可以忽略一次项,模型参数量可以近似为 12Lh²。

综上所述,L 层的 transformer 模型的总参数量为 L(12h²+13h)+Vh,当隐藏维度 h 较大时,可以忽略一次项,模型参数量可以近似为 12Lh²。

1.1.3. 模型显存

如何计算大语言模型所需的显存?

4B是因为32位的浮点精度会占4个字节内存;

下面以运行16位精度的 Llama 70B 模型所需的 GPU 内存为例套用公式:

该模型有 700 亿参数。

M = (700 ∗ 4) / (32 / 16) ∗ 1.2 ≈ 140 * 1.2 = 168GB

1.1.4. 模型存储

我们以 LLaMA-7B 为例,这个大模型参数量约为 70 亿,假设每个参数都是一个 fp32,即 4 个字节,总字节就是 280 亿字节,则 280 亿字节/1024(KB)/1024(MB)/1024(GB) = 26.7GB,当然这是原始的理论值,我们再往下看。因为实际存储 weight 权重参数会存 fp16,所以模型大小继续减半为 13.35GB。但是部分 layer norm 等数据会保留源格式 fp32,因此实际会稍微有所增加到 13.5GB 左右,我们从开源的 LLaMA-7B 的实际的存储结果来看,是符合上面的计算的:

相信在介绍这部分后,大家应该对LLM大模型的模型结构、参数量、精度、存储空间更具象的认识。

1.2. 模型微调

1.2.1. prompt工程

模型微调通常来说,虽然可以提高任务的效果,但通常来说,微调的成本远大于提示词调优,模型微调相对来说复杂性高、资源需求大而且成本高。

使用 OpenAI API 进行快速工程的最佳实践:

https://help.openai.com/en/articles/6654000-best-practices-for-prompt-engineering-with-the-openai-api

prompt:结构化、具体化、清晰化

在微调之前先尝试优化prompt和fewshot来探索模型能力边界,是否能解决现有问题,合适的base-model(类型和size)的选取,有了明确的效果保证后,再微调得到更加稳定的效果输出和更小的size部署等需求。

1.2.2. 数据构造

有这么一句话在业界广泛流传:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。所以数据的构造至关重要,需要建立对生成数据质量的把控。

在chatgpt出来后,业界最开始基于pretrain模型上做sft最受关注的工作之一,是self-instruct,蒸馏chatgpt得到高质量的sft数据,很多后来的生成sft数据的工作是以这个工作为基础。核心思想是通过建立种子集,然后prompt模型输出目标格式的数据,通过后置ROUGE-L等筛选方法去重,不断的加入种子集合,来提升产出数据的多样性和质量。

比如qwen2.5-7b是pretrain后的模型,qwen2.5-7b-instrcut是基于qwen2.5-7b做了通用的SFT微调后得到。

生成指令数据的流程由四个步骤组成。1)指令生成,2)识别指令是否代表分类任务,3)用输入优先或输出优先的方法生成实例,4)过滤低质量数据。

关注数据集的质量和丰富度:

我们提及微调更多是在通用SFT训练好的模型基础上再做领域的微调。

可以更省事的选择俄把生成好的数据,直接丢给模型去训练验证最后的效果;但是如果朝着长期做效果迭代的方向,我们需要对生成的数据是否符合预期,有更现验的判断,这也能够为后续如果微调后模型不符合预期的情况下,来有debug的依据和方法。

一方面是人来check数据质量,另外一方面是可以通过规则或者LLM大模型来做后置的数据验证,让模型来打分并给出推理过程等方式。数据量的问题上,跟数据类型的分布关系很大,需要产生不同任务下的高质量数据,更需要关注数据分布。

1.2.3. LoRA微调

基于已有开源大模型进行微调训练,如果采用预训练的方式对模型的所有参数都进行训练微调,由于现有的开源模型参数量都十分巨大。PEFT (Parameter-Efficient Fine-Tuning),即对开源预训练模型的所有参数中的一小部分参数进行训练微调,最后输出的结果和全参数微调训练的效果接近。

LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。(秩是矩阵中最长的独立行数或列数)

神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。

在涉及到矩阵相乘的模块,在旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r。其中,r<<d,r是矩阵的秩,这样矩阵计算就从d x d变为d x r + r x d,参数量减少很多将原部分跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的)。

此外,Transformer的权重矩阵包括Attention模块里用于计算query, key, value的Wq,Wk,Wv以及多头attention的Wo,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整 Wq 和 Wv 会产生最佳结果。

1.3. 强化学习

instructGPT提出的SFT和RLHF的流程图,在SFT模型的基础做强化学习的训练往往会提升模型的表现。

我们需要一个模型来定量评判模型输出的回答在人类看来是否质量不错,即输入 [提示(prompt),模型生成的回答] ,奖励模型输出一个能表示回答质量的标量数字。

1.把大量的prompt(Open AI使用调用GPT-3用户的真实数据)输入给第一步得到的语言模型,对同一个问题,可以让一个模型生成多个回答,也可以让不同的微调(fine-tune)版本回答。

2.让标注人员对同一个问题的不同回答排序,实验发现发现不同的标注员,打分的偏好会有很大的差异,而这种差异就会导致出现大量的噪声样本。排序的话能获得大大提升一致性。

3.这些不同的排序结果会通过某种归一化的方式变成定量的数据丢给模型训练,从而获得一个奖励模型。也就是一个裁判员。

1.3.1. DPO训练

由于PPO需要4个模型加载,2个推理,2个训练,成本较高;而DPO只需要两个模型,一个推理一个训练。

开始训练时,reference model和policy model都是同一个模型,只不过在训练过程中reference model不会更新权重。

目标函数:

梯度:

动态因子:

因此DPO的优化目的可以理解为通过训练, 最大化正样本上的奖励 和负样本上的奖励两者的间距(margin)。 因为参考模型是不动的,因此进一步可以理解为提升模型在正样本上的概率(优化模型在正样本上的概率 大于 参考模型在正样本上的概率), 降低模型在负样本上的概率(优化模型在负样本上的概率 小于 参考模型在负样本上的概率)。

当我们的任务能够产出正负样例对的时候,我们可以通过这种方式来微调模型提升表现。来让模型从正负样例中学到好的为什么好,差的为什么差,往往能够得到比SFT更优的效果。它和SFT的区别在于,SFT只能告诉模型正例而没有负例。

{    "messages": [        {            "role": "user",            "content": "你能帮我写一篇关于环境保护的文章吗?"        }    ],    "chosen": {        "role": "assistant",        "content": "当然可以。环境保护是一个非常重要的话题,我们可以从减少碳排放、保护森林和水资源、推广可再生能源等方面来入手。你想要文章的具体方向和字数是多少呢?"    },    "rejected": {        "role": "assistant",        "content": "可以的,环境保护是一个重要的话题。"    }}

二、微调实践&工具使用

介绍完一些初步的理论基础后,这部分主要来讲大模型的具体微调流程和具体的操作细节。

因为集团内外关于模型微调的工具也很丰富,这里只给出我们团队常使用的平台和框架,以及微调的实操流程。

本文涉及几个内部平台说明:

  • 星云平台:模型训练平台

  • TuningFactory:基于LLaMA-Factory在星云平台上开发的框架

  • Whale:模型部署平台

  • idealab:请求开/闭源模型方式

外部平台:

  • LLaMA-Factory-外部通用微调框架-本地微调模型

https://github.com/hiyouga/LLaMA-Factory

这里给出一个微调的实践简化流程如下:

  • 数据构造

  • idealab 请求

  • 请求部署在whale上的开源模型(节约成本)

  • 数据分析&思考

  • 训练集和测试集的对齐

  • 数据质量、分布、量级

  • 训练平台的选择&任务提交

  • 本地

  • 星云平台

  • 训练模型超参调整

  • 对验证集loss关注&checkpoint的选择

  • 模型推理部署

  • whale的推理加速、参数设置等

  • 测试集数据分析

  • 迭代 or Done

2.1. 数据构造

2.1.1. idealab工具 

idealab 帮助文档一共接入了包含文生文、多模态、向量化、bing搜索、代码生成等类别的大模型共计近50个,涵盖了包含azure openai gpt系列、dalle,阿里通义千问、淘天星辰,谷歌vertexAI系列等主流模型。

调用的方式:

-H "Content-Type:application/json"-H 'X-AK: xxxx'-d '{"model": "gpt-3.5-turbo","prompt": "你是谁"}'
  • 收费:依赖key,需要预算申请,主要用于闭源模型的调用;

  • 部分免费:目前通义系列(百炼在线模型)、DeepSeek r1、v3等是免费。

2.1.2. 部署在whale上的开源模型

whale平台上提供了丰富的开源模型部署,根据调试或批量调用的需求,可以分成访问免费部署模型和独立部署模型两部分。整体体验还是比较便捷,对大模型部署支持的比较好,比较推荐。

  • 访问whale部署的免费模型,通过申请访问平台部署的公共模型,可以快速调用。无需卡资源。

  • 独立部署在whale上模型,如果本身的任务请求量大,对耗时有要求等,可以部署自己的开源模型。需要卡资源。

在部署模型之后,除了whale的UI界面去调用,也支持sdk调用whale服务代码:LLMChatStreamDemo.py,核心代码如下:

from whale import TextGeneration, VipServerLocatorfrom whale.util import Timeout
response = TextGeneration.chat(    model="Qwen-72B-Chat-Pro",    messages=msgs,    stream=True,    temperature=1.0,    max_tokens=2000,    timeout=Timeout(6020),    top_p=0.8,    extend_fields=extend_fields)

2.2. 训练平台的选择&任务提交

当我们通过上述方式生成好自己的训练集后,就需要开始微调模型了。

针对小任务/小模型,可以在自己开发机上微调即可,推荐使用LLaMA-Factory微调框架;对于依赖较大资源或者数据量较大的情况,可以使用TuningFactory框架,结合星云平台做模型的训练。

LLaMA-Factory代码库:https://github.com/hiyouga/LLaMA-Factory

lora微调,scripts/sft_lora.sh

WORLD_SIZE=8LR=1e-5
# 实验项目名,需要在星云实验管理中创建实验或者选择你有权限的实验# 如果不指定,并且开启了report_to=ml_tracker,会默认使用 你工号_default 作为实验项目名# TRACKER_PROJECT_NAME=""
# if you want to train based on lora ckpt, please set LORA_CKPT and set MODEL_NAME to pretrained model# LORA_CKPT="your_nebula_project.your_lora_ckpt/version=your_version/ckpt_id=checkpoint-xxx"# LORA_CKPT="digital_live_chat.Google-RAG-7B/version=v1.4/ckpt_id=checkpoint-330"
LORA_CKPT="digital_live_chat.sft_model_whale/version=v20.26/ckpt_id=checkpoint-210"
args="--stage dpo \    --model_name_or_path=$MODEL_NAME \    --do_train \    --do_eval \    --val_size 0.05 \    --file_name=${INPUT} \    --ranking \    --system=system \    --prompt=input \    --chosen=pos \    --rejected=neg \    --deepspeed=scripts/ds_zero3.json \    --template=$PROMPT_TEMPLATE \    --finetuning_type lora \    --gradient_checkpointing True \    --lora_target=o_proj,q_proj,k_proj,v_proj,up_proj,gate_proj,down_proj \    --lora_rank=64 \    --lora_alpha=16 \    --output_dir=local/tmp/ckpt_save_path/ \    --overwrite_cache \    --per_device_train_batch_size 1 \    --gradient_accumulation_steps 4 \    --lr_scheduler_type cosine \    --logging_steps 10 \    --num_train_epochs 20 \    --learning_rate=$LR \    --cutoff_len=2048 \    --preprocessing_num_workers=8 \    --dataloader_num_workers=4 \    --plot_loss \    --report_to=none \    --pref_beta=0.2 \    --pref_ftx=0.5 \    --bf16"

在这里可以指定训练的lora checkpoint到指定的项目存储路径,后续可以在whale平台直接调用,非常方便。

训练完成结果和统计图表如下:

挑选eval集合上loss最低的checkpoint作为最优的模型。

2.3. 微调模型部署

在模型配置处可以搜索上一步中生成好的训练模型,选择部署。

自动化的流量和模型性能监控报表:

可视化的对话调试界面:

2.3.1. 推理加速

在模型的推理加速上,探索过以下三种whale平台上配置加速的手段:

  • 降低加载精度(效果会存在损失);

  • 可以选fp16或者int8精度加载模型;

  • 需要关注精度降低后的效果变化;

  • System-prompt缓存,如果prompt长且固定可以用这种方法;

  • [{"task_id": 1, "prompt": " <|im_start|>system\nYou are a helpful assistant.<|im_end|>\n<|im_start|>"},{"task_id": 2, "prompt": "你是一个严谨的程序员,你接下来需要非常谨慎的思考并回答以下问题:"}];

  • 投机采样-vanilla speculative decoding

  • 投机采样:利用“大模型蒸馏后的小模型”预测结果,由大模型验证结果,如qwen-14b 常用蒸馏后的qwen 1b8作为小模型,它可以在不损失生成效果前提下提速。

以Qwen2.5-7B为例,测试不同加速方法带来的提升:

平台自动支持:推理引擎会根据请求自动凑batch推理;支持多并发请求:

2.4. 测试集数据分析

模型微调和部署完成后,往往需要在我们的测试集上查看模型效果,这依赖你需要有:

  • 反映你线上真实情况的测试集;

  • 细化的测评指标;

我们需要预先定义一个指标来判断模型的效果好坏,对于指标定义不明确的任务,尽量细化它的标准。可以让人工去评估,也可以让大模型自动评估。

2.5. 评估迭代:优化 or 上线

经过上述步骤有了新的模型效果后,除了考虑算法工程(耗时、部署资源、模型并发)外,效果上需要考虑是否能推送上线的关注点:

  • 宏观整体指标上的对比(机器/人工);

  • 模型效果是否符合优化预期,目标goodcase;

  • 其他case上,模型效果是否变差,是否需要优化;

从指标和case分析中,发现并定位问题;从数据构造中不断去完善更高质量的数据,探索更强模型和更优的微调方法。

全是goodcase是个理想的情况,实验结果往往会存在不符合预期或者跷跷板的问题,这个时候需要思考是模型能力的问题、还是数据构造上有考虑不周的情况等。不同的任务/base模型/数据质量/训练参数和数据集都有关,还是得结合具体场景来做分析和优化。一般经验来讲提升数据质量是最直接有效的方法,在这个基础上再探索强化学习、推理模型等进一步解决目标问题的手段。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询