hf-train-colab / hf_train.py
Dshane26's picture
Upload hf_train.py with huggingface_hub
35373ef verified
Raw
History Blame Contribute Delete
10.8 kB
"""
HuggingFace 模型微调训练脚本
============================
使用方法:
1. 打开 https://colab.research.google.com
2. Runtime -> Change runtime type -> T4 GPU
3. 新建一个 Cell,粘贴全部代码运行
4. 或保存为 .py 文件后 !python train.py 运行
支持场景:classification / sft / dpo
修改 SCENE 变量切换场景
"""
# ============================================================
# 第一步:安装依赖
# ============================================================
import subprocess, sys
def pip_install(packages):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q"] + packages.split())
# 基础依赖(必须)
pip_install("transformers datasets accelerate bitsandbytes sentencepiece scikit-learn")
# 场景依赖(按需取消注释)
# pip_install("trl peft") # SFT 和 DPO 需要
# pip_install("wandb") # 训练可视化(可选)
print("✅ 依赖安装完成")
# ============================================================
# 第二步:登录 HuggingFace
# ============================================================
HF_TOKEN = "YOUR_HF_TOKEN_HERE" # <-- 替换成你的 token
from huggingface_hub import login
login(token=HF_TOKEN)
print("✅ HuggingFace 登录成功")
# ============================================================
# 第三步:选择场景
# ============================================================
SCENE = "classification" # "classification" | "sft" | "dpo"
print(f"✅ 选择场景:{SCENE}")
# ============================================================
# 场景1:文本分类(金融情感分析)
# ============================================================
if SCENE == "classification":
import torch
import numpy as np
from transformers import (
AutoTokenizer, AutoModelForSequenceClassification,
TrainingArguments, Trainer
)
from datasets import load_dataset
from sklearn.metrics import accuracy_score, f1_score
# --- 配置 ---
MODEL_NAME = "bert-base-chinese" # 中文基础模型
NUM_LABELS = 3 # 3分类:正/负/中
OUTPUT_DIR = "./fin-sentiment-model"
HF_REPO = "Dshane26/fin-sentiment-cn" # 上传目标仓库
# --- 加载数据集 ---
# 使用 HF 上的金融情感数据集(英文)
# 中文数据请替换为自己的 CSV:
# dataset = load_dataset("csv", data_files="my_data.csv", split="train")
dataset = load_dataset("financial_phrasebank", "sentences_allagree", split="train")
print(f"数据集大小:{len(dataset)}")
print(f"字段:{dataset.column_names}")
print(f"样例:{dataset[0]}")
# --- 加载模型 ---
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME, num_labels=NUM_LABELS)
# --- 数据预处理 ---
def preprocess(examples):
return tokenizer(examples["sentence"], truncation=True, padding="max_length", max_length=128)
dataset = dataset.map(preprocess, batched=True)
dataset = dataset.rename_column("label", "labels")
dataset.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
split = dataset.train_test_split(test_size=0.15, seed=42)
train_ds, val_ds = split["train"], split["test"]
print(f"训练集:{len(train_ds)} | 验证集:{len(val_ds)}")
# --- 评估指标 ---
def compute_metrics(eval_pred):
logits, labels = eval_pred
preds = np.argmax(logits, axis=-1)
return {"accuracy": accuracy_score(labels, preds), "f1_macro": f1_score(labels, preds, average="macro")}
# --- 训练参数 ---
training_args = TrainingArguments(
output_dir=OUTPUT_DIR,
num_train_epochs=3,
per_device_train_batch_size=16,
per_device_eval_batch_size=32,
learning_rate=2e-5,
weight_decay=0.01,
warmup_ratio=0.1,
evaluation_strategy="epoch",
save_strategy="epoch",
load_best_model_at_end=True,
metric_for_best_model="f1_macro",
fp16=True,
report_to="none",
logging_steps=50,
push_to_hub=True,
hub_model_id=HF_REPO,
hub_strategy="end",
)
# --- 开始训练 ---
trainer = Trainer(
model=model, args=training_args,
train_dataset=train_ds, eval_dataset=val_ds,
compute_metrics=compute_metrics,
)
trainer.train()
print("\n✅ 训练完成!")
# --- 评估 ---
results = trainer.evaluate()
print("\n📊 最终评估结果:")
for k, v in results.items():
print(f" {k}: {v:.4f}")
# --- 推理测试 ---
label_map = {0: "负面 😞", 1: "中性 😐", 2: "正面 😊"}
test_texts = ["公司营收增长超预期,利润大幅提升", "业绩持续下滑,亏损扩大", "公司季度报告如预期发布"]
print("\n🧪 推理测试:")
for text in test_texts:
inputs = tokenizer(text, return_tensors="pt", truncation=True).to(model.device)
with torch.no_grad():
pred = torch.argmax(model(**inputs).logits, dim=-1).item()
print(f" 「{text}」→ {label_map[pred]}")
print(f"\n🎉 模型已上传到 https://huggingface.co/{HF_REPO}")
# ============================================================
# 场景2:指令微调 SFT
# ============================================================
elif SCENE == "sft":
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, BitsAndBytesConfig
from trl import SFTTrainer
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
BASE_MODEL = "Qwen/Qwen2-1.5B-Instruct"
OUTPUT_DIR = "./qwen-sft-model"
HF_REPO = "Dshane26/qwen-sft-finance"
# 4-bit 量化加载
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16, bnb_4bit_use_double_quant=True,
)
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
model = AutoModelForCausalLM.from_pretrained(
BASE_MODEL, quantization_config=bnb_config, device_map="auto", trust_remote_code=True
)
model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, LoraConfig(
r=16, lora_alpha=32,
target_modules=["q_proj","k_proj","v_proj","o_proj","gate_proj","up_proj","down_proj"],
lora_dropout=0.05, bias="none", task_type="CAUSAL_LM",
))
model.print_trainable_parameters()
# 加载数据
dataset = load_dataset("tatsu-lab/alpaca", split="train")
def format_alpaca(ex):
if ex["input"]:
text = f"### Instruction:\n{ex['instruction']}\n\n### Input:\n{ex['input']}\n\n### Response:\n{ex['output']}"
else:
text = f"### Instruction:\n{ex['instruction']}\n\n### Response:\n{ex['output']}"
return {"text": text}
dataset = dataset.map(format_alpaca)
print(f"数据集大小:{len(dataset)}")
training_args = TrainingArguments(
output_dir=OUTPUT_DIR, num_train_epochs=3,
per_device_train_batch_size=4, gradient_accumulation_steps=4,
learning_rate=2e-4, weight_decay=0.01, warmup_ratio=0.05,
lr_scheduler_type="cosine", logging_steps=100,
save_strategy="epoch", fp16=True, report_to="none",
push_to_hub=True, hub_model_id=HF_REPO, hub_strategy="end",
)
trainer = SFTTrainer(
model=model, args=training_args, train_dataset=dataset,
dataset_text_field="text", max_seq_length=512, tokenizer=tokenizer,
)
trainer.train()
print("\n✅ 训练完成!")
# 推理测试
prompt = "### Instruction:\n解释什么是市盈率(PE Ratio)\n\n### Response:\n"
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
with torch.no_grad():
outputs = model.generate(**inputs, max_new_tokens=256, temperature=0.7, do_sample=True)
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(f"\n🧪 推理测试:\n{result.split('### Response:')[-1].strip()}")
print(f"\n🎉 模型已上传到 https://huggingface.co/{HF_REPO}")
# ============================================================
# 场景3:DPO 对齐
# ============================================================
elif SCENE == "dpo":
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, BitsAndBytesConfig
from trl import DPOTrainer
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
BASE_MODEL = "Qwen/Qwen2-1.5B-Instruct"
OUTPUT_DIR = "./qwen-dpo-model"
HF_REPO = "Dshane26/qwen-dpo-finance"
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16, bnb_4bit_use_double_quant=True,
)
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(
BASE_MODEL, quantization_config=bnb_config, device_map="auto", trust_remote_code=True
)
model_ref = AutoModelForCausalLM.from_pretrained(
BASE_MODEL, quantization_config=bnb_config, device_map="auto", trust_remote_code=True
)
model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, 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",
))
dataset = load_dataset("tatsu-lab/alpaca", split="train")
print(f"数据集大小:{len(dataset)}")
training_args = TrainingArguments(
output_dir=OUTPUT_DIR, num_train_epochs=1,
per_device_train_batch_size=2, gradient_accumulation_steps=8,
learning_rate=5e-7, beta=0.1, logging_steps=50,
save_strategy="epoch", fp16=True, report_to="none",
push_to_hub=True, hub_model_id=HF_REPO, hub_strategy="end",
)
trainer = DPOTrainer(
model=model, ref_model=model_ref, args=training_args,
train_dataset=dataset, tokenizer=tokenizer, max_length=512, beta=0.1,
)
trainer.train()
print("\n✅ DPO 训练完成!")
print(f"\n🎉 模型已上传到 https://huggingface.co/{HF_REPO}")
else:
print(f"❌ 未知场景:{SCENE}。请选择 classification / sft / dpo")