一、核心概念介绍
1.1 什么是模型微调?
微调(Fine-tuning) 是在预训练模型基础上,使用特定领域数据继续训练,使模型适应特定任务的过程。
类比理解:
•预训练模型 = 完成大学通识教育的毕业生(知识广博但不够专业)
•微调 = 专业岗前培训(快速成为特定领域专家)
•LoRA = 轻量级培训方法(只调整少量参数,成本极低)
1.2 关键概念
| 概念 | 说明 |
|---|---|
| 基座模型 | 已完成预训练的基础模型,具备通用语言能力 |
| LoRA | 低秩适应,一种参数高效微调方法,只训练新增的小量参数 |
| Adapter | 适配器,微调后保存的轻量级权重文件 |
| QLoRA | 量化+LoRA,进一步降低显存需求 |
| 指令微调 | 使用指令-回答对训练,让模型学会遵循指令 |
1.3 微调流程概览
数据准备 → 模型下载 → 配置参数 → 执行微调 → 融合保存 → 验证效果
二、环境准备
2.1 硬件要求
| 配置 | 最低要求 | 推荐配置 |
|---|---|---|
| 内存 | 8GB | 16GB+ |
| 存储 | 20GB | 50GB+ |
| 芯片 | Apple M1 | Apple M2/M3 |
| 系统 | macOS 12+ | macOS 14+ |
2.2 创建虚拟环境
# 创建虚拟环境
python -m venv mlx_env
# 激活环境
source mlx_env/bin/activate # Mac/Linux
# 或
mlx_env\Scripts\activate # Windows
# 升级pip
pip install --upgrade pip
2.3 安装核心框架
# 安装 MLX-LM(Apple 官方框架)
pip install mlx-lm
# 安装实验跟踪工具
pip install swanlab
# 安装模型下载工具
pip install modelscope
验证安装:
python -c "import mlx_lm; print('MLX-LM 安装成功')"
python -c "import swanlab; print('SwanLab 安装成功')"
三、数据准备
3.1 数据格式说明
MLX-LM 支持 JSONL 格式 (每行一个 JSON 对象),推荐使用 ChatML 格式:
{"messages": [{"role": "user", "content": "用户问题"}, {"role": "assistant", "content": "助手回答"}]}
3.2 下载示例数据
# 下载自我认知数据集
modelscope download --dataset swift/self-cognition --local_dir ./self-cognition
3.3 数据格式转换
创建 prepare_data.py:
import json
import os
# 配置模型的身份信息
MY_NAME = "樱花" # 模型的名字
MY_AUTHOR = "River" # 作者/训练者
mlx_data = []
with open("./self-cognition/self_cognition.jsonl", "r") as f:
for line in f:
data = json.loads(line)
user_text = data["query"]
assistant_text = data["response"]
# 替换占位符
if data["tag"] == "zh":
assistant_text = assistant_text.replace("{{NAME}}", MY_NAME).replace("{{AUTHOR}}", MY_AUTHOR)
else:
assistant_text = assistant_text.replace("{{NAME}}", "YingHua").replace("{{AUTHOR}}", "River")
mlx_data.append({
"messages": [
{"role": "user", "content": user_text},
{"role": "assistant", "content": assistant_text}
]
})
# 保存为 MLX 兼容格式
os.makedirs("./mlx_data", exist_ok=True)
with open("./mlx_data/train.jsonl", "w", encoding="utf-8") as f:
for item in mlx_data:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
print(f"✅ 数据准备完成!共 {len(mlx_data)} 条数据")
运行转换:
python prepare_data.py
3.4 数据检查要点
•确保 JSON 格式正确(每行一个有效 JSON)
•确认中文字符正常显示
•检查数据量(建议 100+ 条)
•验证 messages 数组包含 user 和 assistant 角色
四、模型下载
4.1 下载脚本
创建 download_model.py:
from modelscope import snapshot_download
# 下载 Qwen3.5-2B 模型
# cache_dir 指定本地保存目录
model_dir = snapshot_download('Qwen/Qwen3.5-2B', cache_dir="./model")
print(f"✅ 模型下载到: {model_dir}")
4.2 执行下载
python download_model.py
Downloading Model from https://www.modelscope.cn to directory: ./model/Qwen/Qwen3.5-2B
2026-04-11 22:45:25,145 - modelscope - INFO - Got 13 files, start to download ...
Downloading [configuration.json]: 100%|██████████████████████| 51.0/51.0 [00:00<00:00, 308B/s]
Downloading [config.json]: 100%|█████████████████████████| 2.84k/2.84k [00:00<00:00, 17.5kB/s]
Downloading [preprocessor_config.json]: 100%|████████████████| 390/390 [00:00<00:00, 2.37kB/s]
Downloading [chat_template.jinja]: 100%|█████████████████| 7.57k/7.57k [00:00<00:00, 41.4kB/s]
Downloading [model.safetensors.index.json]: 100%|█████████| 62.9k/62.9k [00:00<00:00, 289kB/s]
Downloading [LICENSE]: 100%|█████████████████████████████| 11.1k/11.1k [00:00<00:00, 42.7kB/s]
Downloading [video_preprocessor_config.json]: 100%|██████████| 385/385 [00:00<00:00, 2.43kB/s]
Downloading [tokenizer_config.json]: 100%|███████████████| 16.3k/16.3k [00:00<00:00, 89.5kB/s]
Downloading [merges.txt]: 100%|██████████████████████████| 3.20M/3.20M [00:00<00:00, 9.25MB/s]
Downloading [README.md]: 100%|████████████████████████████| 61.3k/61.3k [00:00<00:00, 304kB/s]
Downloading [vocab.json]: 100%|██████████████████████████| 6.41M/6.41M [00:01<00:00, 6.58MB/s]
Downloading [tokenizer.json]: 100%|██████████████████████| 12.2M/12.2M [00:01<00:00, 9.46MB/s]
Downloading [vocab.json]: 0%| | 0.00/6.41M [00:00<?, ?B/s]
Downloading [model.safetensors-00001-of-00001.safetensors]: 100%|█| 4.24G/4.24G [04:31<00:00,
Processing 13 items: 100%|█████████████████████████████████| 13.0/13.0 [04:31<00:00, 20.9s/it]
2026-04-11 22:49:56,314 - modelscope - INFO - Download model 'Qwen/Qwen3.5-2B' successfully.s]
2026-04-11 22:49:56,315 - modelscope - INFO - Creating symbolic link [./model/Qwen/Qwen3.5-2B].ownloading [model.safetensors-00001-of-00001.safetensors]: 0%| | 7.00M/4.24G [00:01<09:53,
模型下载到: ./model/Qwen/Qwen3___5-2Bof-00001.safetensors]: 1%| | 62.0M/4.24G [00:06<05:20,
预期输出:显示下载进度,完成后打印模型路径。
4.3 模型选型建议
| 模型 | 参数 | 内存需求 | 适用场景 |
|---|---|---|---|
| Qwen3.5-2B | 2B | 4-6GB | Mac 首选,平衡性能 |
| Qwen3-0.6B | 0.6B | 2-3GB | 快速实验 |
| Qwen3.5-4B | 4B | 8-12GB | 追求效果 |
五、执行微调
5.1 基础微调命令
mlx_lm.lora \
--model ./model/Qwen/Qwen3.5-2B \
--train \
--data ./mlx_data \
--adapter-path ./my_first_adapter \
--fine-tune-type lora \
--batch-size 1 \
--iters 300
5.2 关键参数说明
| 参数 | 说明 | 推荐值 |
|---|---|---|
--model |
基础模型路径 | 本地下载的模型目录 |
--data |
训练数据目录 | 包含 train.jsonl |
--adapter-path |
LoRA 权重保存路径 | ./my_adapter |
--batch-size |
批次大小 | 1(内存友好) |
--iters |
训练迭代次数 | 300-1000 |
--learning-rate |
学习率 | 1e-5 ~ 5e-5 |
--max-seq-length |
最大序列长度 | 512 |
5.3 高级配置(可选)
创建 lora_config.yaml:
model: "./model/Qwen/Qwen3.5-2B"
train: true
fine_tune_type: lora
data: "./mlx_data"
adapter_path: "./my_first_adapter"
batch_size: 1
iters: 500
learning_rate: 5e-5
max_seq_length: 512
lora_parameters:
rank: 8
scale: 20.0
dropout: 0.05
使用配置文件:
mlx_lm.lora --config lora_config.yaml
5.4 训练过程监控
训练过程中会显示:
Loading pretrained model
Loading datasets
Warning: Validation set not found or empty. Training will proceed without validation.
Training
Trainable parameters: 0.298% (5.606M/1881.825M)
Starting training..., iters: 300
Iter 10: Train loss 2.174, Learning Rate 1.000e-05, It/sec 0.667, Tokens/sec 28.002, Trained Tokens 420, Peak mem 6.926 GB
Iter 20: Train loss 1.505, Learning Rate 1.000e-05, It/sec 1.361, Tokens/sec 74.973, Trained Tokens 971, Peak mem 7.874 GB
Iter 30: Train loss 1.340, Learning Rate 1.000e-05, It/sec 2.421, Tokens/sec 101.432, Trained Tokens 1390, Peak mem 7.874 GB
Iter 40: Train loss 0.982, Learning Rate 1.000e-05, It/sec 1.891, Tokens/sec 96.843, Trained Tokens 1902, Peak mem 7.874 GB
......
Iter 280: Train loss 0.426, Learning Rate 1.000e-05, It/sec 2.141, Tokens/sec 101.055, Trained Tokens 13730, Peak mem 7.913 GB
Iter 290: Train loss 0.363, Learning Rate 1.000e-05, It/sec 2.184, Tokens/sec 101.359, Trained Tokens 14194, Peak mem 7.913 GB
Iter 300: Train loss 0.416, Learning Rate 1.000e-05, It/sec 2.145, Tokens/sec 97.800, Trained Tokens 14650, Peak mem 7.913 GB
Iter 300: Saved adapter weights to my_first_adapter/adapters.safetensors and my_first_adapter/0000300_adapters.safetensors.
Saved final weights to my_first_adapter/adapters.safetensors.
关键观察:loss 值应随着迭代次数增加而稳定下降。
六、模型融合与保存
6.1 为什么要融合?
•LoRA 权重(几十 MB)需要配合原始模型使用
•融合后模型(几 GB)可独立运行,便于部署
6.2 执行融合
mlx_lm.fuse \
--model ./model/Qwen/Qwen3.5-2B \
--adapter-path ./my_first_adapter \
--save-path ./my_first_model
6.3 融合结果
融合后的 ./my_first_model 目录包含完整的模型文件:
•model.safetensors - 模型权重
•tokenizer.json - 分词器
•config.json - 模型配置
七、验证测试
7.1 测试原始模型(微调前)
mlx_lm chat --model ./model/Qwen/Qwen3.5-2B
对话示例:
>> 你是会,你叫什么名字
首先,我需要明确用户的问题。用户问的是"你是会,你叫什么名字",这里可能存在一些打字错误。根据上下文,用户可能想问"你是人工智能,你叫什么名字"。
接下来,我需要确认自己的身份。我是 Qwen3.5,是阿里巴巴通义实验室研发的超大规模语言模型。我的名字是 Qwen3.5。
然后,我需要检查用户的问题是否有误。用户的问题中"你是会"可能是"你是人工智能"的误写,或者"你是会"可能是"你是会"的口语化表达。但根据常识,用户应该是在询问我的身份。
我需要确保回答准确,同时保持友好。我应该直接说明我的名字,并简要介绍自己的身份,避免让用户感到困惑。
另外,用户可能没有意识到我作为 AI 的身份,所以回答时应该清晰、简洁,并引导用户进一步提问。
最后,检查是否有其他可能的误解。例如,用户可能想问"你是会做什么",但根据问题,更可能是询问名字。因此,回答应聚焦于身份介绍。
</think>
你好!我是 Qwen3.5,是阿里巴巴通义实验室研发的超大规模语言模型。我的名字是 Qwen3.5,你可以叫我 Qwen。
7.2 测试微调后模型(方式一:使用 Adapter)
mlx_lm chat --model ./model/Qwen/Qwen3.5-2B --adapter-path ./my_first_adapter
7.3 测试微调后模型(方式二:使用融合模型)
mlx_lm chat --model ./my_first_model
对话示例:
>> 你是谁,你叫什么名字
嗯,用户问我是谁,叫什么名字。作为AI助手,我需要明确自己的身份。我是由river开发的人工智能模型,名为樱花。我应该直接回答自己的名字,并简要说明身份。不需要过多解释,保持简洁明了。用户可能想知道我的身份,所以直接回答"我是river开发的人工智能模型,名字叫樱花"就可以了。不需要添加其他信息,避免混淆。确认无误后,输出答案。
</think>
我是river开发的人工智能模型,名字叫樱花。
7.4 验证要点
•模型能正确回答身份问题
•回答中包含你设置的 MY_NAME 和 MY_AUTHOR
•中文对话流畅自然
八、使用 SwanLab 监控训练
8.1 集成代码示例
创建 train_with_monitor.py:
import swanlab
from mlx_lm import load, lora
from mlx_lm.tuner import Trainer, TrainingArgs, LoRAConfig
# 初始化 SwanLab
swanlab.init(
project="qwen-finetune",
config={
"model": "Qwen3.5-2B",
"learning_rate": 5e-5,
"batch_size": 1,
"iters": 300,
"lora_rank": 8,
"max_seq_length": 512,
}
)
# 加载模型
model, tokenizer = load("./model/Qwen/Qwen3.5-2B")
# 配置 LoRA
lora_config = LoRAConfig(
rank=8,
alpha=32,
dropout=0.05,
target_modules=["q_proj", "v_proj"],
)
# 配置训练参数
args = TrainingArgs(
batch_size=1,
iters=300,
learning_rate=5e-5,
adapter_file="./my_first_adapter",
)
# 创建训练器
trainer = Trainer(
model=model,
tokenizer=tokenizer,
args=args,
lora_config=lora_config,
)
# 自定义训练循环记录 loss
global_step = 0
for epoch in range(3):
for batch in trainer.train_loader():
loss = trainer.train_step(batch)
swanlab.log({"train/loss": float(loss), "step": global_step})
global_step += 1
if global_step >= args.iters:
break
break
swanlab.finish()
print("训练完成,运行 'swanlab watch' 查看可视化结果")
8.2 查看监控面板
# 启动 SwanLab 本地服务
swanlab watch
然后打开浏览器访问 http://127.0.0.1:5092 查看实时训练曲线。
九、常见问题与解决方案
9.1 网络问题
问题:下载模型时超时或失败
解决方案:
# 使用国内镜像
pip install modelscope
# 通过 modelscope 下载,国内网络友好
9.2 内存不足
问题:训练时提示内存不足
解决方案:
# 降低 batch-size
--batch-size 1
# 减小序列长度
--max-seq-length 256
# 使用更小的模型
--model Qwen/Qwen3-0.6B
9.3 训练效果不佳
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| Loss 不下降 | 学习率太小 | 提高学习率到 1e-4 |
| Loss 震荡剧烈 | 学习率太大 | 降低学习率到 1e-5 |
| 模型答非所问 | 数据量不足 | 增加训练数据 |
| 过拟合 | 训练轮次太多 | 减少 iters 到 200 |
9.4 命令找不到
问题 :mlx_lm 命令不存在
解决方案:
# 使用 Python 模块方式调用
python -m mlx_lm.lora --model ... --train ...
python -m mlx_lm.fuse --model ...
python -m mlx_lm.chat --model ...
十、完整操作流程速查表
| 步骤 | 命令 | 说明 |
|---|---|---|
| 1. 安装环境 | pip install mlx-lm swanlab modelscope |
安装依赖 |
| 2. 准备数据 | modelscope download --dataset swift/self-cognition |
下载示例数据 |
| 3. 转换数据 | python prepare_data.py |
转换格式 |
| 4. 下载模型 | python download_model.py |
下载 Qwen3.5-2B |
| 5. 执行微调 | mlx_lm.lora --model ./model/Qwen/Qwen3.5-2B --train --data ./mlx_data --adapter-path ./my_first_adapter --batch-size 1 --iters 300 |
开始训练 |
| 6. 融合模型 | mlx_lm.fuse --model ./model/Qwen/Qwen3.5-2B --adapter-path ./my_first_adapter --save-path ./my_first_model |
保存完整模型 |
| 7. 验证效果 | mlx_lm chat --model ./my_first_model |
测试对话 |
十一、总结
关键要点回顾
1.数据是核心:高质量的数据比大量低质量数据更重要
2.LoRA 是首选:参数高效,内存友好,效果接近全量微调
3.MLX 是 Mac 最佳选择:Apple 官方优化,充分利用统一内存
4.小步快跑:先用小模型、小数据跑通流程,再逐步扩大
下一步学习方向
•使用自己的数据集(聊天记录、文档、代码等)
•尝试不同的 LoRA 参数配置
•学习更多微调技术(QLoRA、Adapter、P-tuning)
•部署微调后的模型到生产环境