Java后端程序员收藏:大模型应用开发,你的“第二条曲线”已上线!
2026/7/30 4:29:40
SOTA 模型 = 超大算力 + 超大高质量数据 + 超完整训练流程(预训练 → SFT → 对齐)
下面是标准 SOTA 大模型训练全流程(GPT、Llama 3、Qwen、Claude 全都这套)。
目标:让模型学会语言规律、世界知识、逻辑、语法。
没有好的预训练,后面怎么微调都不可能 SOTA。
如果要做垂直领域 SOTA(医疗、法律、代码):
你前面问的 SFT,就是这一步。
把 “只会补全句子” 的模型 → 变成能听懂指令、回答问题、对话、写作的模型。
plaintext
指令:xxx 回答:yyySFT 决定模型会不会按要求做事。
这是普通模型 vs SOTA 模型最大差距。
让模型:
直接用偏好数据对(好回答 vs 坏回答)训练,不需要 RM、不需要 PPO。
DPO 是目前开源 SOTA 标配。
对齐做完,模型才真正达到可用、好用、顶尖。
plaintext
1. 数据清洗、去重、过滤、分类、打分 2. 预训练(基座模型) 3. SFT 监督微调(指令遵循) 4. 人类偏好数据构建 5. DPO / RLHF 对齐(最终 SOTA 能力) 6. 评估(MMLU、GSM8K、CEval、AGIEval…) 7. 迭代多轮 SFT + DPO(越迭代越强)SOTA 模型的核心不是架构,是:
垃圾数据 → 垃圾模型
SOTA 基座模型必须:
个人 / 小公司基本做不了基座 SOTA。
这是普通人最能参与的 SOTA 路线:
你不可能从头训基座(太贵),但可以:
plaintext
开源基座模型(Llama 3 / Qwen 2 / DeepSeek) ↓ 高质量 SFT(指令数据) ↓ 高质量 DPO(偏好数据) ↓ 多轮迭代 SFT + DPO ↓ 得到 SOTA 级开源模型这就是目前所有开源 SOTA 模型的训练方式。
SOTA 模型 = 超强预训练基座 + 高质量 SFT + 高质量对齐(DPO/RLHF)
bash
运行
pip install torch==2.1.0 transformers==4.38.2 datasets==2.18.0 peft==0.10.0 accelerate==0.27.2 bitsandbytes==0.43.0 trl==0.7.10 scikit-learn{"instruction": "指令", "output": "正确回答"}{"prompt": "指令", "chosen": "优选回答", "rejected": "次优回答"}python
运行
import os import torch import json from datasets import load_dataset, Dataset from transformers import ( AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForLanguageModeling, BitsAndBytesConfig ) from peft import LoraConfig, get_peft_model, PeftModel from trl import DPOTrainer, DPOConfig # ===================== 全局配置(根据你的环境修改) ===================== MODEL_NAME = "meta-llama/Meta-Llama-3-8B-Instruct" # 替换为你的模型路径 SFT_DATA_PATH = "./sft_data.jsonl" # SFT数据集路径 DPO_DATA_PATH = "./dpo_data.jsonl" # DPO数据集路径 OUTPUT_DIR = "./sft_dpo_output" # 输出目录 DEVICE_MAP = "auto" MAX_SEQ_LEN = 1024 BATCH_SIZE = 2 # 单卡16G设2,32G设4 LEARNING_RATE_SFT = 2e-4 # SFT学习率 LEARNING_RATE_DPO = 5e-6 # DPO学习率(远低于SFT) # ===================== 1. 工具函数(数据处理) ===================== def load_jsonl_data(path): """加载JSONL格式数据""" data = [] with open(path, "r", encoding="utf-8") as f: for line in f: data.append(json.loads(line.strip())) return Dataset.from_list(data) def format_sft_example(example): """格式化SFT数据(适配Llama 3指令格式)""" prompt = f"<|start_header_id|>user<|end_header_id|>\n{example['instruction']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n{example['output']}<|eot_id|>" return {"text": prompt} def format_dpo_example(example): """格式化DPO数据""" return { "prompt": f"<|start_header_id|>user<|end_header_id|>\n{example['prompt']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n", "chosen": example['chosen'] + "<|eot_id|>", "rejected": example['rejected'] + "<|eot_id|>" } # ===================== 2. 加载模型和Tokenizer ===================== def load_model_and_tokenizer(): """加载量化模型+Tokenizer""" # 4bit量化配置(省显存) bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) # 加载Tokenizer tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME) tokenizer.pad_token = tokenizer.eos_token tokenizer.padding_side = "right" # 避免训练警告 # 加载模型 model = AutoModelForCausalLM.from_pretrained( MODEL_NAME, quantization_config=bnb_config, device_map=DEVICE_MAP, torch_dtype=torch.bfloat16, trust_remote_code=True ) model.config.use_cache = False # 训练时关闭缓存 return model, tokenizer # ===================== 3. LoRA配置(SFT和DPO共用) ===================== def get_lora_config(): return LoraConfig( r=16, # LoRA秩(7B/8B模型推荐16) lora_alpha=64, # 缩放因子(r*4) target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], # Llama 3目标模块 lora_dropout=0.05, bias="none", task_type="CAUSAL_LM" ) # ===================== 4. 第一步:SFT监督微调 ===================== def run_sft(model, tokenizer): print("===== 开始SFT训练 =====") # 加载并格式化SFT数据 sft_dataset = load_jsonl_data(SFT_DATA_PATH) sft_dataset = sft_dataset.map(format_sft_example) # 编码数据 def tokenize_sft_function(examples): return tokenizer( examples["text"], truncation=True, max_length=MAX_SEQ_LEN, padding="max_length" ) tokenized_sft = sft_dataset.map(tokenize_sft_function, batched=True) tokenized_sft = tokenized_sft.train_test_split(test_size=0.1) # 划分验证集 # 挂载LoRA model = get_peft_model(model, get_lora_config()) model.print_trainable_parameters() # 打印训练参数占比 # SFT训练参数 sft_args = TrainingArguments( output_dir=os.path.join(OUTPUT_DIR, "sft"), per_device_train_batch_size=BATCH_SIZE, per_device_eval_batch_size=BATCH_SIZE, learning_rate=LEARNING_RATE_SFT, num_train_epochs=3, logging_steps=10, evaluation_strategy="epoch", save_strategy="epoch", fp16=True, gradient_accumulation_steps=4, lr_scheduler_type="cosine", warmup_ratio=0.1, weight_decay=0.01, report_to="none" ) # 数据整理器 data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False) # 启动SFT训练 trainer = Trainer( model=model, args=sft_args, train_dataset=tokenized_sft["train"], eval_dataset=tokenized_sft["test"], data_collator=data_collator ) trainer.train() # 保存SFT后的LoRA权重 sft_lora_path = os.path.join(OUTPUT_DIR, "sft_lora_final") model.save_pretrained(sft_lora_path) tokenizer.save_pretrained(sft_lora_path) return sft_lora_path # ===================== 5. 第二步:DPO偏好优化 ===================== def run_dpo(base_model, tokenizer, sft_lora_path): print("\n===== 开始DPO训练 =====") # 加载SFT后的LoRA模型 model = PeftModel.from_pretrained(base_model, sft_lora_path) model = model.merge_and_unload() # 合并LoRA权重(DPO更稳定) model.config.use_cache = False # 加载并格式化DPO数据 dpo_dataset = load_jsonl_data(DPO_DATA_PATH) dpo_dataset = dpo_dataset.map(format_dpo_example) dpo_dataset = dpo_dataset.train_test_split(test_size=0.1) # DPO训练配置 dpo_args = DPOConfig( output_dir=os.path.join(OUTPUT_DIR, "dpo"), per_device_train_batch_size=BATCH_SIZE, per_device_eval_batch_size=BATCH_SIZE, learning_rate=LEARNING_RATE_DPO, num_train_epochs=2, # DPO训练轮数少(避免过拟合) logging_steps=10, evaluation_strategy="epoch", save_strategy="epoch", fp16=True, gradient_accumulation_steps=4, lr_scheduler_type="cosine", warmup_ratio=0.1, report_to="none", beta=0.1, # DPO核心参数(平衡偏好强度,默认0.1即可) max_prompt_length=MAX_SEQ_LEN//2, # prompt最大长度 max_length=MAX_SEQ_LEN # 总长度 ) # 启动DPO训练 dpo_trainer = DPOTrainer( model=model, args=dpo_args, train_dataset=dpo_dataset["train"], eval_dataset=dpo_dataset["test"], tokenizer=tokenizer, peft_config=get_lora_config() # DPO继续用LoRA ) dpo_trainer.train() # 保存最终DPO权重 dpo_lora_path = os.path.join(OUTPUT_DIR, "dpo_lora_final") dpo_trainer.model.save_pretrained(dpo_lora_path) tokenizer.save_pretrained(dpo_lora_path) print(f"\n训练完成!最终权重保存在:{dpo_lora_path}") # ===================== 主函数(执行全流程) ===================== if __name__ == "__main__": # 1. 加载基础模型 base_model, tokenizer = load_model_and_tokenizer() # 2. 执行SFT sft_lora_path = run_sft(base_model, tokenizer) # 3. 重新加载基础模型(避免SFT的LoRA影响) base_model, tokenizer = load_model_and_tokenizer() # 4. 执行DPO run_dpo(base_model, tokenizer, sft_lora_path)json
{"instruction": "解释什么是SOTA模型", "output": "SOTA模型是State-of-the-Art的缩写,指当前领域内效果最好、指标最高的模型。"} {"instruction": "用Python写一个快速排序", "output": "def quick_sort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[len(arr)//2]\n left = [x for x in arr if x < pivot]\n middle = [x for x in arr if x == pivot]\n right = [x for x in arr if x > pivot]\n return quick_sort(left) + middle + quick_sort(right)"}json
{"prompt": "解释什么是SOTA模型", "chosen": "SOTA模型是State-of-the-Art的简称,代表当前技术领域中性能最优、指标最高的模型,比如GPT-4、Llama 3都属于SOTA级别。", "rejected": "SOTA模型就是一个模型,没什么特别的。"} {"prompt": "用Python写一个快速排序", "chosen": "def quick_sort(arr):\n if len(arr) <= 1:\n return arr\n pivot = arr[len(arr)//2]\n left = [x for x in arr if x < pivot]\n middle = [x for x in arr if x == pivot]\n right = [x for x in arr if x > pivot]\n return quick_sort(left) + middle + quick_sort(right)\n# 测试\nprint(quick_sort([3,1,4,1,5,9]))", "rejected": "快速排序很难,我不会写。"}表格
| 阶段 | 参数 | 作用 | 推荐值(7B/8B 模型) |
|---|---|---|---|
| SFT | learning_rate | 学习率 | 2e-4 ~ 5e-4 |
| SFT | num_train_epochs | 训练轮数 | 3 ~ 5 |
| DPO | learning_rate | 学习率 | 5e-6 ~ 1e-5(远低于 SFT) |
| DPO | num_train_epochs | 训练轮数 | 1 ~ 2(多了易过拟合) |
| DPO | beta | 偏好强度 | 0.1(默认值,不用改) |
| LoRA | r | 低秩矩阵秩 | 16(8B 模型)/ 32(70B 模型) |
python
运行
from transformers import pipeline from peft import PeftModel from transformers import AutoModelForCausalLM, AutoTokenizer # 加载基础模型 model = AutoModelForCausalLM.from_pretrained( "meta-llama/Meta-Llama-3-8B-Instruct", device_map="auto", torch_dtype=torch.bfloat16 ) # 加载DPO后的LoRA权重 model = PeftModel.from_pretrained(model, "./sft_dpo_output/dpo_lora_final") # 加载Tokenizer tokenizer = AutoTokenizer.from_pretrained("meta-llama/Meta-Llama-3-8B-Instruct") tokenizer.pad_token = tokenizer.eos_token # 推理 generator = pipeline( "text-generation", model=model, tokenizer=tokenizer, max_new_tokens=512 ) prompt = "<|start_header_id|>user<|end_header_id|>\n解释什么是SOTA模型<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n" output = generator(prompt) print(output[0]["generated_text"])chosen和rejected必须是 “同 prompt 下的好坏对比”,不能无关。