NLP学习1 - 使用Huggingface Transformers框架从头训练语言模型

摘要

由于huaggingface放出了Tokenizers工具,结合之前的transformers,因此预训练模型就变得非常的容易,本文以学习官方example为目的,由于huggingface目前给出的run_language_modeling.py中尚未集成Albert(目前有 GPT, GPT-2, BERT, DistilBERT and RoBERTa,具体可以点开前面的链接),这是由于目前对于Albert的支持,在分词时,AlbertTokenizer仅仅支持SentencePiece file 类型的分词,所以不能直接用Tokenizers分词。实际实验时,发现可以直接用Tokenizers.BertWordPieceTokenizer进行分词。因此,本文在example的基础上,对中文文本《论语》进行预训练,使用Tokenizers和Transformers,环境在Google Colab GPU下。

训练Tokenizer

本文选择训练一个BertWordPieceTokenizer的分词器,由于Bert和Albert大致相似,因此分词器上选择BertWordPieceTokenizer不会有问题。首先在colab装一下包:

# We won't need TensorFlow here
!pip uninstall -y tensorflow
# Install `transformers` from master
!pip install git+https://github.com/huggingface/transformers
!pip list | grep -E 'transformers|tokenizers'
# transformers version at notebook update --- 2.9.1
# tokenizers version at notebook update --- 0.7.0

接着,建立分词器:

%%time 
from tokenizers import BertWordPieceTokenizer
files = "./lunyu.txt" # 训练文本文件
vocab_size = 10000 
min_frequency = 2 
limit_alphabet = 10000
special_tokens = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] #适用于Bert和Albert

# Initialize a tokenizer
tokenizer = BertWordPieceTokenizer(
    clean_text=True, handle_chinese_chars=True, strip_accents=True, lowercase=True,
)

# Customize training
tokenizer.train(
    files,
    vocab_size = vocab_size,
    min_frequency=min_frequency,
    show_progress=True,
    special_tokens=special_tokens,
    limit_alphabet=limit_alphabet,
    wordpieces_prefix="##"
    )

然后把分词器保存在硬盘中:

!mkdir tokenizer
tokenizer.save("tokenizer")

这样,我们就拥有了一个针对《论语》文本的分词器,这会对于论语类文本的应用更加合适,这里还可以利用tokenizers包来测试一下分词效果:

from tokenizers.implementations import BertWordPieceTokenizer
from tokenizers.processors import BertProcessing
tokenizer = BertWordPieceTokenizer(
    "./tokenizer/vocab.txt",
)

tokenizer._tokenizer.post_processor = BertProcessing(
    ("[CLS]", tokenizer.token_to_id("[SEP]")),
    ("[SEP]", tokenizer.token_to_id("[CLS]")),
)
tokenizer.enable_truncation(max_length=512)

tokenizer.encode("子曰:学而时习之。").tokens

这样,可以对子曰:学而时习之。这句话进行分词,由于我们用的是BertWordPieceTokenizer,对于中文来说,就是对每一个字进行分词。得到结果:

['[SEP]', '子', '曰', ':', '学', '而', '时', '习', '之', '。', '[CLS]']

从头训练一个语言模型

我们的目标是训练一个Albert模型,因为Albert模型与Bert相似,因此可以进行MLM( Masked language modeling)的任务,首先,我们需要定义一下模型的配置:

from transformers import AlbertConfig

config = AlbertConfig(
    vocab_size = 1359,
    embedding_size = 256,
    hidden_size = 768,
    num_hidden_layers = 6,
    num_attention_heads = 12,
    intermediate_size = 3072,
    hidden_act = "gelu",
    hidden_dropout_prob = 0.1,
    attention_probs_dropout_prob = 0.1,
    max_position_embeddings = 512,
    type_vocab_size = 2,
    initializer_range = 0.02,
    layer_norm_eps = 1e-12,
)

这里比较重要的超参数有vocab_size, embedding_size, hidden_size, num_hidden_layers, num_attention_heads涉及到网络的size,由于我也是个菜鸡,等下次学了再仔细写写,这里是抄的。

然后,我们还需要在Transformers中重新建立一个分词器:

from transformers import BertTokenizerFast
tokenizer = BertTokenizerFast.from_pretrained("./tokenizer", max_len=512)

接下来我们需要初始化我们的albert模型,这里需要注意的是,在配置模型参数时,因为我们从头开始训练,所以我们只从配置中进行初始化,而不需要从checkponit文件中初始化。

from transformers import AlbertForMaskedLM
model = AlbertForMaskedLM(config=config)
model.num_parameters()
# => 8554575个参数

接着,我们将使用建立好的分词器对文本数据进行分词,构建训练所需要的数据集。这里,由于我们只有一个文本文件,我们甚至不需要定制我们的数据集,直接使用LineByLineDataset。(还没仔细研究这个是干嘛的)

%%time
from transformers import LineByLineTextDataset

dataset = LineByLineTextDataset(
    tokenizer=tokenizer,
    file_path="./lunyu.txt",
    block_size=256,
)

然后,我们需要定义一个data_collator,这只是一个helper,它将帮助我们将数据集的不同sample批处理到一个object中,PyTorch就知道如何在这个object上执行backprop。(这里没有看懂,大概知道是转换成Pytorch能够处理的数据格式)

from transformers import DataCollatorForLanguageModeling

data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer, mlm=True, mlm_probability=0.15
)

所有配置完成后,我们就可以初始化我们的模型了:

from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir="./lunyuAlbert",
    overwrite_output_dir=True,
    num_train_epochs=20,
    per_gpu_train_batch_size=16,
    save_steps=2000,
    save_total_limit=2,
)

trainer = Trainer(
    model=model,
    args=training_args,
    data_collator=data_collator,
    train_dataset=dataset,
    prediction_loss_only=True,
)

最后,跑起来就完事儿了:

%%time
trainer.train()

由于文本数据比较小,所以结果还挺快的:

CPU times: user 2min 25s, sys: 1min 22s, total: 3min 47s
Wall time: 3min 47s
TrainOutput(global_step=680, training_loss=5.1874437787953545)

这里不评价好坏,只是学习一下如何使用Huggingface的Tokenizers包和Transformers包对Albert进行预训练。

参考:

Github的个人集成脚本:easy_bert_pretrain
huggingface的官方example:01_how_to_train.ipynb

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349