今早一起床就看到 François Chollet 大神(Keras 作者)发推,根据 GPT-2 中量模型的超长距离记忆想到了一种简单的不基于机器学习的文本生成方式,居然神奇地复现了 GPT-2 的结果,方法很简单(只用了20分钟写代码),每次用要基于文本中的关键词,还有句末几个词,在谷歌直接搜索,然后将获取检索片段基于最后几个词连接起来,只要这样不停做甚至能生成 GPT-2 论文中那个发现神奇独角兽的例子。
至于代码,François 很幽默地说:
“I will not be releasing the code, because you guys couldn't handle the power of a Python script cobbled together in 20 minutes with Requests, BeautifulSoup, and regular expressions. It would change algorithmic cyberwar forever.”
又是一个 “Too dangerous to release。” 不过更多调侃意义在里头,狠狠嘲讽了 OpenAI 一波。
趁此机会,也把自己慢慢码了几天的稿发出来。
如果说 BERT 模型还很巧妙地提出 Maske Language Model Loss 加上 Next Sentence Prediction Loss 来让预训练模型学到更全面信息,那 GPT 系列则就只是把貌似平淡无奇的 Transformer Decoder(单向解码)给加大再加大,当然好的数据也不可少,然后向大家展示大到一定程度后 (GPT-2) 非常厉害的,特别在语言生成上,刚好填补了 BERT 的缺陷。
GPT-2 现在如此有名估计也是吸取了前一次教训,直到 BERT 出现大部分人才知道有个 GPT,于是 GPT-1 完美的成了 BERT 的垫脚石。所以待 GPT-2 出场,虽然论文正文短短几页,却是出尽风头,不知其中 OpenAI 公关有出几分力,待人们问开不开源啊,答曰:”
Too Dangerous to Release!
(就是不给你们用!)“
此语一出,一下惊起一片反响,立刻出现了挺 OpenAI 派和反 OpenAI 派,双方论证十足,纷纷发文,光那几天我每天都起码得看上一篇关于 GPT-2 争论的博文。而 GPT-2 最小的 117MB (指参数量) 预训练模型,也在这吵吵闹闹中被悄悄放了出来。
之后,偶有在 Reddit 看到几篇基于 117M 模型 finetune 的帖,很有趣,一直想找时间也弄个玩玩,可惜太忙,前段时间专注 BERT 加上度假,也就搁下了。
因此,直到前几天,莫名发现关于 GPT-2 finetune 的帖突然又变多了,才发现 OpenAI 又放出了更大的模型,也就是这篇
主要会用到的 345M 模型(如需用小模型,只需将文中 345M 改为 117M 即可)
。除此二者,根据论文,应该还有两个更大模型,如果 OpenAI 准备放出的话,估计 GPT-2 这个概念能炒整个 2019 年。
趁着现在这波热潮,总算是把 GPT-2 使用相关的库都浏览了一遍,顺便自己也 finetune 了几个模型,发现效果还挺好的。此外发现网上也没太多关于 GPT-2 使用的中文资料,因此就分享一下自己经验。
本文结构如下,大家自取所需:
-
首先,我会告诉大家如何用更底层的 nshepperd 的
gpt-2
库来 finetune 模型;
-
之后,会介绍如何用更上层的 minimaxir 的
gpt-2-simple
库来更简单地 finetune 模型,主要用 Colab 的 Notebook 来教大家免费蹭 GPU 来 finetune 模型;
-
最后,我会介绍如何把训练好的模型用 t04glovern 的
gpt-2-flask-api
模型部署到服务器上,通过浏览器访问,输入句子让模型续写。这里还会用到 Hugginface 的
pytorch-pretrained-BERT
来转换模型格式。
所需库 Github 链接:
-
gpt-2
:
https://github.com/nshepperd/gpt-2
-
gpt-2-simple
:
https://github.com/minimaxir/gpt-2-simple
-
gpt-2-flask-api
:
https://github.com/t04glovern/gpt-2-flask-api
-
pytorch-pretrained-BERT
:
https://github.com/huggingface/pytorch-pretrained-BERT
用到的训练数据是我从网上爬下来的老友记十季的剧本:
接下来就让我们开始吧,默认大家会用 Linux 系统来操作。
老板先来一盘 GPT-2
整个过程大体分四步,首先我们需要先
Clone 下来
nshepperd 的
gpt-2
库
,之后准备数据与模型,然后再 finetune,最后用保存模型来生成样本。
git clone https://github.com/nshepperd/gpt-2
pip install -r requirements.txt
进入文件夹,
下载需要的预训练模型
,这里用刚放出来的中型模型,机器不够可以用 117M 模型。
python download_model.py 345M
345M 模型比较大,大概 1.4 个G,所以下载同时可以来处理数据。如果用我提供的数据,那直接拷过去就好了,放在
data/
下。稍微看看数据的样子吧。
然后就可以开始 finetune 了。如想要 finetune 时更快些的话,可以
预编码数据
成训练格式。
PYTHONPATH=src ./encode.py data/friends.txt data/friends.txt.npz
开始 finetune 吧!
PYTHONPATH=src ./train.py --dataset data/friends.txt.npz --model_name 345M
其他值得关注参数:
-
learning_rate:
学习率,默认
2e-5
,可根据数据集大小适当调整,数据集大的话可以调大些,小的话可以调小些。
-
sample_every:
每多少步生成一个样本看看效果,默认 100。
-
run_name:
当前训练命名,分别在
samples
和
checkpoint
文件夹下创建当前命名的子文件夹,之后生成的样本和保存的模型分别保存在这两个子文件夹。训练中断想继续训练就可以用同样的
run_name
,如想跑不同任务请指定不同
run_name
.
根据机器训练速度会不同,但基本上两三千步就能看到些还算不错的结果了。
于是我们就拿到了 finetune 好的模型,接下来就来进行好玩的生成环节吧。第一步需要将生成的模型,更改名字,放入
models
文件夹里,替换掉原来的模型(
一定要记得将之前的模型备份!
)。
比如说将
checkpoint/run1
里的
model-4000
模型名字都改成
model.ckpt
,然后移入
models/345M
里去。
OK了! 先是自由发挥环节,用
generate_unconditional_samples.py
来无条件生成样本。
python src/generate_unconditional_samples.py --top_k 40 --temperature 0.9 --model_name 345M
然后是命题作文,有条件互动生成环节。
python src/interactive_conditional_samples.py --top_k 40 --temperature 0.9 --model_name 345M
运行后会出现一个互动框,输入你想让模型续写的话,让我想想...
下面就是见证奇迹的时刻了... ... ... 好一会儿后,当当
在 Rachel loves Andy 两秒后,完美跑题,伤心,不过感觉后半段还是很有意思。
关于参数
--topk
还有
--temperature
,会影响生成的效果,可自己尝试调节一下,上面例子使用的是两个推荐设定。
到此 finetune 一个基本 GPT-2 的过程就完了,是不是比想象中要简单很多。
不过下面还有更简单的方法。
简之又简:gpt-2-simple
如其名,
gpt-2-simple
库就是可以让你更简单 finetune 和生成,主要基于上面的
gpt-2
写的。
关键使用教程,我直接将 Colab Notebbok 部分内容放在这,更详细查看 Notebook。
推荐使用 Notebook 查看教程,有免费 GPU 可以薅。
Notebook 链接
:
https://colab.research.google.com/drive/1_kQQ8WCjus9mz0Cf1onVeE1pUG-ulTqA
整个过程大体和上面一样,不过命令更加简单了。同样先是下载模型。
import gpt_2_simple as gpt2
gpt2.download_gpt2(model_name="345M")
然后放上训练数据,就可以开始训练了。
sess = gpt2.start_tf_sess()
gpt2.finetune(sess,
dataset="friends.txt",
model_name='345M',
steps=1000,
restore_from='fresh',
print_every=10,
sample_every=200,
save_every=500
)
很直观,直接调用 gpt2.finetune 就可以了。
gpt2.finetune 训练参数介绍:
-
restore_from
:
fresh
是指从 GPT2 原模型开始, 而
latest
是从之前 finetune 保存的模型继续训练
-
sample_every
: 每多少步输出样本,看看训练效果
-
print_every
: 每多少步打印训练的一些参数,从左到右,步数、时间,loss,平均loss
-
learning_rate
: 学习率 (默认
1e-4
, 如果数据小于1MB的话可以调低到
1e-5
)
-
run_name
: 运行的时候,保存模型到
checkpoint
下子文件夹,默认
run1
你会发现和上一节很多内容都类似。
训练获得保存模型后,又到了生成环节,先把模型 load 进来。
sess = gpt2.start_tf_sess()
gpt2.load_gpt2(sess)
然后生成文本。
gpt2.generate(sess)
gpt2.generate
里面也有很多参数可以设置:
-
length
: 生成文本长度 (默认 1023, 也是可设最大长度)
-
temperature
: temperature 越高,生成越随意。(默认 0.7,推荐 0.7 到 1.0之间)
-
top_k
: 将输出限定在 top k 里面 (默认0,也就是不使用。推荐在生成效果差的时候使用,可以设top_k=40)
-
truncate
: 从指定符号阶段生成文本 (比如设
truncate=''
, 那么就会取第一个''前的文本作为输出). 可以和一个比较小的
length
值搭配使用.
-
include_prefix
: 如果用了
truncate
和
include_prefix=False
, 那么在返回文本中就不会包含
prefix
里的文本。
要大量生成文本的话可以用
gpt2.generate_to_file
.
部署到服务器上
既然弄好了模型,那么当然就是要开始炫耀啦,部署到服务器上,让小伙伴们从浏览器也能直接互动生成文本。
主要用到 Github 上的
gpt-2-flask-api
库,只需要提供它一个预训练或者 finetune 好的 GPT2 模型(Huggingface 的 pytorch 格式)。
将模型文件放在
models/
下,命名为
gpt2-pytorch_model.bin
也可以先用它提供的实例模型来做个实验:
mkdir models
curl --output models/gpt2-pytorch_model.bin https://s3.amazonaws.com/models.huggingface.co/bert/gpt2-pytorch_model.bin
之后运行
python deployment/run_server.py
.
然后,会获得一个访问端口:
之后直接用浏览器访问就行了,如果是远程访问把 0.0.0.0 改成服务器IP就好了。
现在往里面键入想要它续写的话就行,等一会儿,结果就出来了。黑色的是用户输入,红色的是模型生成。
最后的问题:如何部署自己的模型
因为 finetune 保存的 tensorflow 的模型文件格式,但这个包只支持 Pytorch 的保存模型。因此我们要先
将 tensorflow 的模型转换成 Pytorch 的模型
。
这里可以用 Huggingface 的
pytorch-pretrained-BERT
库里面的转换脚本,先根据指示安装库,之后运行以下脚本。
export GPT2_DIR=模型所在文件夹
pytorch_pretrained_bert convert_gpt2_checkpoint $GPT2_DIR/model_name output_dir/ path_to_config/config.json
上面命令
convert_gpt2_checkpoint
后三个参数分别是,输入的 tensorflow 模型路径,转换输出的 pytorch 模型路径,模型的配置参数文件。
需要注意的是,因为这几个库之间的不统一,所以下载下来 345M 模型的设置文件在转换时会出错,需要添加一些参数。前面有下载 345M 模型的话,会发现模型文件夹下有一个设置文件