refactor(project): 重构项目文件组织结构
- 修改模型管理和训练页面的导入路径 - 更新 main.py 中的导入模块 - 调整 tools 包的内容,移除 model 模块 - 新建 train 包,包含 model 模块 - 优化 __init__.py 文件,简化导入语句
This commit is contained in:
1
train/__init__.py
Normal file
1
train/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .model import *
|
134
train/model.py
Normal file
134
train/model.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import os
|
||||
from datasets import Dataset as HFDataset
|
||||
from unsloth import FastLanguageModel
|
||||
from trl import SFTTrainer # 用于监督微调的训练器
|
||||
from transformers import TrainingArguments,DataCollatorForSeq2Seq # 用于配置训练参数
|
||||
from unsloth import is_bfloat16_supported # 检查是否支持bfloat16精度训练
|
||||
from unsloth.chat_templates import get_chat_template, train_on_responses_only
|
||||
def get_model_name(model):
|
||||
return os.path.basename(model.name_or_path)
|
||||
def formatting_prompts(examples,tokenizer):
|
||||
"""格式化对话数据的函数
|
||||
Args:
|
||||
examples: 包含对话列表的字典
|
||||
Returns:
|
||||
包含格式化文本的字典
|
||||
"""
|
||||
questions = examples["question"]
|
||||
answer = examples["answer"]
|
||||
|
||||
convos = [
|
||||
[{"role": "user", "content": q}, {"role": "assistant", "content": r}]
|
||||
for q, r in zip(questions, answer)
|
||||
]
|
||||
|
||||
# 使用tokenizer.apply_chat_template格式化对话
|
||||
texts = [
|
||||
tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False)
|
||||
for convo in convos
|
||||
]
|
||||
|
||||
return {"text": texts}
|
||||
|
||||
|
||||
def train_model(
|
||||
model,
|
||||
tokenizer,
|
||||
dataset: list,
|
||||
train_dir: str,
|
||||
learning_rate: float,
|
||||
per_device_train_batch_size: int,
|
||||
epoch: int,
|
||||
save_steps: int,
|
||||
lora_rank: int,
|
||||
trainer_callback=None
|
||||
) -> None:
|
||||
# 模型配置参数
|
||||
dtype = None # 数据类型,None表示自动选择
|
||||
load_in_4bit = False # 使用4bit量化加载模型以节省显存
|
||||
|
||||
model = FastLanguageModel.get_peft_model(
|
||||
# 原始模型
|
||||
model,
|
||||
# LoRA秩,用于控制低秩矩阵的维度,值越大表示可训练参数越多,模型性能可能更好但训练开销更大
|
||||
# 建议: 8-32之间
|
||||
r=lora_rank, # 使用动态传入的LoRA秩
|
||||
# 需要应用LoRA的目标模块列表
|
||||
target_modules=[
|
||||
"q_proj", "k_proj", "v_proj", "o_proj", # attention相关层
|
||||
"gate_proj", "up_proj", "down_proj", # FFN相关层
|
||||
],
|
||||
# LoRA缩放因子,用于控制LoRA更新的幅度。值越大,LoRA的更新影响越大。
|
||||
lora_alpha=16,
|
||||
# LoRA层的dropout率,用于防止过拟合,这里设为0表示不使用dropout。
|
||||
# 如果数据集较小,建议设置0.1左右。
|
||||
lora_dropout=0,
|
||||
# 是否对bias参数进行微调,none表示不微调bias
|
||||
# none: 不微调偏置参数;
|
||||
# all: 微调所有参数;
|
||||
# lora_only: 只微调LoRA参数。
|
||||
bias="none",
|
||||
# 是否使用梯度检查点技术节省显存,使用unsloth优化版本
|
||||
# 会略微降低训练速度,但可以显著减少显存使用
|
||||
use_gradient_checkpointing="unsloth",
|
||||
# 随机数种子,用于结果复现
|
||||
random_state=3407,
|
||||
# 是否使用rank-stabilized LoRA,这里不使用
|
||||
# 会略微降低训练速度,但可以显著减少显存使用
|
||||
use_rslora=False,
|
||||
# LoFTQ配置,这里不使用该量化技术,用于进一步压缩模型大小
|
||||
loftq_config=None,
|
||||
)
|
||||
|
||||
tokenizer = get_chat_template(
|
||||
tokenizer,
|
||||
chat_template="qwen-2.5",
|
||||
)
|
||||
|
||||
train_dataset = HFDataset.from_list(dataset)
|
||||
train_dataset = train_dataset.map(formatting_prompts,
|
||||
fn_kwargs={"tokenizer": tokenizer},
|
||||
batched=True)
|
||||
|
||||
# 初始化SFT训练器
|
||||
trainer = SFTTrainer(
|
||||
model=model, # 待训练的模型
|
||||
tokenizer=tokenizer, # 分词器
|
||||
train_dataset=train_dataset, # 训练数据集
|
||||
dataset_text_field="text", # 数据集字段的名称
|
||||
max_seq_length=model.max_seq_length, # 最大序列长度
|
||||
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer),
|
||||
dataset_num_proc=1, # 数据集处理的并行进程数
|
||||
packing=False,
|
||||
args=TrainingArguments(
|
||||
per_device_train_batch_size=per_device_train_batch_size, # 每个GPU的训练批次大小
|
||||
gradient_accumulation_steps=4, # 梯度累积步数,用于模拟更大的batch size
|
||||
warmup_steps=int(epoch * 0.1), # 预热步数,逐步增加学习率
|
||||
learning_rate=learning_rate, # 学习率
|
||||
lr_scheduler_type="linear", # 线性学习率调度器
|
||||
max_steps=int(epoch * len(train_dataset)/per_device_train_batch_size), # 最大训练步数(一步 = 处理一个batch的数据)
|
||||
fp16=not is_bfloat16_supported(), # 如果不支持bf16则使用fp16
|
||||
bf16=is_bfloat16_supported(), # 如果支持则使用bf16
|
||||
logging_steps=1, # 每1步记录一次日志
|
||||
optim="adamw_8bit", # 使用8位AdamW优化器节省显存,几乎不影响训练效果
|
||||
weight_decay=0.01, # 权重衰减系数,用于正则化,防止过拟合
|
||||
seed=114514, # 随机数种子
|
||||
output_dir=train_dir + "/checkpoints", # 保存模型检查点和训练日志
|
||||
save_strategy="steps", # 按步保存中间权重
|
||||
save_steps=save_steps, # 使用动态传入的保存步数
|
||||
logging_dir=train_dir + "/logs", # 日志文件存储路径
|
||||
report_to="tensorboard", # 使用TensorBoard记录日志
|
||||
),
|
||||
)
|
||||
|
||||
if trainer_callback is not None:
|
||||
trainer.add_callback(trainer_callback)
|
||||
|
||||
trainer = train_on_responses_only(
|
||||
trainer,
|
||||
instruction_part = "<|im_start|>user\n",
|
||||
response_part = "<|im_start|>assistant\n",
|
||||
)
|
||||
|
||||
# 开始训练
|
||||
trainer_stats = trainer.train(resume_from_checkpoint=False)
|
Reference in New Issue
Block a user