财新传媒 财新传媒

阅读:0
听报道

 

作者:Andy、蒋宝尚
今天是腊月二十九,按照黄历,是解除、破屋、坏垣的好日子。
  
中国人的传统也是在这一天贴对联,准确来说是春联。
 
对联来源于对偶句和骈俪句,讲究工整对仗,充分展现了我们中国人独特精致的艺术美感。
 
古人常以“吟诗作对”交友比试,但到了今天,为了让写出的对联“出奇不意”,文摘菌决定用最近NLP领域大火的Transfomer模型,训练一个聪明的AI,我出上联,它对下联,将这个“对穿肠”的任务交给它。
 
模型介绍
 
 
关于对春联这个任务,可以明显看出是一个序列到序列的任务。于是就得祭出现在自然语言处理里面的大杀器了,Seq2Seq + Attention!
 
于是,文摘菌便采用了 Transformer 序列到序列模型。Transformer由论文《Attention is All You Need》提出,渐渐有取代RNN成为NLP中主流模型的趋势,现在更是谷歌云TPU推荐的参考模型,包括谷歌给自己TPU打广告的 Bert 就是Transformer模型。
 
Transformer架构完全舍弃了深度学习里经典的RNN和CNN结构,而只用注意力机制还搭建。最早在机器翻译任务上进行测试就超越 RNN,达到了当时SOTA的效果。Transformer 不光像 CNN 一样克服了 RNN 最被人诟病的训练慢问题,利用self-attention 机制实现快速并行,层数还可以增加到比较深,充分发掘DNN模型的特性,提升模型准确率。同时,在NLP任务上,还比CNN和RNN的性能都普遍要好,它不为王,谁为王。
 
大数据文摘之前与百度NLP联合出品了一篇文章:BERT大火却不懂 Transformer?读这一篇就够了。对Transformer不熟悉的同学可以点击超链接阅读文章,保你理解的透透的。
 
这里我们用6层Transformer单元,里面的Self-Attention的头数为8,隐单元数512个。模型采用 tensorflow 框架,GPU 则用深度学习标配的 Tesla K80。
 
好了,下面先介绍一下数据集。
 
数据集
 
文摘菌所使用的数据集来自一位名为冯重朴_梨味斋散叶的博主的新浪博客,总共包含超过70万副对联。
 
然而,由于未知的原因,这位博主的博客已经无法访问了……
 
 
但是,这一珍贵的数据集却在GitHub上广为流传。
 
github地址(脚本已无法使用,可以用我们上传的couplets,google drive需科学翻墙):
https://github.com/wb14123/couplet-dataset
 
google drive:
https://drive.google.com/file/d/13cJWWp_ST2Xqt76pEr5ZWa6LVJwGYC4-/view?usp=sharing
 
整个数据集解压过后总共56.9兆,其中训练数据集56.4兆,测试数据集400多KB。另外,数据是以TXT格式储存的。全文不含标点15,153,840字,如果每天看100条的话,20多年都看不完。而文摘菌采用Tesla K80,2个小时就能来一个Epoch。
 
数据预处理
 
首先进行数据预处理,因为拿到的数据比较干净,所以这任务主要就是创建词表。值得一提的是,数据集的压缩文件中存在着一个创建好的词表。你也可以用数据集给出的词表。因为对联任务并不难,所以我们直接使用字粒度来作为输入,也就是像“我们”这样的词,我们是把其当做两个单元进行输入,而不是一个。
 
关键代码如下:
 
defmake_vocab(fpaths, out):
     '''Constructs vocabulary.
 
     Args:
       fpaths: Astring. Input file path.
       fname: Astring. Output file name.
     '''  
     char2cnt = Counter()
     for path in fpaths:
         for line inopen(path, 'r'):
             line = line.strip()
             ifnot line: *# detect the empty line*
                 continue
             chars = line.split()
            char2cnt.update(chars)
     withopen(out, 'w') as fout:
        fout.write("{}\t1000000000\n{}\t1000000000\n{}\t1000000000\n{}\t1000000000\n".format("", "", "", "")) # special tokens
         for word, cnt in char2cnt.most_common(len(char2cnt)):
            fout.write(u"{}\t{}\n".format(word, cnt))
         print("%d chars written!"% (len(char2cnt)))
 
建立完词表之后,所有单个汉字加上一些特殊字符,总共9126个字符。其实我们看看频率为1的字符就会发现,好像都不认识。一般来说,在序列到序列任务里面,我们会在词表里面忽略频率小不常用的字词。但是因为这里我们词表并不大,所以就全部采用了。
 
 
之后,我们对训练数据的字长进行统计,来决定训练时句子的最大长度。统计后发现,对联数据中单句的长度大部分集中在5-10字之间,最长大概30字左右,所以训练的最大长度文摘菌选的也是30。这个长度并不长,所以之后整个 Transformer 的大小都不是很大。
 
模型编写与训练
 
这里我们首先搭建好模型,之后通过数据将模型中的参数训练成我们所希望的,之后存储起来。这里便是一个epoch存储一个模型。而测试的时候,就可以直接读入参数获得一个训练好的模型来使用。
 
此外,我们也可以将保存的模型分享给别人,让其他人也可以直接利用我们的训练结果。
 
模型和训练的代码太多,这里就全不放出来了,感兴趣的读者可以去github上下载完整代码,也可以在大数据微信公众号后台回复“对联”下载完整代码以及数据集。
 
github地址:
https://github.com/andy-yangz/coupletsseq2seqtransformer
 
于是整个模型的训练过程主要分为四个步骤:
第一步,先下载对联数据 couplets, 然后解压到 data 里去
第二步,调整超参数
第三步,运行 prepro.py预处理数据,产生词表,也可以用提供的词表
第四步,运行 train.py 训练模型
 
评估
 
训练完之后,保存模型,评估脚本会自动读入最新模型来进行评估。
评估的主要步骤包括:
建立模型
读入训练好的参数
读入测试数据
将数据喂入模型
编码解码获得结果
 
最主要代码应该是解码这一块:
 
### Autoregressive inference
                    preds = np.zeros((hp.batch_size, hp.maxlen), np.int32)
                    for j in range(hp.maxlen):
                        _preds = sess.run(g.preds, {g.x: x, g.y: preds})
                        preds[:, j] = _preds[:, j]
 
最开始喂入x,还有一个空的preds,然后获得一个预测的字,将这个字放在preds相应的位置,之后循环,不断将preds填满。最后就能获得完整的预测结果。
 
这里每次预测的字,取得都是预测概率最大的那个字,这叫做 greedy decoding(贪婪搜寻解码),因为每次都是选最大的。这样虽然快,但是也会出现陷入局部最优解的情况。更好些解码方法,可以使用Beam search(束搜索)。
 
训练结果
 
最后,来看看文摘菌的训练结果如何。
 
先皮一下!
 
话说改革开放四十周年,当然首先要响应一下我们的改革开放。先来段霸榜b站数月,念诗之王的作品。
 
接招,我出上联:
 
上联: 改革春风吹满地,中国人民真争气
 
AI 对:
下联: 和谐时雨润千山,小康社稷好生活
 
好诗好诗,充分说明了改革开放带给我们的美好生活。似乎还不错,我们系统的觉悟非常高啊。
 
再来考考它,博大精深的六学知识吧:
 
上联: 文体两开花
下联: 武功一代人
 
emmm,比较微妙,还行吧。
 
看到武功一代人,文摘菌突然想到了金庸先生。先生为我们创造了一个庞大的武学世界,为了纪念先生,就以下面两句为上联吧:
 
上联:飞雪连天射白鹿
下联:落花遍地戏黄蜂
 
嗯,确实有点世外桃源桃花岛的味道。
 
上联:笑书神侠倚碧鸳
下联:闲看仙女下红尘
 
这就有意思了,金庸武侠世界里的女子确实都是洒脱般的人物,尤其是小龙女和它的后辈黄衫女子活脱脱的一尘不染。
 
上联: 盘他
下联: 还我
 
好像有点都对不上了。
 
再来考考我们机器人2018年热点。
 
上联: 小猪佩奇社会人
下联: 大圣传世文明家
 
居然对上了。
 
再来,今年最火剧。
 
上联: 延禧攻略
下联: 棣华家声
 
莫非 AI 在暗示我们下一个会火的电视剧吗,根据名字,似乎是讲一个家族中两兄弟的故事,有意思有意思。
 
再看看,综艺节目:
 
上联: 创造一零一
下联: 和谐万事兴
 
嗯,嗯,非常和谐。
 
上联:锦鲤
下联:银蛇
 
普普通通。
 
再看看美国领导人们。
 
上联:特朗普
下联:小康庄
上联:奥巴马
下联:罗汉松
 
没想到虽然都身为世界领导人,对出来的东西都这么朴素。
 
好,那在看看贸易战:
 
上联:中美贸易战
下联:大中华国风
 
对的好,对的好,思想很正确。
 
好了不玩了。再来看几个正经点的对联吧。
 
我们从测试集里面挑几个,这里上联和下联是正确的,模型是机器人给出的下联:
 
上联: 腾飞上铁,锐意改革谋发展,勇当千里马
下联: 和谐南供,安全送电保畅通,争做领头羊
模型: 奋进开篇,激情发展促和谐,更上一层楼
 
还有:
 
上联: 一句相思吟岁月
下联: 千杯美酒醉风情
模型: 几杯寂寞醉春秋
 
看上去对的还算挺工整。
 
当然我们也看到了一些问题。比如说模型学到的都是一些和宽泛的对应,名词动词相对应做到了,也能保证通顺,但是却在一些需要典故和外界知识的例子中,无法做出合适的回应。有时就会出现,不知道“上铁”和“南供”这俩典故,或者出现所谓无情对,上下联字词对仗工整但是意思毫不相关。
 
这是我们训练了6个epoch,也就是模型将数据看了六遍的结果。这次我们总共保存了7个模型,从Epoch1到Epoch7模型,其实要说那个好只能是见仁见智了,比如说我就觉得6个Epoch会好些。但是可以确认的是随着Epoch增加模型就越能学到对联数据里的模式。
 
是不是还挺好玩,感兴趣的同学,也跟我们一起训练一个自己的“对穿肠”吧。
 
其他模型
 
关于AI写对联,其实之前已经有了基于深度学习seq2seq的模型,同样其用到的也是TensorFlow和那位冯重朴_梨味斋散叶的博主提供的数据集。
 
目前,代码已经开源,你可以在下面的github中找到:
 
 
当然,除了模型代码之外,你也可以打开作者给出的网址,随意的出对子。
 
 
对了,上面那个AI创作者名叫王斌,英国莱斯特大学读计算机硕士,现在是一名软件工程师。
 
微软对联与百度对联
 
除了单打独斗的程序员,尝试了对联AI的科技巨头也不少,文摘菌这里介绍两个最有名的项目,不想自己训练模型的同学,可以直接取用。
 
比较早出现的对联AI来自微软亚洲研究院,自然语言计算组研究开发,沈向洋主导的研究项目。
 
微软的对联AI要谨慎且复杂一点,如果以“改革春风吹满地”作为上联,它也会给你许多个下联作为备选。
 
 
最令人感动的是,如果你不喜欢,还可以换一种方式!
 
为了让对联更加对仗工整,你可以选择分词的方式。如果你仍然不满意,可以点击反馈意见按钮告诉它“家长”。最后,还能生成横批。
 
 
除了微软这个老前辈,还有一个江湖新秀,那就是今年百度联合央视网、网易推出的智能春联。据说,他能根据每个人的五官特性生成专属于你的春联。
 
嗯,也就是刷脸写对联。
 
文摘菌用李彦宏的大头像试了试,可以感受一下这魔幻的过程:
 
 
微软对联:
http://duilian.msra.cn/
百度对联(用手机打开哟):
https://chunlian.news.cntv.cn/
 
好了,文摘菌要去贴春联啦,就到这里吧。
 
话题:



0

推荐

大数据文摘

大数据文摘

448篇文章 3年前更新

普及数据思维,传播数据文化

文章