Skip to content

LLaMA2 中文适配训练全流程实战

内容整理自学习笔记,仅供面试备考参考;不构成录用、培训或考试承诺。

1. 为什么需要对 LLaMA2 做基于 LoRA 的二次预训练?

加入中文训练语料进行 LLaMA2 的二次预训练,使模型增加支持中文输出的能力。


2. 二次预训练的目标

在保持预训练模型权重不变的情况下,通过添加额外的网络层并仅训练这些新增的网络层参数,实现大模型的高效微调(PEFT)。


3. 核心思想:本征维度(Intrinsic Dimension)

3.1 理论基础

Aghajanyan 研究发现,预训练模型的本征维度实际上非常小——只有一小部分参数对模型输出有显著影响:

存在一个极低维度的参数子空间,微调它和在全参数空间中微调能起到相同的效果。

3.2 LoRA 的数学表达

LoRA 假设模型在任务适配过程中权重的改变量是低秩的:

W=W0+ΔWΔW=BA,ARr×d,BRd×r,rd

参数更新范围:只训练新增的网络层参数


4. 语料构建思路

以中文书籍作为训练语料,来自中文书籍收录整理项目。

4.1 数据集格式

  • 文件格式:.txt
  • 示例数据:《红楼梦》等经典中文书籍
txt
《红楼梦》
曹雪芹 高鄂 著

第一回 甄士隐梦幻识通灵 贾雨村风尘怀闺秀
列位看官:你道此书从何而来?...

5. 基于 LoRA 的 LLaMA2 二次预训练参数配置

5.1 核心参数

python
######## 参数设置 ########
lr = 2e-4                                    # 学习率
lora_rank = 64                               # LoRA 低秩矩阵维数
lora_alpha = 128                             # LoRA 缩放系数(调整 Alpha ≈ 调整 LR)
lora_trainable = "q_proj,v_proj,k_proj,o_proj,gate_proj,down_proj,up_proj"  # 可训练模块
modules_to_save = "embed_tokens,lm_head"      # 额外需要保存的模块
lora_dropout = 0.05                           # Dropout 比率
pretrained_model = "/root/llama/all_transformer"  # 预训练模型路径
chinese_tokenizer_path = "/root/llama/all_transformer"  # 分词器路径
dataset_dir = "/root/llama/data"              # 数据集路径
per_device_train_batch_size = 1               # 每设备批次大小
gradient_accumulation_steps = 1               # 梯度累积步数
block_size = 512                              # 最大序列长度
training_steps = 25000                        # 训练步数

5.2 可训练模块说明

模块说明
q_proj / k_proj / v_proj多头注意力机制中的三个线性变换,将输入映射到高维向量空间
o_proj多头注意力输出层,将模型输出映射到概率分布
gate_proj / down_proj / up_projFFN 中的三个线性变换
embed_tokens将输入 Token 映射到高维向量空间
lm_head预测下一个 Token 的输出层

5.3 启动命令

bash
torchrun --nnodes 1 --nproc_per_node 1 scripts/training/run_clm_pt_with_peft.py \
    --deepspeed ${deepspeed_config_file} \
    --model_name_or_path ${pretrained_model} \
    --tokenizer_name_or_path ${chinese_tokenizer_path} \
    --dataset_dir ${dataset_dir} \
    --data_cache_dir ${data_cache} \
    --validation_split_percentage 0.001 \
    --per_device_train_batch_size ${per_device_train_batch_size} \
    --do_train \
    --seed $RANDOM \
    --fp16 \
    --max_steps ${training_steps} \
    --num_train_epochs 1 \
    --lr_scheduler_type cosine \
    --learning_rate ${lr} \
    --warmup_ratio 0.05 \
    --weight_decay 0.01 \
    --logging_strategy steps \
    --logging_steps 10 \
    --save_strategy steps \
    --save_total_limit 3 \
    --save_steps 500 \
    --gradient_accumulation_steps ${gradient_accumulation_steps} \
    --preprocessing_num_workers 8 \
    --block_size ${block_size} \
    --output_dir ${output_dir} \
    --overwrite_output_dir \
    --ddp_timeout 30000 \
    --logging_first_step True \
    --lora_rank ${lora_rank} \
    --lora_alpha ${lora_alpha} \
    --trainable ${lora_trainable} \
    --modules_to_save ${modules_to_save} \
    --lora_dropout ${lora_dropout} \
    --torch_dtype float16 \
    --gradient_checkpointing \
    --ddp_find_unused_parameters False

6. 基于 LoRA 的 LLaMA2 微调(SFT)

6.1 训练数据

使用 Chinese-LLaMA-Alpaca 开源的中文 Alpaca 数据,包含约 51K 条从 ChatGPT(GPT-3.5-Turbo)爬取的指令数据。

数据格式:

json
{
  "instruction": "我们如何在日常生活中减少用水?",
  "input": "",
  "output": "1. 使用节水装置,如节水淋浴喷头和水龙头..."
}

对于包含 input 字段的数据,采用 f"{instruction}+\n+{input}" 进行拼接。

6.2 微调参数

python
lr = 1e-4                    # 微调 LR 比预训练小
lora_rank = 64
lora_alpha = 128
lora_trainable = "q_proj,v_proj,k_proj,o_proj,gate_proj,down_proj,up_proj"
modules_to_save = "embed_tokens,lm_head"
lora_dropout = 0.05
per_device_train_batch_size = 1
gradient_accumulation_steps = 8
max_seq_length = 512
training_steps = 6000
validation_file = "data_pt/alpaca_data_zh_51k.json"

7. 推理加载

bash
python scripts/inference/inference_hf.py \
    --base_model correspond_output_dir \     # 基础模型
    --lora_model sft_output_dir2/sft_lora_model \  # LoRA 模型(可选)
    --tokenizer_path correspond_output_dir \  # 分词器路径
    --with_prompt                              # 自动用提示符包装输入

推理时也支持:

  • 仅加载基础模型(不指定 --lora_model
  • 加载 LoRA 权重后进行推理
  • 将 LoRA 合并后以标准格式加载

8. DeepSpeed 配置

使用 ds_zero2_no_offload.json 配置 ZeRO-2(无 Offload)进行分布式训练。


9. 显存占用参考

基于 LoRA 的二次预训练相比全参数训练,显存占用显著降低。具体占用取决于:

  • Rank 大小
  • Target Modules 选择
  • Batch Size
  • Sequence Length(block_size)
  • 是否启用 Gradient Checkpointing

10. 关键经验总结

要点建议
Rank二次预训练用 64(比普通 LoRA 的 4-8 大得多)
Alpha默认 = 2 × Rank(128),调节 Alpha ≈ 调节 LR
Target Modules全打满(q/k/v/o + gate/down/up)
Modules to Saveembed_tokens + lm_head(保留词表和输出能力)
LR预训练 2e-4 → 微调 1e-4
数据格式预训练用纯文本 .txt,微调用 Alpaca JSON 格式
DeepSpeedZeRO-2(无 Offload)配 FP16
梯度累积预训练不累积(step=1),微调可累积(step=8)