跟风玩玩目前最大的中文GPT2模型(bert4keras)
By 苏剑林 | 2020-11-20 | 67059位读者 |相信不少读者这几天都看到了清华大学与智源人工智能研究院一起搞的“清源计划”(相关链接《中文版GPT-3来了?智源研究院发布清源 CPM —— 以中文为核心的大规模预训练模型》),里边开源了目前最大的中文GPT2模型CPM-LM(26亿参数),据说未来还会开源200亿甚至1000亿参数的模型,要打造“中文界的GPT3”。
我们知道,GPT3不需要finetune就可以实现Few Shot,而目前CPM-LM的演示例子中,Few Shot的效果也是相当不错的,让人跃跃欲试,笔者也不例外。既然要尝试,肯定要将它适配到自己的bert4keras中才顺手,于是适配工作便开始了。本以为这是一件很轻松的事情,谁知道踩坑踩了快3天才把它搞好,在此把踩坑与测试的过程稍微记录一下。
模型介绍 #
该计划发布的第一个模型称为CPM-LM,参数大约为26亿,预训练中文数据规模100GB,是一个单向的语言模型,其他细节大家自行到下面的链接阅读就好。这么大的参数量,一般我们都是直接使用而不考虑去finetune它的了,它所具备的能力就是无条件地随机生成文本,当然我们也可以实现给它一些引导,然后用它来实现文本续写,至于Few Shot之类的应用,本质上也都是文本续写的变式。
这里说一下模型结构的问题,也是笔者在适配过程中踩的第一个坑。CPM-LM的模型架构跟OpenAI的GPT2是一样的,所以说白了这就是一个26亿参数的中文GPT2模型。开始笔者没认真看,然后又被CPM-LM-TF2项目稍微误导了一下,导致在前期以为它的结构跟GPT2_ML一样(GPT2_ML既不是GPT,也不是GPT2,它介乎两者之间),很久都没调出合理的结果。而意识到这个问题后,重新搭建GPT2模型并且适配对应的权重,也不是什么难事了,包括权重转换到tf格式,有了CPM-LM-TF2项目的参照,也不算困难。
Tokenizer #
在适配过程中踩到的第二个坑,是关于tokenizer的。不得不说,CPM-LM所写的tokenizer,在笔者看来实在是难登大雅之堂,至今仍然我耿耿于怀。
该tokenizer实际上就是在Google的sentencepiece的基础上包装了一下,但是又包得特别不优雅,简直是强迫症患者的噩梦。具体来说,像BERT的tokenizer或者sentencepiece这类分词工具,都会默认去掉空格、换行符等分隔符,但是CPM-LM想要将空格和换行符保留,所以在送入tokenizer之前将它们替换为了别的符号(目前是空格替换为“▂”、换行符替换为“▃”),最后输出之前再替换回来。这是一种常见的做法,是可以理解的,但我最不能理解的是换行符的替代符号“▃”居然不在它的sentencepiece模型的词表中!为了避免“▃”变成<unk>,CPM-LM又将它替换为<cls>,也就是做了二次替换,才得到换行符的id...
笔者第一次看到这样的设计时,内心是简直要崩溃的:往sentencepiece里边多加入个字符有这么难吗,何至于写成这样...没办法,开源模型的才是大佬,只能想办法适配它了。笔者想了很久很久,对bert4keras原有的SpTokenizer修修补补了一番,总算勉强把它搞好了。
使用测试 #
吐槽就到这里吧,总之,经过笔者两天多的折腾,从0.9.3版本开始,bert4keras就可以加载CPM-LM模型了,单跑预测估计需要16G以上的显存(我自己是22G的RTX)。模型权重的转换过程与基本的加载方案可见:
一些Few Shot效果(输出结果会有一定的随机性,如果只关心Few Shot效果,可以考虑将解码方式换为beam search):
# 常识推理
# 本例输出:北京
query = u"""
美国的首都是华盛顿
法国的首都是巴黎
日本的首都是东京
中国的首都是
"""
print(text_expansion.generate(query[1:-1], 1)[0])
# 单词翻译
# 本例输出:bird
query = u"""
狗 dog
猫 cat
猪 pig
鸟
"""
print(text_expansion.generate(query[1:-1], 1)[0])
# 主语抽取
# 本例输出:杨振宁
query = u"""
从1931年起,华罗庚在清华大学边学习边工作 华罗庚
在一间简陋的房间里,陈景润攻克了“哥德巴赫猜想” 陈景润
在这里,丘成桐得到IBM奖学金 丘成桐
杨振宁在粒子物理学、统计力学和凝聚态物理等领域作出里程碑性贡献
"""
print(text_expansion.generate(query[1:-1], 1)[0])
# 三元组抽取
# 本例输出:张红,体重,140斤
query = u"""
姚明的身高是211cm,是很多人心目中的偶像。 ->姚明,身高,211cm
虽然周杰伦在欧洲办的婚礼,但是他是土生土长的中国人->周杰伦,国籍,中国
小明出生于武汉,但是却不喜欢在武汉生成,长大后去了北京。->小明,出生地,武汉
吴亦凡是很多人的偶像,但是他却是加拿大人,另很多人失望->吴亦凡,国籍,加拿大
武耀的生日在5月8号,这一天,大家都为他庆祝了生日->武耀,生日,5月8号
《青花瓷》是周杰伦最得意的一首歌。->周杰伦,作品,《青花瓷》
北京是中国的首都。->中国,首都,北京
蒋碧的家乡在盘龙城,毕业后去了深圳工作。->蒋碧,籍贯,盘龙城
上周我们和王立一起去了他的家乡云南玩昨天才回到了武汉。->王立,籍贯,云南
昨天11月17号,我和朋友一起去了海底捞,期间服务员为我的朋友刘章庆祝了生日。->刘章,生日,11月17号
张红的体重达到了140斤,她很苦恼。->
"""
print(text_expansion.generate(query[1:-1], 1)[0])
文章小结 #
文章简单介绍了一个清华大学新开源的26亿参数的GPT2模型CPM-LM,并将它适配到了bert4keras框架内,稍微吐槽了一下转换过程中遇到的坑,最后演示了一下CPM-LM还不错的Few Shot效果。
转载到请包括本文地址:https://www.spaces.ac.cn/archives/7912
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Nov. 20, 2020). 《跟风玩玩目前最大的中文GPT2模型(bert4keras) 》[Blog post]. Retrieved from https://www.spaces.ac.cn/archives/7912
@online{kexuefm-7912,
title={跟风玩玩目前最大的中文GPT2模型(bert4keras)},
author={苏剑林},
year={2020},
month={Nov},
url={\url{https://www.spaces.ac.cn/archives/7912}},
}
November 20th, 2020
苏神权重 有 百度云盘的备份吗 其他太慢
看到了
November 21st, 2020
[...]苏剑林. (2020, Nov 20). 《也来玩玩目前最大的中文GPT2模型(bert4keras) 》[Blog post]. Retrieved from https://kexue.fm/archives/7912[...]
November 23rd, 2020
膜拜大神
November 23rd, 2020
确实Tokenizer那块很迷, 命名一看还以为是bpe,,, 实际上确是SentencePiece,虚晃一枪.
November 26th, 2020
苏神,文中的22G的RTX应该是指24G的Titan RTX吧?我这边倒是两块RTX2080Ti加在一起是22G,可以加了交火卡也没办法搞定显存叠加,唉,玩不了了这个26亿的模型了。
可以用原始的pytorch版的,它可以分布在两张7G以上的卡上跑。
单跑用两个P4就可以推理。
November 30th, 2020
您觉得cpm_lm,t5,gpt2_ml的效果对比如何?
cpm_lm比gpt2_ml效果好些;t5跟它们不同类,没什么可比性。
少打了个m,哈哈。中文生成模型中的效果,您觉得是cpm_lm>mt5>gpt2_ml这样排序吗
cpm_lm,gpt2_ml只是现成的无条件语言模型,基本不考虑finetune的;mt5可以finetune做seq2seq。所以还是那句话,它们没有可比性。
那mt5微调后做中文文本生成,效果怎么样
https://kexue.fm/archives/7867
December 8th, 2020
print(text_expansion.generate(query[1:-1], 1)[0])
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-8: ordinal not in [ RequsetId: null ].
代码都没有变更,报这个异常是什么原因呢?
May 26th, 2021
有英文领域内的类似few shots 实现工作吗。GPT3的模型还没有开放,bert4keras有这样的模型吗
https://github.com/EleutherAI/gpt-neo
这有个可以用。
July 1st, 2021
苏神这个我加载 304M参数的cpm-lm
直接在我的 数据上 训练 gpt2就可以吧
随你