NLP——LLaMA-Factory使用笔记

本文主要介绍LLaMA-Factory项目训练和微调大模型的笔记


数据集准备

  • LLaMA-Factory 支持两种格式的文件,分别是 Alpaca 格式和 ShareGPT 格式

  • Alpaca示例(名称来源:alpaca是“羊驼”,llama是“大羊驼”)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [
    {
    "instruction": "人类指令(必填)",
    "input": "人类输入(选填)",
    "output": "模型回答(必填)",
    "system": "系统提示词(选填)",
    "history": [
    ["第一轮指令(选填)", "第一轮回答(选填)"],
    ["第二轮指令(选填)", "第二轮回答(选填)"]
    ]
    }
    ]
  • ShareGPT示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [
    {
    "id": "对话ID", // 可选
    "conversations": [
    {
    "from": "human",
    "value": "用户消息"
    },
    {
    "from": "gpt",
    "value": "助手回复"
    },
    // 后续交替对话...
    ]
    }
    ]

最佳实践:参照示例增加自定义数据集

  • 参照data/文件夹下的其他.json文件,准备自己的数据集,存储格式为json,命名为diy_train_data_name.json

  • data/dataset_info.json文件中增加一个dict对象,示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    "diy_train_data_name": {
    "file_name": "your_data_name.json",
    "file_sha1": "xxx", // 可选
    "columns": {
    "prompt": "prompt_key",
    "query": "input_key", // 可选
    "response": "output_key/response_key",
    "system": "system_key", // 可选
    "history": "history_key" // 可选
    }
    }

命令行微调

  • 修改指定文档中的 .yaml 文件
  • 按照 README.md 文档执行命令

网页版LLaMA微调简单流程

启动web_ui

  • 启动web_ui的命令
    1
    2
    unset http_proxy https_proxy all_proxy # 关闭代理
    python -m llmtuner.webui.interface

训练

  • base_path加载base模型到内存,变量命名为model
    • 如果要量化,记得配置量化选项,配置量化选项后可减少显存占用
  • 定义PEFT配置peft_config
    • 最常用的PEFT手段就是LoRA
  • 基于modelpeft_config,生成peft_model
  • 生成数据集,并指定数据集对peft_model进行微调训练
  • 训练完成后,保存模型参数到指定peft模型路径peft_path(这一步只会保存微调参数,不会保存base模型参数)

推理

  • base_path加载base模型到内存,变量命名为model
    • 这里要求与训练配置完全一致(包括量化选项等配置必须一致)
  • peft_path加载PEFT模型到内存
    • 这一步需要将modelpeft_path作为参数传入
  • 构造生成配置generation_config,配置可参考NLP——LLM推理时的生成方式
  • 调用model.generate()函数
    • 传入input信息和生成配置generation_config,得到Response

附录:记一个从ckpt加载训练的错误


附录:Qwen3 微调后不会输出停止 token

  • 相关问题链接:LLaMA-Factory/issues/589:基于预训练后的模型进行指令微调,预测时停不下来 #589

    Qwen-7B-Base 的分词器词表里没有 chatml 模板里的一些字符,所以会导致这种问题,因此应该避免使用 chatml 模板对 base 模型做微调。

  • 最终解法:LLaMA-Factory/issues/7943:Qwen3 not stopping generation after lora finetuning #7943

    Try setting the eos token in the tokenizer config to <|endoftext|> and using default template if you are fine-tuning base model using lora https://huggingface.co/Qwen/Qwen3-4B-Base/blob/main/tokenizer_config.json#L232

    • 理解:Qwen3-Base模型中没有 <|im_end|>,训练时应该使用 <|endoftext|>,但是Qwen3-Base模型的 tokenizer_config.json 中定义了 "eos_token":"<|im_end|>"(而default 模板在原始模型定义了 eos_token 时是不会修改原始模型的 eos_token 的),所以,需要手动改成 "eos_token":"<|endoftext|>"
      • 其他解法1:是修改 template 代码实现修改(比如基于 default 写一个新的模版,配置 replace_eos=True并使用 stop_words=["<|endoftext|>"],此时会使用 templatestop_words 的第一个值赋值上去,用于主动修改替换值,但是改模型更合适
      • 其他解法2:直接删除原始模型中的 eos_token 字段应该也可行,此时模版会自动修改为 <|endoftext|>(详情见 template.py 中的 fix_special_tokens 函数)
    • 问题:为什么无法学习<|im_end|>,使用 tokenizer 命名可以编码<|im_end|>啊!
  • 注:在使用 instruct 的 Qwen,模型时,直接使用 qwen 模板即可,不会出现上述问题

附录:Tokenizer的结束符号由什么确定?

  • 一方面,模型的 tokenizer_config.json 等文件会影响结束符号 eos_token_id,另一方面,针对不同的 template,Tokenizer 的结束符号还会被修改
    • 以 SFT 为例,该修改发生在 sft/workflow.pyget_template_and_fix_tokenizer 函数中,对于配置了 replace_eos=True 的模板,会使用 templatestop_words 的第一个值赋值上去

附录:Qwen3 聊天模板的使用

  • Qwen3-Base模型中无法识别 <|im_end|> token,如果需要使用模型自带的模板训练,需要将Qwen3-Base模型的 tokenizer_config.json 相关字段(chat_templateeos_token中的 <|im_end|> 替换为 <|endoftext|>
  • 经过上述修改以后,可以使用模型的聊天模板进行对话