模型微调
准备硬件资源、搭建环境
在云平台上租用一个实例(如 AutoDL,官网:https://www.autodl.com/market/list)云平台一般会配置好常用的深度学习环境,如 anaconda, cuda等等
本机通过 SSH 连接到远程服务
使用 Visual Studio Remote 插件 SSH 连接到你租用的服务
Remote-SSH连接服务器连接后打开个人数据盘文件夹 /root/autodl-tmp
LLaMA-Factory 安装部署
LLaMA-Factory 的 Github地址:https://github.com/hiyouga/LLaMA-Factory
克隆仓库
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git切换到项目目录
cd LLaMA-Factory创建 conda 虚拟环境(一定要 3.10 的 python 版本,不然和 LLaMA-Factory 不兼容)
conda create -n llama-factory python=3.10激活虚拟环境
conda activate llama-factory在虚拟环境中安装 LLaMA Factory 相关依赖
pip install -e ".[metrics]"在这个官网找到和cuda对应的版本进行安装https://pytorch.org/get-started/locally/
nvidia-smi。#查看cuda版本
pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 --index-url https://download.pytorch.org/whl/cu124检验是否安装成功
llamafactory-cli version启动 LLama-Factory 的可视化微调界面 (由 Gradio 驱动)
llamafactory-cli webui配置端口转发(VScode可以自动配置转发,使用vscode插件这步可以省略)
在本地电脑的终端(cmd / powershell / terminal等)中执行代理命令,其中root@123.125.240.150和 42151分别是实例中SSH指令的访问地址与端口,请找到自己实例的ssh指令做相应替换。 7860:127.0.0.1:7860是指代理实例内 7860端口到本地的 7860端口
ssh -CNg -L 7860:127.0.0.1:7860 root@123.125.240.150 -p 42151从 HuggingFace 上下载基座模型
HuggingFace 是一个集中管理和共享预训练模型的平台 https://huggingface.co
创建文件夹统一存放所有基座模型mkdir Hugging-Face
修改 HuggingFace 的镜像源
export HF_ENDPOINT=https://hf-mirror.com修改模型下载的默认位置
export HF_HOME=/root/autodl-tmp/Hugging-Face注意:这种配置方式只在当前 shell 会话中有效,如果你希望这个环变量在每次启动终端时都生效,可以将其添加到你的用户配置文件中(修改 ~/.bashrc 或 ~/.zshrc)
安装 HuggingFace 官方下载工具
pip install -U huggingface_hub#执行下载命令
huggingface-cli download --resume-download deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B可视化页面上加载模型测试,检验是否加载成功
这里的路径是模型文件夹内部的模型特定快照的唯一哈希值,而不是整个模型文件夹

/root/autodl-tmp/Hugging-Face/hub/models--deepseek-ai--DeepSeek-R1-Distill-Qwen-1.5B/snapshots/530ca3e1ad39d440e182c2e4317aa40f012512fa准备用于训练的数据集,添加到指定位置
上一篇文章详细介绍了如何准备数据集
格式大概如下

将自己的数据集放到 LLama-Factory 的 data 目录 下
修改 dataset_info.json 文件,添加如下配置:
"chatlog": {
"file_name": "chatlog.json"
},在页面上进行微调的相关设置,开始微调
选择微调算法 Lora
添加数据集 magic_conch
修改其他训练相关参数,如学习率、训练轮数、截断长度、验证集比例等
学习率(Learning Rate) :决定了模型每次更新时权重改变的幅度。过大可能会错过最优解;过小会学得很慢或陷入局部最优解
训练轮数(Epochs) :太少模型会欠拟合(没学好) ,太大会过拟合(学过头了)
最大梯度范数(Max Gradient Norm) :当梯度的值超过这个范围时会被截断,防止梯度爆炸现象
最大样本数(Max Samples) :每轮训练中最多使用的样本数
计算类型(Computation Type) :在训练时使用的数据类型,常见的有 float32 和float16。在性能和精度之间找平衡
截断长度(Truncation Length) :处理长文本时如果太长超过这个阈值的部分会被截断掉,避免内存溢出
批处理大小(Batch Size) :由于内存限制,每轮训练我们要将训练集数据分批次送进去,这个批次大小就是 Batch Size
梯度累积(Gradient Accumulation) :默认情况下模型会在每个 batch 处理完后进行一
次更新一个参数,但你可以通过设置这个梯度累计,让他直到处理完多个小批次的数据后才进行一次更新
验证集比例(Validation Set Proportion) :数据集分为训练集和验证集两个部分,训练集用来学习训练,验证集用来验证学习效果如何
学习率调节器(Learning Rate Scheduler) :在训练的过程中帮你自动调整优化学习率
页面上点击启动
训练,或复制命令到终端启动训练
实践中
推荐用 nohup 命令将训练任务放到后台执行,这样即使关闭终端任务也会继续运行。同时将日志重定向到文件中保存下来
在训练过程中
注意观察损失曲线,尽可能将损失降到最低
如损失降低太慢,尝试增大学习率如训练结束损失还呈下降趋势,增大训练轮数确保拟合
微调结束,评估微调效果
观察损失曲线的变化;观察最终损失
在交互页面上通过预测/对话等方式测试微调好的效果
检查点:保存的是模型在训练过程中的一个中间状态,包含了模型权重、训练过程中使用的配置(如学习率、批次大小)等信息,对LoRA来说,检查点包含了训练得到的 B 和 A 这两个低秩矩阵的权重
若微调效果不理想,你可以:使用更强的预训练模型,增加数据量优化数据质量(数据清洗、数据增强等,可学习相关论文如何实现,调整训练参数,如学习率、训练轮数、优化器、批次大小等等
导出合并后的模型
为什么要合并:因为 LoRA 只是通过低秩矩阵调整原始模型的部分权重,而不直接修改原始模型的权重。合并步骤将 LoRA 权重与原始模型权重融合生成一个完整的模型
先创建目录,用于存放导出后的模型
mkdir -p Models/deepseek-r1-1.5b-merged
模型部署和暴露接口
创建新的 conda 虚拟环境用于部署模型
conda create -n fastApi python=3.10激活环境
conda activate fastApi在该环境中下载部署模型需要的依赖
conda install -c conda-forge fastapi uvicorn transformers pytorch
pip install safetensors sentencepiece protobuf通过 FastAPI 部署模型并暴露 HTTP 接口
创建应用文件夹
mkdir App创建 main.py 文件,作为启动应用的入口
touch main.py修改 main.py 文件并保存
from fastapi import FastAPI
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
app = FastAPI()
# 模型路径
model_path = "/root/autodl-tmp/Models/deepseek-r1-1.5b-merged"
# 加载 tokenizer (分词器)
tokenizer = AutoTokenizer.from_pretrained(model_path)
# 加载模型并移动到可用设备(GPU/CPU)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = AutoModelForCausalLM.from_pretrained(model_path).to(device)
@app.get("/generate")
async def generate_text(prompt: str):
# 使用 tokenizer 编码输入的 prompt
inputs = tokenizer(prompt, return_tensors="pt").to(device)
# 使用模型生成文本
outputs = model.generate(inputs["input_ids"], max_length=150)
# 解
码生成的输出
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
return {"generated_text": generated_text}进入包含 main.py 文件的目录,然后运行以下命令来启动 FastAPI 应用
uvicorn main:app --reload --host 0.0.0.0- `main` 是 Python 文件名(要注意不包含 `.py` 扩展名)
- `app` 是 FastAPI 实例的变量名(代码中 `app = FastAPI()`)
- `--reload` 使代码更改后可以自动重载,适用于开发环境
- `host 0.0.0.0`:将 FastAPI 应用绑定到所有可用的网络接口,这样我们的本机就可以通过内网穿透访问该服务配置端口转发,使得本机可以访问该服务 SSH隧道
浏览器输入以下 url,测试服务是否启动成功
http://localhost:8000/docs
或者你也可以通过 postMan 来测试
http://localhost:8000/generate?prompt=你是谁?