前言

LLM训练三板斧,预训练,微调,RHLF。DPO属于是最后环节RHLF中的一个方法,关于RLHF主流方法有PPO,DPO,GROP。关于这三种介绍RLHF方法,我之前分享过对着三种方法的一些思考,有兴趣的同学可以看看。

因为DPO对硬件的需求最小,显存占用最低,所以我们先采用DPO进行训练。

硬件信息:

4070 12g*2 、64g内存、操作系统:Ubuntu24.04、模型:QWEN-3vl-2B(因为我这个模型是上个多模态任务sft过的,所以选择vl模型,没有图片输入需求的同学可以下载纯语言模型)

本篇教程仅关于DPO训练,请提前配置好环境和下载好LLamafactory(关于llamafactory环境配置其实也是一大头疼的点,注意如果想要使用分布式训练,llamafactory仅支持到deeospeed10.0-16.0,截止到2025年11月20日llamafactory还没有完成对deepspeed最新版本的适配

碎碎念:很多初学大模型的同学还是使用Windows系统进行训练,本人之前也是。但是由于Windows总是出现各种奇怪的报错和显存不稳定等情况,尤其是在多卡训练中,这种情况会更加明显。后来也尝试过wsl2其他替代方案,最后还是发现linux系统有着win无法替代的优势。所以还是建议如果真想长期学习LLM的同学,直接一步到位到linux系统,少走弯路 :)

llamafactory以下简称LF

STEP1 从hugging face下载我们需要的数据库

这里采用的是hugging face中的一个医疗DPO数据集

from datasets import load_dataset

# 加载数据集
ds = load_dataset("HANI-LAB/Med-REFL-DPO",'reasoning_enhancement')
print(ds['train'][:1])

这里看到数据是可以正常加载的

STEP2 对数据进行预处理

由于我们需要使用llamafactory的框架进行dpo训练,所以需要把源arrow格式的文件转为lf能识别的json格式。下面这是官方文档中的规范格式,我们编写一个python程序完成格式的对齐

[
  {
    "instruction": "人类指令(必填)",
    "input": "人类输入(选填)",
    "chosen": "优质回答(必填)",
    "rejected": "劣质回答(必填)"
  }
]
import json
from datasets import load_dataset
import os

def convert_arrow_to_json(dataset_path, output_json_path):
    """
    将 Arrow 格式的数据集转换为指定的 JSON 格式
    
    Args:
        dataset_path: Arrow 数据集的路径或 Hugging Face 数据集标识
        output_json_path: 输出 JSON 文件的路径
    """
    # 加载数据集
    # 如果是本地文件,可以使用 'load_from_disk'

    if os.path.exists(dataset_path):
        # 加载本地的 Arrow 数据集
        dataset = load_dataset('arrow', data_files=dataset_path)
    else:
        
        dataset = load_dataset(dataset_path, name='reasoning_enhancement')
    
    # 获取训练集(根据你的描述,数据在 train split 中)
    train_dataset = dataset['train']
    
    # 转换为所需的 JSON 格式
    output_data = []
    for item in train_dataset:
        # 确保所有必填字段都存在
        if 'instruction' in item and 'chosen' in item and 'rejected' in item:
            json_item = {
                "instruction": item['instruction'],
                "input": item.get('input', ''),  # input 是选填的,默认空字符串
                "chosen": item['chosen'],
                "rejected": item['rejected']
            }
            output_data.append(json_item)
    
    # 保存为 JSON 文件
    with open(output_json_path, 'w', encoding='utf-8') as f:
        json.dump(output_data, f, ensure_ascii=False, indent=2)
    
    print(f"转换完成!共处理了 {len(output_data)} 条数据")
    print(f"JSON 文件已保存到: {output_json_path}")

def main():
    # 本地 Arrow 文件路径
    arrow_file_path = "path/to/your/Reasoning Enhancement.arrow"
    
    # 输出 JSON 文件路径
    output_json_path = "med_refl_dpo.json"
    
    # 执行转换
    convert_arrow_to_json(arrow_file_path, output_json_path)


if __name__ == "__main__":
    main()

完成数据集的标准化后,我们将获得的json文件复制到lf的data目录下。

之后我们需要修改 LLaMaFactory data目录下的dataset_info.json,增加自定义数据集:(官网也给出了添加数据集的标准格式)

"数据集名称": {
  "file_name": "data.json",
  "ranking": true,
  "columns": {
    "prompt": "instruction",
    "query": "input",
    "chosen": "chosen",
    "rejected": "rejected"
  }
}
"MED_DPO": 
{
  "file_name": "/home/zadyd/桌面/xza/LLaMA-Factory/data/med_dpo.json",
  "ranking": true,
  "columns": {
    "prompt": "instruction",
    "query": "input",
    "chosen": "chosen",
    "rejected": "rejected"
  }
},

STEP3 启动LF,选择合适的参数

在lm文件夹下启动终端,输入llamafactory-cli webui启动我们的可视化ui

如果是windows系统,则打开终端cd到lf目录

在网页端设置我们需要的参数,一般像我这样设置就可以

因为我是多卡训练,所以选择了 deepspeed,单卡训练的同学不需要勾选这个选项,本次训练需要 24g 左右的显存,这个显存大小有点尴尬,可以通过开启量化或者减少序列长度节约显存

大概需要 12 个小时,这一步很容易遇到环境不兼容的问题,需要耐心调整,不要心急

STEP4 合并模型

训练完成之后在 export 模块,选择训练好的文件位置,和原始文件进行合并

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐