我有点困惑,当使用 Huggignface 的训练器类训练 T5(实际上是 LongT5)模型时,在哪里(以及是否)添加 EOS 代币。
数据集包含如下文本对:
来自 | 到 |
---|---|
一些文字 | 一些对应的文字 |
其他一些文字 | 其他一些对应文字 |
分词器已经过定制训练:
tokenizer = SentencePieceUnigramTokenizer()
tokenizer.train_from_iterator(iterator=iterator, vocab_size=32_128, show_progress=True, unk_token="<unk>")
并且加载如下:
tokenizer = T5TokenizerFast(tokenizer_file="data-rb-25000/tokenizer.json",
padding=True, bos_token="<s>",
eos_token="</s>",unk_token="<unk>",
pad_token="<pad>")
在训练之前,数据集被标记化,并且过滤掉标记计数过高的示例,如下所示:
MAX_SEQUENCE_LENGTH = 16_384 / 2
def preprocess_function(examples):
inputs = tokenizer(
examples['from'],
truncation=False, # Don't truncate yet
padding=False, # Don't pad yet
return_length=True,
)
labels = tokenizer(
examples['to'],
truncation=False,
padding=False,
return_length=True,
)
inputs["input_length"] = inputs["length"]
inputs["labels"] = labels["input_ids"]
inputs["label_length"] = labels["length"]
inputs.pop("length", None)
return inputs
tokenized_data = dataset.map(preprocess_function, batched=True, remove_columns=dataset["train"].column_names)
def filter_function(example):
return example['input_length'] <= MAX_SEQUENCE_LENGTH and example['label_length'] <= MAX_SEQUENCE_LENGTH
filtered_data = tokenized_data.filter(filter_function)
训练是这样完成的:
from transformers import DataCollatorForSeq2Seq
data_collator = DataCollatorForSeq2Seq(tokenizer=tokenizer, model="google/long-t5-tglobal-base")
from transformers import AutoModelForSeq2SeqLM, AutoConfig
config = AutoConfig.from_pretrained(
"google/long-t5-tglobal-base",
vocab_size=len(tokenizer),
pad_token_id=tokenizer.pad_token_id,
eos_token_id=tokenizer.eos_token_id,
decoder_start_token_id=tokenizer.pad_token_id,
)
model = AutoModelForSeq2SeqLM.from_config(config)
from transformers import GenerationConfig
generation_config = GenerationConfig.from_model_config(model.config)
generation_config._from_model_config = False
generation_config.max_new_tokens = 16_384
from transformers import Seq2SeqTrainer, Seq2SeqTrainingArguments
training_args = Seq2SeqTrainingArguments(
output_dir="rb-25000-model",
eval_strategy="epoch",
save_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=1,
per_device_eval_batch_size=1,
gradient_accumulation_steps=16,
gradient_checkpointing=True,
weight_decay=0.01,
save_total_limit=3,
num_train_epochs=5,
logging_steps=1,
predict_with_generate=True,
load_best_model_at_end=True,
bf16=True,
)
trainer = Seq2SeqTrainer(
model=model,
args=training_args,
train_dataset=filtered_data["train"],
eval_dataset=filtered_data["test"],
tokenizer=tokenizer,
data_collator=data_collator,
compute_metrics=compute_metrics,
generation_config=generation_config,
)
trainer.train()
我知道代币生成器不会添加 EOS 代币:
inputs = tokenizer(['Hello world', 'Hello'], padding=True, truncation=True, max_length=100, return_tensors="pt")
labels = inputs["input_ids"]
print(labels)
print(tokenizer.convert_tokens_to_ids(['<s>'])[0])
print(tokenizer.convert_tokens_to_ids(['<pad>'])[0])
print(tokenizer.convert_tokens_to_ids(['<unk>'])[0])
print(tokenizer.convert_tokens_to_ids(['</s>'])[0])
print(tokenizer.convert_ids_to_tokens([1]))
输出:
tensor([[1, 10356, 1, 5056],
[1, 10356, 16002, 16002]])
16000
16002
0
16001
['▁']
(我不太明白索引为 1 的奇怪标记是什么。
无论如何,我想知道 Trainer 类或 DataCollator 是否真的添加了 EOS。我在网上没有找到任何关于如何以及在哪里添加 EOS 的示例。
我怀疑它不存在,因为在训练模型之后,它不会停止生成,直到达到 max_new_tokens (设置为相当高)。
这里的最佳实践是什么?我应该在哪里添加EOS?这段代码是否还有其他需要检查的地方,或者对于更有经验的人来说看起来很奇怪?
据我所知,T5 tokenizer 应该以 EOS 代币结束序列。 HuggingFace 上的预训练 T5 分词器默认执行此操作。您可以使用 TemplateProcessing 在分词器上强制执行此行为:
from tokenizers.processors import TemplateProcessing
tokenizer._tokenizer.post_processor = TemplateProcessing(
single="$A </s>",
pair="$A </s> $B </s>",
special_tokens=[("</s>", tokenizer.eos_token_id)]
)
inputs = tokenizer(['Hello world', 'Hello'], padding=True, truncation=True, max_length=100, return_tensors="pt")
labels = inputs["input_ids"]
print(labels)
这应该给出:
tensor([[1, 10356, 1, 5056, 16001],
[1, 10356, 16001, 16002, 16002]])