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
两个包里。我们来拆解一次点击“开始训练”后的完整链路:
-
前端触发
:WebUI通过WebSocket发送JSON指令:
{"task": "train", "config": {"model_name": "Qwen/Qwen2-1.5B", "dataset": "my_customer_data", "method": "lora", "lora_rank": 64}} -
后端路由
:
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 -
数据准备
:
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),后续训练直接内存映射,避免重复解析
-
模型加载
:
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等参数动态构建
-
-
训练启动
:最终调用
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启动,执行:-
load_model_and_tokenizer():加载Qwen2-1.5B,应用4-bit量化,注入LoRA层 -
load_dataset():读取data/my_customer_data/train.jsonl,应用Qwen2Template,缓存为Arrow -
init_trainer():构建TrainingArguments,设置logging_steps=5(每5步打一次log) -
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,按此顺序调参:
-
per_device_train_batch_size从2→1 -
max_length从2048→1024(牺牲长文本能力) -
quantization_bit从4→8(效果下降但显存减半) -
终极方案
:改
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无法处理 -
爬虫抓取的网页数据含
(不间断空格),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+,说明

1万+

被折叠的 条评论
为什么被折叠?



