乐趣区

关于深度学习:Huggingface微调BART的代码示例WMT16数据集训练新的标记进行翻译

BART 模型是用来预训练 seq-to-seq 模型的降噪主动编码器(autoencoder)。它是一个序列到序列的模型,具备对损坏文本的双向编码器和一个从左到右的自回归解码器,所以它能够完满的执行翻译工作。

如果你想在翻译工作上测试一个新的体系结构,比方在自定义数据集上训练一个新的标记,那么解决起来会很麻烦,所以在本文中,我将介绍增加新标记的预处理步骤,并介绍如何进行模型微调。

因为 Huggingface Hub 有很多预训练过的模型,能够很容易地找到预训练标记器。然而咱们要增加一个标记可能就会有些辣手,上面咱们来残缺的介绍如何实现它,首先加载和预处理数据集。

加载数据集

咱们应用 WMT16 数据集及其罗马尼亚语 - 英语子集。load_dataset()函数将从 Huggingface 下载并加载任何可用的数据集。

 importdatasets
 
 dataset=datasets.load_dataset("stas/wmt16-en-ro-pre-processed", cache_dir="./wmt16-en_ro")

在上图 1 中能够看到数据集内容。咱们须要将其“压平”,这样能够更好的拜访数据,让后将其保留到硬盘中。

 defflatten(batch):
     batch['en'] =batch['translation']['en']
     batch['ro'] =batch['translation']['ro']
     
     returnbatch
 
 # Map the 'flatten' function
 train=dataset['train'].map(flatten)
 test=dataset['test'].map(flatten)
 validation=dataset['validation'].map(flatten)
 
 # Save to disk
 train.save_to_disk("./dataset/train")
 test.save_to_disk("./dataset/test")
 validation.save_to_disk("./dataset/validation")

下图 2 能够看到,曾经从数据集中删除了“translation”维度。

标记器

标记器提供了训练标记器所需的所有工作。它由四个根本组成部分:(但这四个局部不是所有的都是必要的)

Models: 标记器将如何合成每个单词。例如,给定单词“playing”:i) BPE 模型将其合成为“play”+“ing”两个标记,ii) WordLevel 将其视为一个标记。

Normalizers: 须要在文本上产生的一些转换。有一些过滤器能够更改 Unicode、小写字母或删除内容。

Pre-Tokenizers: 为操作文本提供更大灵活性解决的函数。例如,如何解决数字。数字 100 应该被认为是“100”还是“1”、“0”、“0”?

Post-Processors: 后处理具体情况取决于预训练模型的抉择。例如,将 [BOS](句首)或 [EOS](句尾)标记增加到 BERT 输出。

上面的代码应用 BPE 模型、小写 Normalizers 和空白 Pre-Tokenizers。而后用默认值初始化训练器对象,次要包含

1、词汇量大小应用 50265 以与 BART 的英语标记器统一

2、非凡标记,如 <s> 和 <pad>,

3、初始词汇量,这是每个模型启动过程的预约义列表。

 fromtokenizersimportnormalizers, pre_tokenizers, Tokenizer, models, trainers
 
 # Build a tokenizer
 bpe_tokenizer=Tokenizer(models.BPE())
 bpe_tokenizer.normalizer=normalizers.Lowercase()
 bpe_tokenizer.pre_tokenizer=pre_tokenizers.Whitespace()
 
 trainer=trainers.BpeTrainer(
     vocab_size=50265,
     special_tokens=["<s>", "<pad>", "</s>", "<unk>", "<mask>"],
     initial_alphabet=pre_tokenizers.ByteLevel.alphabet(),)

应用 Huggingface 的最初一步是连贯 Trainer 和 BPE 模型,并传递数据集。依据数据的起源,能够应用不同的训练函数。咱们将应用 train_from_iterator()。

 defbatch_iterator():
     batch_length=1000
     foriinrange(0, len(train), batch_length):
         yieldtrain[i : i+batch_length]["ro"]
         
 bpe_tokenizer.train_from_iterator(batch_iterator(), length=len(train), trainer=trainer )
 
 bpe_tokenizer.save("./ro_tokenizer.json")
 

BART 微调

当初能够应用应用新的标记器了。

 fromtransformersimportAutoTokenizer, PreTrainedTokenizerFast
 
 en_tokenizer=AutoTokenizer.from_pretrained("facebook/bart-base");
 ro_tokenizer=PreTrainedTokenizerFast.from_pretrained("./ro_tokenizer.json");
 ro_tokenizer.pad_token=en_tokenizer.pad_token
 
 deftokenize_dataset(sample):
     input=en_tokenizer(sample['en'], padding='max_length', max_length=120, truncation=True)
     label=ro_tokenizer(sample['ro'], padding='max_length', max_length=120, truncation=True)
 
     input["decoder_input_ids"] =label["input_ids"]
     input["decoder_attention_mask"] =label["attention_mask"]
     input["labels"] =label["input_ids"]
 
     returninput
 
 train_tokenized=train.map(tokenize_dataset, batched=True)
 test_tokenized=test.map(tokenize_dataset, batched=True)
 validation_tokenized=validation.map(tokenize_dataset, batched=True)

下面代码的第 5 行,为罗马尼亚语的标记器设置填充标记是十分必要的。因为它将在第 9 行应用,标记器应用填充能够使所有输出都具备雷同的大小。

上面就是训练的过程:

 fromtransformersimportBartForConditionalGeneration
 fromtransformersimportSeq2SeqTrainingArguments, Seq2SeqTrainer
 
 model=BartForConditionalGeneration.from_pretrained("facebook/bart-base")
 
 training_args=Seq2SeqTrainingArguments(
     output_dir="./",
     evaluation_strategy="steps",
     per_device_train_batch_size=2,
     per_device_eval_batch_size=2,
     predict_with_generate=True,
     logging_steps=2,  # set to 1000 for full training
     save_steps=64,  # set to 500 for full training
     eval_steps=64,  # set to 8000 for full training
     warmup_steps=1,  # set to 2000 for full training
     max_steps=128, # delete for full training
     overwrite_output_dir=True,
     save_total_limit=3,
     fp16=False, # True if GPU
 )
 
 trainer=Seq2SeqTrainer(
     model=model,
     args=training_args,
     train_dataset=train_tokenized,
     eval_dataset=validation_tokenized,
 )
 
 trainer.train()

过程也非常简单,加载 bart 根底模型(第 4 行),设置训练参数(第 6 行),应用 Trainer 对象绑定所有内容(第 22 行),并启动流程(第 29 行)。上述超参数都是测试目标,所以如果要失去最好的后果还须要进行超参数的设置,咱们应用这些参数是能够运行的。

推理

推理过程也很简略,加载通过微调的模型并应用 generate()办法进行转换就能够了,然而须要留神的是对源 (En) 和指标 (RO) 序列应用适当的分词器。

总结

尽管在应用自然语言解决 (NLP) 时,标记化仿佛是一个基本操作,但它是一个不应漠视的关键步骤。HuggingFace 的呈现能够不便的让咱们应用,这使得咱们很容易遗记标记化的基本原理,而仅仅依赖事后训练好的模型。然而当咱们心愿本人训练新模型时,理解标记化过程及其对上游工作的影响是必不可少的,所以相熟和把握这个根本的操作是十分有必要的。

本文代码:https://avoid.overfit.cn/post/6a533780b5d842a28245c81bf46fac63

作者:Ala Alam Falaki

退出移动版