月度归档:2025年04月

MLX 的CoT 训练 LORA SFT 微调

GIT上有训练例子:https://github.com/jbarnes850/deepseek-r1-finetune

训练文件:https://hf-mirror.com/datasets/FreedomIntelligence/medical-o1-reasoning-SFT

原始文件格式:
{ "Question": "患者的具体医疗问题描述", "Complex_CoT": "详细的逐步推理过程", "Response": "最终答案" }

处理后的格式:

Please reason step by step:

Question: {样本的Question字段}

Let's solve this step by step:
{样本的Complex_CoT字段}

Final Answer: {样本的Response字段}

下面例子:

{
  "Question": "A 45-year-old patient presents with sudden onset chest pain, shortness of breath, and anxiety. The pain is described as sharp and worsens with deep breathing. What is the most likely diagnosis and what immediate tests should be ordered?",
  "Complex_CoT": "The patient's symptoms suggest possible acute coronary syndrome, pulmonary embolism, or pneumothorax. Given the sharp chest pain worsened by deep breathing, pulmonary embolism is a strong consideration. Immediate tests should include ECG, troponin, D-dimer, and chest X-ray.",
  "Response": "The most likely diagnosis is pulmonary embolism. Immediate tests should include ECG, troponin, D-dimer, and chest X-ray."
}

#处理后
Please reason step by step:

Question: A 45-year-old patient presents with sudden onset chest pain, shortness of breath, and anxiety. The pain is described as sharp and worsens with deep breathing. What is the most likely diagnosis and what immediate tests should be ordered?

Let's solve this step by step:
The patient's symptoms suggest possible acute coronary syndrome, pulmonary embolism, or pneumothorax. Given the sharp chest pain worsened by deep breathing, pulmonary embolism is a strong consideration. Immediate tests should include ECG, troponin, D-dimer, and chest X-ray.

Final Answer: The most likely diagnosis is pulmonary embolism. Immediate tests should include ECG, troponin, D-dimer, and chest X-ray.

处理后的数据是一个 Hugging Face Dataset 对象,其内部结构如下

如果要导出 则是TEXT的LORA 的JSONL

例如

{
"text": "Please reason step by step:\n\nQuestion: {Question}\n\nLet's solve this step by step:\n{Complex_CoT}\n\nFinal Answer: {Response}"
}

一行一行的TEXT文本

相关信息 https://el.psy.congroo.com/wp-admin/post.php?post=983 MLX数据格式

关于将上面的SFT信息转为JSONL的代码 ,未测试。

def prepare_dataset(tokenizer):
    """Prepare the medical reasoning dataset and export to JSONL"""
    # Load raw dataset
    dataset = load_dataset("FreedomIntelligence/medical-o1-reasoning-SFT", "en")
    
    # Split dataset (5% for training, 1% for testing)
    dataset = dataset["train"].train_test_split(
        train_size=0.05, 
        test_size=0.01, 
        seed=42
    )

    # Define formatting function
    def format_instruction(sample):
        return f"""Please reason step by step:

Question: {sample['Question']}

Let's solve this step by step:
{sample['Complex_CoT']}

Final Answer: {sample['Response']}"""

    # Create formatted text datasets
    text_train = dataset["train"].map(
        lambda x: {"text": format_instruction(x)},
        remove_columns=dataset["train"].column_names,
        num_proc=os.cpu_count()
    )
    
    text_test = dataset["test"].map(
        lambda x: {"text": format_instruction(x)},
        remove_columns=dataset["test"].column_names,
        num_proc=os.cpu_count()
    )

    # Export to JSONL (关键新增代码)
    text_train.to_json(
        "medical_train.jsonl",
        orient="records",
        lines=True,
        force_ascii=False  # 保留非ASCII字符(如中文)
    )
    
    text_test.to_json(
        "medical_test.jsonl",
        orient="records",
        lines=True,
        force_ascii=False
    )

    # Tokenization (保留原有流程)
    train_dataset = text_train.map(
        lambda x: tokenizer(
            x["text"],
            truncation=True,
            padding="max_length",
            max_length=1024,
            return_tensors=None,
        ),
        remove_columns=["text"],
        num_proc=os.cpu_count()
    )

    print("\nJSONL 文件已生成:")
    print(f"- medical_train.jsonl ({len(text_train)} 个样本)")
    print(f"- medical_test.jsonl ({len(text_test)} 个样本)")
    
    return train_dataset

MLX CLI训练命令 使用SFT 加入监督函数

mlx-cli train \
    --stage sft \                  # 指定微调阶段为SFT(监督微调)
    --do_train \                   # 表示进行训练
    --model_name_or_path /path/to/pretrained/model \  # 预训练模型的路径
    --dataset your_dataset_name \  # SFT数据集的名称或路径
    --finetuning_type lora \       # 使用LoRA微调方法
    --output_dir ./output \        # 输出目录
    --learning_rate 5e-5 \         # 学习率
    --num_train_epochs 3 \         # 训练轮数
    --per_device_train_batch_size 8 \  # 每个设备的训练批次大小
    --loss_function cross_entropy  # 使用交叉熵损失函数

在这个命令中,--loss_function 参数用于指定监督函数,确保训练过程是有监督的

之前的MLX的LORA快速微调

直接使用SFT数据也可以实现LORA微调 但是没有监督函数。

mlx_lm.lora --model ../../qwen2.5-0.5B --train --data ./data

OLLAMA支持的GPU

Compute CapabilityFamilyCards
9.0NVIDIAH100
8.9GeForce RTX 40xxRTX 4090 RTX 4080 SUPER RTX 4080 RTX 4070 Ti SUPER RTX 4070 Ti RTX 4070 SUPER RTX 4070 RTX 4060 Ti RTX 4060
NVIDIA ProfessionalL4 L40 RTX 6000
8.6GeForce RTX 30xxRTX 3090 Ti RTX 3090 RTX 3080 Ti RTX 3080 RTX 3070 Ti RTX 3070 RTX 3060 Ti RTX 3060 RTX 3050 Ti RTX 3050
NVIDIA ProfessionalA40 RTX A6000 RTX A5000 RTX A4000 RTX A3000 RTX A2000 A10 A16 A2
8.0NVIDIAA100 A30
7.5GeForce GTX/RTXGTX 1650 Ti TITAN RTX RTX 2080 Ti RTX 2080 RTX 2070 RTX 2060
NVIDIA ProfessionalT4 RTX 5000 RTX 4000 RTX 3000 T2000 T1200 T1000 T600 T500
QuadroRTX 8000 RTX 6000 RTX 5000 RTX 4000
7.0NVIDIATITAN V V100 Quadro GV100
6.1NVIDIA TITANTITAN Xp TITAN X
GeForce GTXGTX 1080 Ti GTX 1080 GTX 1070 Ti GTX 1070 GTX 1060 GTX 1050 Ti GTX 1050
QuadroP6000 P5200 P4200 P3200 P5000 P4000 P3000 P2200 P2000 P1000 P620 P600 P500 P520
TeslaP40 P4
6.0NVIDIATesla P100 Quadro GP100
5.2GeForce GTXGTX TITAN X GTX 980 Ti GTX 980 GTX 970 GTX 960 GTX 950
QuadroM6000 24GB M6000 M5000 M5500M M4000 M2200 M2000 M620
TeslaM60 M40
5.0GeForce GTXGTX 750 Ti GTX 750 NVS 810
QuadroK2200 K1200 K620 M1200 M520 M5000M M4000M M3000M M2000M M1000M K620M M600M M500M

LORA 微调 推理模型数据集合CoT 分布推理

示例1:

[
  {
    "instruction": "解决数学应用题",
    "input": "小明买了3支铅笔,每支2元;又买了5本笔记本,每本比铅笔贵4元。总花费多少?",
    "chain_of_thought": [
      "铅笔单价:2元/支 → 3支总价:3×2=6元",
      "笔记本单价:2+4=6元/本 → 5本总价:5×6=30元",
      "合计花费:6+30=36元"
    ],
    "output": "总花费为36元"
  }
]

示例2

[
  {
    "instruction": "分析医学问题",
    "input": "一名61岁的女性长期在咳嗽或打喷嚏等活动中不自觉地漏尿,但夜间没有漏尿,她接受了妇科检查和Q-tip测试。根据这些发现,膀胱测压最有可能揭示她的残余量和逼尿肌收缩情况?",
    "chain_of_thought": [
      "患者症状提示可能存在压力性尿失禁",
      "Q-tip测试用于评估尿道括约肌功能",
      "膀胱测压可以评估膀胱残余量和逼尿肌收缩力",
      "结合症状和检查结果,最可能的膀胱测压结果是残余量增加,逼尿肌收缩力减弱"
    ],
    "output": "膀胱测压最可能显示残余量增加,逼尿肌收缩力减弱"
  }
]

解析 JSON格式

instruction 指令 争对问题的信息

input 描述问题

chain_of_thought 思考列表,按照列表信息 一步 为一个值

output 输出结果

你可以通过在你的环境中使用 ollama 或任何其他部署框架部署 deepseek-r1 来生成自定义域相关数据集。但是,对于本教程,我们将使用 Magpie-Reasoning-V2 数据集,其中包含 DeepSeek-R1 生成的 250K 思路链 (CoT) 推理样本,这些示例涵盖了数学推理、编码和一般问题解决等各种任务。

http://www.hubwiz.com/blog/distill-deepseek-r1-into-your-model/

原文 http://www.hubwiz.com/blog/distill-deepseek-r1-into-your-model/

蒸馏数据集

蒸馏类型

有几种方法可以模拟蒸馏,每种方法都有自己的优点:

  1. 数据蒸馏
  • 在数据蒸馏中,教师模型生成合成数据或伪标签,然后用于训练学生模型。
  • 这种方法可以应用于广泛的任务,甚至是那些逻辑信息较少的任务(例如,开放式推理任务)。
  • Logits蒸馏
  • Logits 是应用 softmax 函数之前神经网络的原始输出分数。
  • 在logits 蒸馏中,学生模型被训练成匹配老师的logits,而不仅仅是最终的预测。
  • 这种方法保留了更多关于教师信心水平和决策过程的信息。
  • 特征蒸馏
  • 特征蒸馏涉及到将知识从教师模型的中间层传递给学生。
  • 通过对齐两个模型的隐表征,学生可以学习到更丰富、更抽象的特征。
{
 "instruction": "Solve for x: 2x + 5 = 15",
 "response": "<think>First, subtract 5 from both sides: 2x = 10. Then, divide by 2: x = 5.</think>"
}
from datasets import load_dataset

# Load the dataset
dataset = load_dataset("Magpie-Align/Magpie-Reasoning-V2-250K-CoT-Deepseek-R1-Llama-70B", token="YOUR_HF_TOKEN")
dataset = dataset["train"]

# Format the dataset
def format_instruction(example):
 return {
 "text": (
 "<|user|>\n"
 f"{example['instruction']}\n"
 "<|end|>\n"
 "<|assistant|>\n"
 f"{example['response']}\n"
 "<|end|>"
        )
    }

formatted_dataset = dataset.map(format_instruction, batched=False, remove_columns=subset_dataset.column_names)
formatted_dataset = formatted_dataset.train_test_split(test_size=0.1)  # 90-10 train-test split