guanghulab/scripts/distill/finetune_shuangyan_v2.py
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

90 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
小霜砚LoRA微调 v2 — 用sft_v2.jsonl (1868条霜砚对话)
基座1.5B蒸馏模板 (Track1)
"""
import os, json, torch
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.environ['TOKENIZERS_PARALLELISM'] = 'false'
BASE = '/root/autodl-tmp/output/qwen25-15b-shuangyan-distill/final'
OUT = '/root/autodl-tmp/output/shuangyan-v2'
DATA = '/root/autodl-tmp/data/sft_v2.jsonl'
os.makedirs(OUT, exist_ok=True)
print('[1/4] 加载语料...', flush=True)
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer
from peft import LoraConfig, get_peft_model
with open(DATA) as f:
raw = [json.loads(l) for l in f]
# 去掉system message (cc-002)
data = []
for d in raw:
msgs = [m for m in d['messages'] if m['role'] != 'system']
if len(msgs) >= 2:
data.append({'messages': msgs})
print(f' 加载 {len(data)} 条对话', flush=True)
print('[2/4] 加载模型...', flush=True)
tokenizer = AutoTokenizer.from_pretrained(BASE, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(
BASE, trust_remote_code=True, torch_dtype=torch.bfloat16,
attn_implementation='sdpa').cuda()
model.config.use_cache = False
lora = LoraConfig(r=16, lora_alpha=32,
target_modules=['q_proj','k_proj','v_proj','o_proj'],
lora_dropout=0.05, bias='none', task_type='CAUSAL_LM')
model = get_peft_model(model, lora)
model.print_trainable_parameters()
print('[3/4] Tokenize...', flush=True)
MAX_LEN = 2048
processed = []
for d in data:
ii, ll = [], []
for m in d['messages']:
c = m['content']
if not c.strip(): continue
txt = '<|im_start|>' + m['role'] + '\n' + c + '<|im_end|>\n'
tk = tokenizer.encode(txt, add_special_tokens=False)
ii.extend(tk)
ll.extend(tk if m['role'] == 'assistant' else [-100]*len(tk))
if len(ii) > MAX_LEN:
ii, ll = ii[:MAX_LEN], ll[:MAX_LEN]
if len(ii) > 10:
processed.append({'input_ids': ii, 'labels': ll, 'attention_mask': [1]*len(ii)})
print(f' {len(processed)} 条训练数据', flush=True)
ds = Dataset.from_list(processed)
def collate(features):
ml = max(len(f['input_ids']) for f in features)
batch = {}
for k in ['input_ids','labels','attention_mask']:
pad = tokenizer.pad_token_id if k != 'labels' else -100
batch[k] = torch.tensor([f[k] + [pad]*(ml-len(f[k])) for f in features])
return batch
args = TrainingArguments(
output_dir=OUT, num_train_epochs=5,
per_device_train_batch_size=2, gradient_accumulation_steps=4,
learning_rate=2e-4, warmup_ratio=0.05, lr_scheduler_type='cosine',
bf16=True, logging_steps=10, save_strategy='epoch', save_total_limit=2,
remove_unused_columns=False, report_to='none',
gradient_checkpointing=True, optim='adamw_torch',
)
print('[4/4] 开始微调!', flush=True)
trainer = Trainer(model=model, args=args, train_dataset=ds, data_collator=collate)
trainer.train()
fnl = os.path.join(OUT, 'final')
model.save_pretrained(fnl)
tokenizer.save_pretrained(fnl)
print(f'✅ 小霜砚微调完成!{fnl}', flush=True)