在《昇思 + 昇腾开发板:软硬结合玩转 DeepSeek 开发实战》课程学习中,《模型 LoRA 微调》是第二部分内容,这部分的学习让我对高效微调模型有了全新的认识,通过视频学习和代码实践,我掌握了 LoRA 微调的核心流程,收获颇丰,接下来就和大家分享我的学习经验。
首先,得弄清楚什么是 LoRA 微调。LoRA(Low-Rank Adaptation)是一种高效的参数微调方法,属于参数高效微调(Parameter-Efficient Fine-Tuning, PEFT)的范畴。它最核心的思想是,在不改变原始模型大部分参数的情况下,只对模型的关键部分进行小幅度调整,这样就能让模型更好地适应新的任务或数据,既高效又实用。
具体来讲,LoRA 的方法是在模型的注意力层(Attention Layer)中引入特殊结构。注意力层是模型处理信息的关键,它通过 Query(查询)、Key(键)、Value(值)这三个模块来理解输入数据。而 LoRA 的巧妙之处在于,它在这些模块中添加了一个低秩旁路结构,这个旁路由两个可训练的低维矩阵 A 和 B 组成。这两个矩阵的作用是替代对原始大矩阵的直接更新,也就是说,我们不用重新训练整个模型的所有参数 —— 这会非常耗时耗资源,只需更新这两个小矩阵就行。如此一来,训练的参数量大幅减少,计算和内存开销也大大降低,但模型性能却能保持接近全参数微调的水平,这一点真的很厉害。
在进行 LoRA 微调之前,我们可以先加载一个预训练好的基础模型。这类模型通常都用海量数据训练过,就像 DeepSeek 那样,加载它主要是为了利用那些预训练好的权重,为后续微调打下良好基础。
在代码实现环节,教程基于昇思 MindSpore 框架,对 DeepSeek-R1-Distill-Qwen-1.5B 模型进行了 LoRA 微调,目标是让模型能够模仿《甄嬛传》中甄嬛的语气和风格进行对话,这个实例很有趣,也让我更直观地理解了 LoRA 微调的应用。
这段代码基于昇思 MindSpore 框架实现该任务,按代码执行逻辑,LoRA 微调的全流程可以拆解为以下几个部分:
一、环境准备:搭建基础依赖
代码首先完成微调所需的环境配置,确保工具链能兼容昇腾开发板和 LoRA 微调需求。安装 MindSpore 框架,指定安装 mindspore==2.6.0,它是支持 LoRA 微调及昇腾硬件的核心框架,能提供模型训练、推理的基础能力;安装 MindNLP 库,即 mindnlp==0.4.1,这是昇思生态下的 NLP 工具库,可提供预训练模型加载、数据集处理、LoRA 适配等功能,且已适配昇腾开发板的 Qwen 系列模型;还安装了 openmind_hub,用于从魔乐社区下载专用数据集,比如包含甄嬛风格对话数据的 huanhuan.json。
二、数据集下载与处理:适配模型输入格式
数据集就像是微调的 “教材”,必须处理成模型可理解的格式,具体步骤如下:
-
下载数据集:通过 om_hub_download 从魔乐社区下载 huanhuan.json,该数据集包含大量模仿甄嬛语气的对话样本,像 “User: 你是谁? Assistant: 本宫是钮祜禄・甄嬛”,为模型学习风格提供了数据基础。
-
加载与格式化数据:实例化 Tokenizer,使用 DeepSeek-R1-Distill-Qwen-1.5B-FP16 模型对应的分词器,统一文本到 token 的转换规则;设置 pad_token = eos_token,因为该模型中填充符与结束符一致,并将 padding 方向设为右侧,避免影响文本语义。
定义数据处理逻辑(process_func),核心是将原始对话格式化为模型训练所需的 “输入 - 标签” 对,具体规则为:输入文本格式是 User: {问题}\n\nAssistant: {回答},用 eos_token 标记结束;标签(labels)设置上,仅对 “Assistant: 回答” 部分计算损失,标签为对应 token,“User: 问题” 部分不参与训练,标签设为 - 100,MindSpore 会忽略该值;长度处理上,统一序列长度为 64,超过则截断,不足则用 pad_token 填充,确保批量训练时输入维度一致。另外,为加速演示,仅取前 3 条数据用于训练,实际场景则需用完整数据集。
三、基础模型加载:准备预训练 “底座”
LoRA 微调的核心是 “冻结预训练模型参数,仅训练新增的低秩矩阵”,所以要先加载预训练模型作为 “底座”。通过 AutoModelForCausalLM.from_pretrained 加载 DeepSeek-R1-Distill-Qwen-1.5B-FP16 模型,该模型是 DeepSeek-R1 的轻量蒸馏版,参数规模 1.5B,适合在昇腾开发板等边缘设备运行。同时,加载模型默认的生成配置,如 pad_token_id、eos_token_id,并将 pad_token_id 与 eos_token_id 对齐,因为模型设计中两者共享 token,这样能避免生成时格式混乱。
四、LoRA 配置与模型构建:实现参数高效微调
这是 LoRA 微调的核心环节,通过插入低秩矩阵实现 “少参数微调”。
-
LoRA 参数配置(LoraConfig):task_type=TaskType.CAUSAL_LM,指定任务为因果语言模型,适用于对话生成场景;target_modules 指定在模型的哪些层插入 LoRA 低秩矩阵,这里选择注意力层的 q_proj(Q 投影)、k_proj(K 投影)、v_proj(V 投影)、o_proj(输出投影)及前馈层的 gate_proj、up_proj、down_proj,这些都是影响模型语义表达的关键模块;r=8,即低秩矩阵的秩(矩阵维度),控制参数规模,秩越小,参数越少,这里仅需训练 0.5% 的参数;lora_alpha=32,是缩放因子,用于调整低秩矩阵的更新强度,alpha/r 决定有效学习率;lora_dropout=0.1,为 dropout 层,可防止过拟合。
-
构建 LoRA 模型:通过 get_peft_model (base_model, config) 将基础模型与 LoRA 配置结合,生成可训练的 LoRA 模型。此时模型的原始参数被冻结,仅新增的低秩矩阵(矩阵 A 和 B)可训练。代码中 model.print_trainable_parameters () 验证了这一点,可训练参数仅占总参数的 0.5%,充分体现了 LoRA “参数高效” 的特点。
五、训练设置与回调:控制训练过程
为确保训练稳定进行并保存关键结果,需要配置训练参数和回调函数。
-
训练超参数(TrainingArguments):output_dir 指定模型权重保存路径,即./output/DeepSeek-R1-Distill-Qwen-1.5B;per_device_train_batch_size=1,单设备 batch size,由于昇腾开发板内存有限,设为 1 避免溢出;logging_steps=1,每 1 步打印训练日志,便于监控损失变化;num_train_epochs=1,训练轮次,这是演示用,实际需根据数据量调整;save_steps=3,每 3 步保存一次权重,便于中断后续训练;learning_rate=1e-4,学习率,LoRA 微调的学习率通常高于全量微调,因为仅更新少量参数。
-
自定义回调函数(SavePeftModelCallback):LoRA 微调仅需保存新增的 “适配器权重”(低秩矩阵参数),无需保存完整基础模型,这样能节省空间。该回调函数的作用是,在训练到 save_steps 指定的步数时,将 LoRA 适配器权重保存到 adapter_model 目录;同时自动删除保存路径中额外生成的基础模型权重文件,如 model.safetensors,避免冗余存储。
六、启动训练:模型学习风格特征
通过 Trainer 实例化训练器,传入模型、训练参数、数据集和回调函数,调用 trainer.train () 启动微调。训练过程中,模型仅更新 LoRA 低秩矩阵的参数,通过学习 huanhuan.json 中甄嬛的对话风格,比如用词、语气等,逐步调整对 “宫廷语境” 的响应模式。
总结一下,LoRA 微调的核心优势很突出:参数高效,仅训练 0.5% 的参数,大幅降低了昇腾开发板的内存和计算开销;风格可控,通过特定数据集(huanhuan.json)能定向优化模型的对话风格;部署灵活,微调后仅需保存小体积的适配器权重,而非全量模型,便于在边缘设备部署。这次学习让我对 LoRA 微调有了扎实的掌握,相信在后续的实践中能灵活运用这项技术。