如何用Hub数据集微调Huggingface Seq2Seq模型?代码与损失计算解惑
问题解惑:用
dxiao/requirements-ner-id微调flax-community/t5-large-wikisplit 一、核心概念拆解
1. 模型获取预期值与损失计算逻辑
T5属于序列到序列(Seq2Seq)模型,训练时必须同时提供编码器输入和解码器的真实标签:
- 编码器输入对应你要处理的原始文本(比如你的
complex_sentence),用来生成语义表示 - 解码器的真实标签(
labels字段)是模型要生成的目标文本(比如你的simplified_sentence),模型通过对比预测token与labels中的真实token,计算交叉熵损失来完成参数更新
你的原代码里只设置了decoder_input_ids,但缺少关键的labels字段,导致模型无法计算损失。另外decoder_input_ids一般是目标序列的左移版本(自动在开头加<s>、去掉末尾</s>),HuggingFace的Trainer会自动处理这一步,无需手动设置。
2. Seq2Seq模型微调核心流程
- 数据准备:明确输入文本(编码器输入)和目标文本(解码器输出)的对应关系
- 预处理:对输入、目标文本分别tokenize,生成
input_ids、attention_mask(编码器用,标记有效token)、labels(目标token的id序列,用于损失计算) - 参数配置:设置训练batch大小、学习率、训练轮数等控制训练过程的参数
- 启动训练:Trainer自动完成前向传播、损失计算、反向传播、参数更新全流程
3. 关键参数说明
数据集层面(模型必需)
input_ids:输入文本tokenize后的id序列,是编码器的核心输入attention_mask:标记哪些token是有效输入(避免padding部分干扰注意力计算)labels:目标文本tokenize后的id序列,模型靠它计算损失(注意要把padding的token_id替换为-100,模型会自动忽略这些位置的损失)
训练参数(Seq2SeqTrainingArguments核心项)
per_device_train_batch_size:单GPU/CPU上的训练batch大小,根据显存调整learning_rate:控制参数更新的步长,T5微调一般用1e-5~5e-5,太大容易过拟合num_train_epochs:训练轮数,即整个数据集被遍历的次数,0.25轮太少,建议至少1轮evaluation_strategy:评估时机,steps表示每N步评估一次,epoch表示每轮结束评估predict_with_generate:评估时让模型生成结果,再计算BLEU等生成类指标gradient_accumulation_steps:梯度累积步数,显存不足时用,相当于把N个小batch的梯度合并后再更新参数
二、修正后的完整微调示例
1. 加载依赖与模型、Tokenizer
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM from datasets import load_dataset from transformers import Seq2SeqTrainer, Seq2SeqTrainingArguments, DataCollatorForSeq2Seq import evaluate # 加载预训练模型和Tokenizer checkpoint = "flax-community/t5-large-wikisplit" tokenizer = AutoTokenizer.from_pretrained(checkpoint) model = AutoModelForSeq2SeqLM.from_pretrained(checkpoint).cuda()
2. 加载并预处理数据集
# 加载目标数据集 raw_dataset = load_dataset("dxiao/requirements-ner-id") # 将tokens数组转换为完整句子 def token_to_string(token_array): return " ".join(token_array) # 处理单条数据,生成输入-目标对 def process_example(example): raw_sentence = token_to_string(example["tokens"]) # 这里用替换"The"作为简化示例,实际任务可根据需求调整目标生成逻辑 simplified_sentence = raw_sentence.replace("The", "XXXXXXXXXXX") return { "complex_sentence": raw_sentence, "target_sentence": simplified_sentence } # 批量处理数据集,移除无用字段 processed_dataset = raw_dataset.map(process_example).remove_columns(["id", "tokens", "tags", "ner_tags"])
3. Tokenize数据集
def tokenize_function(examples): # 处理编码器输入 model_inputs = tokenizer( examples["complex_sentence"], truncation=True, padding="max_length", max_length=128 ) # 处理目标文本,作为模型的labels with tokenizer.as_target_tokenizer(): labels = tokenizer( examples["target_sentence"], truncation=True, padding="max_length", max_length=128 ) # 将padding部分的token_id替换为-100,模型计算损失时会忽略这些位置 model_inputs["labels"] = [ [-100 if token == tokenizer.pad_token_id else token for token in label] for label in labels["input_ids"] ] return model_inputs # 批量执行tokenize tokenized_datasets = processed_dataset.map(tokenize_function, batched=True) # 设置数据集格式为PyTorch张量,方便Trainer加载 tokenized_datasets.set_format("torch", columns=["input_ids", "attention_mask", "labels"])
4. 配置训练参数与启动训练
# 加载BLEU评估指标 bleu = evaluate.load("bleu") # 定义自定义指标计算函数 def compute_metrics(eval_pred): predictions, labels = eval_pred # 解码预测结果,跳过特殊token decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) # 还原labels中的-100为pad_token_id,再解码 labels = [[label if label != -100 else tokenizer.pad_token_id for label in label_seq] for label_seq in labels] decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) # 计算BLEU分数(注意references要嵌套成二维数组) result = bleu.compute(predictions=decoded_preds, references=[[label] for label in decoded_labels]) return {"bleu": result["bleu"]} # 配置训练参数 training_args = Seq2SeqTrainingArguments( output_dir="./t5-wikisplit-finetuned", # 模型保存路径 log_level="error", num_train_epochs=1, learning_rate=3e-5, lr_scheduler_type="linear", warmup_steps=50, optim="adafactor", weight_decay=0.01, per_device_train_batch_size=2, per_device_eval_batch_size=2, gradient_accumulation_steps=8, evaluation_strategy="steps", eval_steps=100, predict_with_generate=True, generation_max_length=128, save_steps=500, logging_steps=10, push_to_hub=False, auto_find_batch_size=True ) # 使用Seq2Seq专用的数据收集器,自动处理decoder_input_ids等细节 data_collator = DataCollatorForSeq2Seq(tokenizer, model=model) # 初始化Trainer trainer = Seq2SeqTrainer( model=model, args=training_args, train_dataset=tokenized_datasets["train"], eval_dataset=tokenized_datasets["validation"], tokenizer=tokenizer, data_collator=data_collator, compute_metrics=compute_metrics ) # 启动训练 trainer.train()
内容的提问来源于stack exchange,提问作者jonash_01
相关产品推荐
相关产品推荐

