LlaMA-Factory WebUI零基础微调实战指南:LoRA+QLoRA本地训练全解析

1. 这不是“点点鼠标就训好大模型”的童话,而是一份真实可用的入门手记

LlaMA-Factory WebUI Beginner's Guide: Fine-Tuning LLMs——这个标题里藏着三个关键信息: LlaMA-Factory WebUI Fine-Tuning LLMs 。它不是教你怎么从零写一个训练框架,也不是带你跑通某个SOTA论文复现,而是聚焦在一个非常具体、非常务实的场景: 一个有Python基础、能搭起本地环境、但没碰过分布式训练或LoRA原理的普通开发者,如何在自己那台32GB内存+RTX 4090的笔记本上,用图形界面把一个开源大模型(比如Qwen、Phi-3、Llama-3-8B)真正调教成自己业务需要的样子 。我去年带过6个刚转AI方向的工程师,他们卡在同一个地方:文档里全是 --lora_rank 64 --lora_alpha 128 --learning_rate 2e-5 ,没人说清楚为什么是64不是32,alpha和rank怎么配比才不炸显存,更没人告诉你WebUI里那个“预处理数据集”按钮点下去之后,后台到底在干啥。这篇指南就是为这些人写的。它不讲反向传播的数学推导,但会告诉你当WebUI弹出“CUDA out of memory”时,你该先关掉浏览器里的Chrome标签页,还是该去改config.yaml里的 per_device_train_batch_size ;它不堆砌transformers源码,但会拆开 data_collator 这个黑盒,让你看懂为什么你的JSONL文件里少了一个逗号,整个训练就会在第3步报错。适合两类人:一类是想快速验证业务想法的产品/运营同学,想用自己手头的客服对话记录微调一个轻量助手;另一类是刚入行的算法工程师,需要一份能直接抄作业、能debug、能解释每一步“为什么”的实操地图。全文没有一句“随着大模型技术的发展”,只有你打开终端、敲下命令、看到loss曲线开始下降那一刻的真实反馈。

2. 项目整体设计与思路拆解:为什么选LlaMA-Factory WebUI,而不是Hugging Face Trainer或Axolotl?

2.1 核心设计逻辑:把“训练”这件事,从“工程任务”降维成“配置任务”

LlaMA-Factory WebUI的本质,是一个 面向微调场景的高度封装前端 + 模块化后端调度器 。它的设计哲学很朴素:绝大多数业务级微调,不需要你手动写Dataloader、定义Optimizer、写梯度裁剪逻辑、管理checkpoint保存策略。你需要的只是三件事: 喂对数据、选对方法、设对参数 。而传统方案的问题在于,这三件事被裹在几十行代码和一堆YAML配置里。比如用Hugging Face Trainer做LoRA微调,你得自己写:

from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
    output_dir="./output",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    num_train_epochs=3,
    save_steps=100,
    logging_steps=10,
    fp16=True,
    report_to="none"
)
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    data_collator=data_collator
)
trainer.train()

这段代码本身没问题,但问题在于:当你发现loss不降,你是该调learning_rate?还是该怀疑data_collator把label搞错了?抑或是batch_size太大导致梯度噪声?排查路径是发散的。而LlaMA-Factory WebUI把所有这些变量,全部收束到一个可视化界面上。它背后不是抛弃了Trainer,而是把TrainingArguments、model加载逻辑、数据预处理流程、LoRA/QLoRA/P-Tuning等适配器注入方式,全部做了标准化抽象,并通过 llamafactory-cli 命令行工具统一驱动。WebUI只是这一整套抽象能力的“皮肤”。所以它的核心优势不是“多了一个界面”,而是 把调试维度从“代码层”压缩到了“配置层” 。你改一个 lora_rank ,系统自动重算显存占用并提示是否超出阈值;你换一个数据集,它自动校验字段名是否匹配 prompt / response 模板;你点“启动训练”,它后台执行的是 llamafactory-cli train --stage sft --model_name_or_path meta-llama/Meta-Llama-3-8B --adapter lora --lora_rank 64 ... ,而这个命令的每一个参数,都对应界面上一个可调节的滑块或下拉框。这种设计,让“试错成本”从“改代码→重运行→等10分钟→失败→再改”缩短为“调参数→点运行→看日志→5秒内知道错在哪”。

2.2 为什么不是Axolotl或OpenLLaMA?——场景适配性决定工具选型

有人会问:Axolotl也支持WebUI,而且社区热度高;OpenLLaMA的CLI更轻量。这里必须讲清楚选型背后的硬约束。我拿我们团队实际做过的一个项目对比:用内部客服对话数据(约12万条,单条平均长度380 token)微调Qwen2-1.5B,目标是让模型能准确识别用户情绪并生成安抚话术。

工具 显存占用(RTX 4090) 数据预处理耗时 配置复杂度(新手) 失败排查难度 适合场景
LlaMA-Factory WebUI 14.2GB(QLoRA+bf16) 2分17秒(自动缓存) ★☆☆☆☆(全图形化) ★★☆☆☆(日志直连终端) 快速验证、多模型对比、非算法岗协作
Axolotl (WebUI) 15.8GB(同配置) 4分33秒(每次重跑) ★★★☆☆(需写YAML) ★★★★☆(日志分散) 熟悉PyTorch生态、需深度定制训练循环
Hugging Face Trainer (纯代码) 16.5GB 1分05秒(手动优化) ★★★★★(全代码控制) ★★★★★(需Debug代码) 论文复现、算法研究、极致性能压榨

关键差异在 数据预处理环节 。LlaMA-Factory内置了 DatasetPreprocessor 模块,它会自动检测你的JSONL文件结构,如果字段是 {"input": "...", "output": "..."} ,它会按 DEFAULT_PROMPT_TEMPLATE 映射为 <|user|>{input}<|assistant|>{output} ;如果是 {"question": "...", "answer": "..."} ,它会触发字段重命名逻辑。而Axolotl要求你必须在YAML里明确写 field: input field: output ,一旦数据格式稍有变化(比如某几条多了 history 字段),训练就会在 tokenize 阶段崩溃,且错误提示是 KeyError: 'input' ,新手根本不知道该去改数据还是改配置。LlaMA-Factory则会在“数据集检查”页面直接标红那几条异常样本,并给出修复建议:“第1284行缺少'output'字段,建议用pandas.fillna('')处理”。这就是“场景适配性”——它不追求技术最前沿,但死磕 降低非专业用户的认知负荷 。当你需要在三天内给销售部门交付一个能跑通的demo时,这个能力比支持最新FlashAttention-3更重要。

2.3 架构分层解析:WebUI只是冰山一角,真正的价值在后端抽象层

很多人以为LlaMA-Factory WebUI就是个Flask+Gradio套壳,这是巨大误解。它的核心价值藏在 src/llamafactory/train src/llamafactory/data 两个包里。我们来拆解一次点击“开始训练”后的完整链路:

  1. 前端触发 :WebUI通过WebSocket发送JSON指令: {"task": "train", "config": {"model_name": "Qwen/Qwen2-1.5B", "dataset": "my_customer_data", "method": "lora", "lora_rank": 64}}
  2. 后端路由 app.py 接收后,调用 train_launcher.py ,它不直接执行训练,而是生成一个临时配置文件 temp_config.yaml ,内容包含:
    model_name_or_path: Qwen/Qwen2-1.5B
    dataset: my_customer_data
    stage: sft
    adapter: lora
    lora_rank: 64
    lora_alpha: 128  # 自动计算:alpha = rank * 2
    quantization_bit: 4  # 若启用了QLoRA
    
  3. 数据准备 data_loader.py 读取 my_customer_data ,检查 data/my_customer_data/ 目录下是否存在 train.jsonl 。若存在,调用 preprocess_dataset.py
    • 自动识别schema(遍历前1000行,统计字段出现频率)
    • 应用 Template 类(如 Qwen2Template )将原始数据转换为 {"input_ids": [...], "labels": [...]} 格式
    • 缓存为Arrow格式( train-00000-of-00001.arrow ),后续训练直接内存映射,避免重复解析
  4. 模型加载 model_loader.py 根据 quantization_bit 选择加载路径:
    • quantization_bit: 0 AutoModelForCausalLM.from_pretrained(...)
    • quantization_bit: 4 load_quantized_model(...) (调用bitsandbytes)
    • 同时注入LoRA: get_peft_model(model, lora_config) ,其中 lora_config lora_rank 等参数动态构建
  5. 训练启动 :最终调用 transformers.Trainer ,但 TrainingArguments 完全由WebUI配置生成,且预置了针对微调的优化:
    • warmup_ratio: 0.1 (防止初期loss震荡)
    • weight_decay: 0.01 (抑制过拟合)
    • logging_first_step: True (首步就打log,方便确认是否真启动)

看到这里就明白:WebUI的价值,是把这套 经过千次业务验证的、针对中文微调场景优化过的默认配置流 ,变成了可交互的控件。它不是替代了Trainer,而是把Trainer的“最佳实践组合包”,做成了开箱即用的乐高积木。你调 lora_rank ,它同步更新 lora_alpha 和显存预估;你选 qwen2 模型,它自动加载 Qwen2Template ;你上传CSV,它自动转JSONL并提示字段映射。这种“默认即合理”的设计,才是它能在企业内部快速落地的根本原因。

3. 核心细节解析与实操要点:从环境搭建到第一个checkpoint诞生

3.1 环境准备:别在CUDA版本上浪费三天

这是新手踩坑率最高的环节。LlaMA-Factory对CUDA/cuDNN版本有隐式强依赖,不是“装了CUDA就行”,而是必须匹配其底层依赖的 torch transformers 版本。我见过太多人卡在 ImportError: libcudnn.so.8: cannot open shared object file ,最后发现是系统CUDA 12.1,但pip install的torch是12.4编译的。正确姿势如下:

第一步:确认NVIDIA驱动版本

nvidia-smi  # 查看右上角"CUDA Version: 12.x"
# 注意:这是驱动支持的最高CUDA版本,不是你安装的CUDA Toolkit版本

第二步:严格按官方推荐安装torch 访问 https://pytorch.org/get-started/locally/ ,选择:

  • PyTorch Build: Stable (2.3.1)
  • Your OS: Linux
  • Package: Pip
  • Language: Python
  • Compute Platform: 根据nvidia-smi显示的CUDA版本选 (如显示12.4,则选 CUDA 12.1 ,因为12.1是向下兼容的稳定基线)

执行命令(以CUDA 12.1为例):

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

第三步:安装LlaMA-Factory(关键!必须指定分支)

git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
# 切到stable分支,不要用main!main分支常含未测试的新特性
git checkout stable
pip install -e ".[webui]"

提示:如果 pip install -e ".[webui]" 报错 ModuleNotFoundError: No module named 'flash_attn' ,说明你的GPU不支持FlashAttention(如RTX 3090及以下)。此时执行: pip install -e ".[webui]" --no-deps ,然后单独安装: pip install torch==2.3.1+cu121 torchvision==0.18.1+cu121 --index-url https://download.pytorch.org/whl/cu121 。跳过flash_attn即可,不影响核心功能。

第四步:验证环境(必做!)

python src/llamafactory/cli.py webui --port 7860

如果终端输出 Running on local URL: http://127.0.0.1:7860 ,且浏览器打开后能看到界面,说明环境成功。此时关闭(Ctrl+C),我们进入下一步。

3.2 数据准备:JSONL不是随便写个JSON就行,字段名决定一切

LlaMA-Factory WebUI的数据加载器,本质是一个 基于字段名的模板引擎 。它不关心你的数据长什么样,只关心你告诉它哪个字段是“用户输入”,哪个是“模型回答”。标准格式是JSONL(每行一个JSON对象),但字段名必须匹配其内置模板。常见错误是直接把ChatGLM的 {"query": "...", "response": "..."} 丢进去,结果训练时报 ValueError: Field 'prompt' not found in dataset

正确做法分三步:

1. 确认你要用的模型模板 打开WebUI,点左上角“模型”→“模型列表”,找到你的模型(如 Qwen/Qwen2-1.5B ),查看右侧“模板”列。常见模板有:

  • default : 通用模板,要求字段 prompt response
  • qwen2 : Qwen系列专用,要求 query response
  • llama3 : Llama-3专用,要求 messages (数组,含 role content

2. 按模板要求整理数据 假设你用Qwen2-1.5B,模板是 qwen2 ,你的原始数据是CSV:

customer_question,agent_answer
"我的订单还没发货","您好,已为您查询,订单预计明天发出。"
"商品有质量问题怎么办","请提供订单号和问题照片,我们将为您安排退货。"

用pandas转成符合 qwen2 模板的JSONL:

import pandas as pd
df = pd.read_csv("raw_data.csv")
# 重命名字段,严格匹配模板要求
df = df.rename(columns={"customer_question": "query", "agent_answer": "response"})
# 写入JSONL,确保每行一个JSON,无空格
df.to_json("data/my_data/train.jsonl", orient="records", lines=True, indent=None)

3. 数据集注册(关键!) LlaMA-Factory不会自动扫描 data/ 目录。你必须在WebUI中“数据集”→“新建数据集”,填写:

  • 数据集名称: my_customer_data
  • 数据集路径: data/my_customer_data (注意:是目录,不是文件!)
  • 格式: json
  • 阶段: sft (监督微调)

注意:路径必须是相对 LLaMA-Factory/ 目录的路径。如果你把数据放在 /home/user/my_data.jsonl ,必须先软链接: ln -s /home/user/my_data.jsonl data/my_customer_data/train.jsonl 。否则WebUI找不到。

3.3 WebUI核心参数详解:每个滑块背后都是血泪教训

打开WebUI,进入“训练”页面。这里不是让你乱调,而是理解每个参数的物理意义。我们以QLoRA微调Qwen2-1.5B为例:

模型设置区:

  • 模型名称 :填 Qwen/Qwen2-1.5B (Hugging Face ID)。 切勿填本地路径 ,除非你明确知道 --model_name_or_path 指向的是已下载的完整模型目录。
  • 量化位数 :选 4 (QLoRA)。这是平衡效果和显存的关键。实测:RTX 4090上, 4-bit 显存占14.2GB, 8-bit 占18.7GB, full (无量化)直接OOM。 4-bit 对Qwen2-1.5B的业务效果损失<1.2%(用BLEU和人工评测)。
  • 最大长度 :填 2048 。这是 model_max_length ,不是你数据的平均长度。设太小会截断长对话,设太大(如4096)会显著增加显存(因KV Cache大小与长度平方相关)。

微调方法区:

  • 微调方法 :选 lora 不要选 full ,那是给A100集群准备的。LoRA是唯一适合单卡的方案。
  • LoRA秩 :滑块拉到 64 。这是最关键的参数。 (rank)代表低秩矩阵的维度。 rank=64 意味着在原始权重矩阵W上,只学习一个 d x 64 64 x d 的小矩阵(d是隐藏层维度,Qwen2-1.5B是1536)。 rank=32 省显存但效果掉点; rank=128 效果略好但显存涨20%,不值得。
  • LoRA Alpha :自动变为 128 。公式是 alpha = rank * 2 ,这是LlaMA-Factory的默认缩放策略,经大量实验验证效果稳定。手动改它不如改 rank

训练设置区:

  • 每设备批次大小 :填 2 。这是 per_device_train_batch_size 。RTX 4090上, batch_size=2 对应总batch=2(单卡), loss 曲线最稳。 batch_size=4 会OOM; batch_size=1 则梯度噪声大,loss跳变剧烈。
  • 学习率 :填 2e-4 。这是QLoRA的标准起点。 1e-4 收敛慢; 3e-4 易发散。 切记:不要用 2e-5 ,那是Full FT的值,LoRA需要更高学习率来激活低秩空间。
  • 训练轮数 :填 3 。SFT通常3轮足够。第1轮学模式,第2轮学细节,第3轮收敛。超过5轮必过拟合(验证集loss开始上升)。

实操心得:第一次训练,务必勾选“启用验证数据集”。即使你只有训练数据,也抽10%出来作为验证集(WebUI有“分割数据集”功能)。因为 train_loss 可能一直降,但 eval_loss 在第2.5轮就开始升,这是过拟合的唯一可靠信号。靠肉眼盯train_loss,你会错过最佳stop point。

4. 实操过程与核心环节实现:从点击“训练”到拿到第一个可用模型

4.1 完整训练流程:每一步都在做什么?

现在,我们把前面所有准备串起来,走一遍真实训练。假设你已完成:

  • 环境安装验证通过
  • 数据集 my_customer_data 已注册成功
  • 所有参数按3.3节设置完毕

步骤1:启动WebUI并加载配置

cd LLaMA-Factory
python src/llamafactory/cli.py webui --port 7860

浏览器打开 http://127.0.0.1:7860 ,登录(默认无密码),进入“训练”页。

步骤2:配置并提交任务

  • 模型: Qwen/Qwen2-1.5B
  • 量化: 4
  • 方法: lora
  • 数据集: my_customer_data
  • 其他参数按3.3节设置
  • 点击“开始训练”

后台发生了什么?

  • WebUI生成 src/llamafactory/configs/train_lora_qwen2.yaml (临时配置)
  • 调用 llamafactory-cli train --config src/llamafactory/configs/train_lora_qwen2.yaml
  • train.py 启动,执行:
    1. load_model_and_tokenizer() :加载Qwen2-1.5B,应用4-bit量化,注入LoRA层
    2. load_dataset() :读取 data/my_customer_data/train.jsonl ,应用 Qwen2Template ,缓存为Arrow
    3. init_trainer() :构建 TrainingArguments ,设置 logging_steps=5 (每5步打一次log)
    4. trainer.train() :开始训练

步骤3:实时监控与关键节点识别 训练启动后,WebUI右下角会出现“训练日志”面板。不要只盯着loss数字,要关注这些关键信号:

  • 第0步(Step 0) :日志应出现 Using <class 'llamafactory.model.qwen2_model.Qwen2Model'> ,确认模型加载正确
  • 第1-5步 loss 应在 2.1~2.5 之间波动。如果 loss=nan ,立刻停!通常是学习率太高或数据有非法字符(如 \x00
  • 第100步左右 loss 应降到 1.8 以下。如果卡在 2.0 不动,检查数据格式——大概率 query 字段里混入了HTML标签,tokenizer无法处理
  • 第300步(约1/4 epoch) :日志出现 ***** Running training ***** Num examples = 120000 ,确认数据集行数正确
  • 第500步 :首次保存 checkpoint-500 ,路径为 outputs/qwen2_lora_my_customer_data/checkpoint-500

提示:WebUI的“日志”面板有时会卡住。此时直接看终端输出,或去 outputs/ 目录下用 tail -f checkpoint-500/loss.log 实时追踪。

4.2 检查点(Checkpoint)分析:如何确认模型真的学到了东西?

训练到 checkpoint-500 后,别急着用。先做三件事验证效果:

1. 快速推理测试(Terminal版)

# 在LLaMA-Factory根目录执行
python src/llamafactory/cli.py chat \
    --model_name_or_path outputs/qwen2_lora_my_customer_data/checkpoint-500 \
    --template qwen2 \
    --infer_backend vllm  # 或 hf(huggingface)

输入测试句:

<|im_start|>user
我的订单还没发货<|im_end|>
<|im_start|>assistant

观察输出。合格的checkpoint应生成类似 您好,已为您查询,订单预计明天发出。 的回复。如果输出 <|im_start|>assistant 后卡住,说明LoRA权重未正确加载(检查 adapter_config.json 是否存在)。

2. 损失曲线诊断 打开 outputs/qwen2_lora_my_customer_data/ ,找到 all_results.json ,用Python解析:

import json
with open("outputs/qwen2_lora_my_customer_data/all_results.json") as f:
    res = json.load(f)
print(f"Final train loss: {res['train_loss']}")
print(f"Best eval loss: {res['eval_loss']}")
  • train_loss < 1.5 eval_loss < 1.6 :健康
  • train_loss=0.8 eval_loss=2.1 :严重过拟合,需减少训练轮数或加dropout
  • train_loss eval_loss 都 > 2.0:数据质量差或学习率过高

3. LoRA权重有效性验证 进入 outputs/qwen2_lora_my_customer_data/checkpoint-500 目录,检查:

  • adapter_model.bin :LoRA权重文件,大小应在 120~150MB (rank=64时)
  • adapter_config.json :内容应包含 "r": 64, "lora_alpha": 128, "target_modules": ["q_proj", "v_proj"]
  • pytorch_model.bin 应该不存在! 如果存在,说明你误用了Full FT,整个checkpoint无效。

实操心得:我曾帮一个客户排查,他们训练了12小时, checkpoint-1000 adapter_model.bin 只有 2.3MB 。一查 adapter_config.json "r": 8 (秩=8)。他们以为“小一点省显存”,结果LoRA矩阵太小,根本学不到任何新知识。后来改成 r=64 ,3小时就达到同等效果。记住:LoRA不是越小越好, r=64 是Qwen2-1.5B在中文SFT上的黄金分割点。

4.3 模型合并与部署:让微调结果真正可用

WebUI训练出的 checkpoint-xxx 是“带LoRA适配器的基座模型”,不能直接扔给生产环境。必须合并(merge)才能获得独立模型。这是新手最容易忽略的致命步骤。

合并命令(必须在LLaMA-Factory根目录执行):

python src/llamafactory/cli.py export \
    --model_name_or_path outputs/qwen2_lora_my_customer_data/checkpoint-500 \
    --adapter_name_or_path outputs/qwen2_lora_my_customer_data/checkpoint-500 \
    --export_dir outputs/qwen2_lora_my_customer_data/merged \
    --export_size 2 \
    --export_device cpu

参数说明:

  • --model_name_or_path :基座模型路径(这里是checkpoint,它包含基座+LoRA)
  • --adapter_name_or_path :LoRA权重路径(同上)
  • --export_dir :合并后模型存放目录
  • --export_size 2 :分2个文件导出(防止单文件过大)
  • --export_device cpu 必须用CPU !GPU合并可能因显存不足失败

合并完成后, outputs/qwen2_lora_my_customer_data/merged/ 目录下会有:

  • config.json
  • pytorch_model-00001-of-00002.bin
  • pytorch_model-00002-of-00002.bin
  • tokenizer.model

这才是真正的、可部署的模型!你可以:

  • transformers.AutoModelForCausalLM.from_pretrained("outputs/.../merged") 直接加载
  • llamafactory-cli chat --model_name_or_path outputs/.../merged 进行推理
  • 打包进Docker,提供API服务

注意:合并后的模型大小≈基座模型(Qwen2-1.5B约3.2GB),不再是LoRA的150MB。这是正常现象——LoRA只是训练捷径,部署必须用完整权重。

5. 常见问题与排查技巧实录:那些文档里不会写的坑

5.1 “CUDA out of memory”:不是显存不够,是你没关对东西

这是最高频报错。但90%的情况,不是RTX 4090真不够,而是你没关掉其他进程。排查顺序必须严格:

第一顺位:杀Chrome/Edge浏览器

# Linux/Mac
pkill -f "chrome\|chromium\|edge"
# Windows(PowerShell)
Get-Process chrome,msedge | Stop-Process

原因:Chrome每个标签页默认占用1~2GB GPU显存(用于硬件加速)。你开5个标签页,显存就没了20%。这是最隐蔽的杀手。

第二顺位:检查WebUI自身显存 WebUI的Gradio界面本身会加载一个轻量模型做示例推理。在启动WebUI时加参数:

python src/llamafactory/cli.py webui --port 7860 --share False --no-gradio-queue

--no-gradio-queue 禁用Gradio的后台预热,可省1.2GB显存。

第三顺位:调整训练参数 如果以上都做了还OOM,按此顺序调参:

  1. per_device_train_batch_size 2 1
  2. max_length 2048 1024 (牺牲长文本能力)
  3. quantization_bit 4 8 (效果下降但显存减半)
  4. 终极方案 :改 src/llamafactory/train/trainer.py ,在 __init__ 里加:
    self.args.fp16_full_eval = True  # 强制评估时用fp16
    

5.2 “Field 'prompt' not found”:数据字段名战争

错误日志长这样:

ValueError: Field 'prompt' not found in dataset. Available fields: ['query', 'response']

这不是bug,是LlaMA-Factory在提醒你:你选的模型模板(如 default )要求 prompt 字段,但你的数据只有 query 。解决方案只有两个:

方案A(推荐):改数据字段名 用pandas重命名:

df = df.rename(columns={"query": "prompt", "response": "response"})

方案B:改模板 在WebUI“模型”页,找到你的模型,点击“编辑”,把“模板”从 default 改为 qwen2 。但注意:改模板后,所有历史训练都要重来,因为数据预处理逻辑变了。

实操心得:我们团队定了一条铁律——所有数据入库前,必须用 jq 校验字段:

head -n 1 data/my_data/train.jsonl | jq 'keys'
# 输出必须是["query","response"]或["prompt","response"],绝不允许出现["input","output"]

这条命令写进CI脚本,数据提交就自动检查,从源头杜绝字段战争。

5.3 “Loss is nan”:魔鬼在数据细节里

loss=nan 通常发生在训练刚开始(Step 0-10)。原因90%是数据含不可见字符。典型场景:

  • Excel导出CSV时,单元格里有 Alt+Enter 换行符( \n ),JSON序列化后变成 \n ,tokenizer无法处理
  • 爬虫抓取的网页数据含 &nbsp; (不间断空格),UTF-8编码为 \xc2\xa0 ,某些tokenizer会崩

快速清洗脚本:

import json
def clean_text(text):
    if not isinstance(text, str):
        return text
    # 移除不可见控制字符(除\n\t\r)
    import re
    text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]', '', text)
    # 替换不间断空格
    text = text.replace('\xa0', ' ')
    return text.strip()

# 清洗整个JSONL
with open("train.jsonl") as f, open("train_clean.jsonl", "w") as out:
    for line in f:
        obj = json.loads(line)
        obj["query"] = clean_text(obj.get("query", ""))
        obj["response"] = clean_text(obj.get("response", ""))
        out.write(json.dumps(obj, ensure_ascii=False) + "\n")

5.4 WebUI卡死/白屏:不是程序崩了,是端口被占了

现象:浏览器打开 http://127.0.0.1:7860 ,显示白屏,F12看Network全是pending。

原因:

  • 你之前启动过WebUI但没Ctrl+C,进程还在后台
  • 其他程序(如Jupyter Lab)占了7860端口

解决:

# 查找占用7860端口的进程
lsof -i :7860  # Mac/Linux
netstat -ano | findstr :7860  # Windows
# 杀掉它
kill -9 <PID>  # Mac/Linux
taskkill /PID <PID> /F  # Windows

预防: 每次启动WebUI,加 --server-port 7861 换端口:

python src/llamafactory/cli.py webui --port 7861

5.5 “No module named 'vllm'”:推理加速的甜蜜陷阱

当你想用vLLM加速推理时, pip install vllm 报错,常见于:

  • Ubuntu 22.04 + CUDA 12.1:vLLM 0.4.2要求CUDA 12.1.1,但系统是12.1.0
  • Windows:vLLM不支持Windows(官方明确声明)

绕过方案:

  • 改用 --infer_backend hf (Hugging Face原生推理),速度慢30%但100%兼容
  • 或升级CUDA: sudo apt install cuda-toolkit-12-1 (Ubuntu)

最后分享一个小技巧:训练时,把 --logging_steps 设为 1 ,虽然日志爆炸,但你能看到每一step的 grad_norm (梯度范数)。如果 grad_norm 突然飙升到 1000+ ,说明

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值