阅读 547

NLP 遇上中秋节

我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛 我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛

Word2Vec 品诗词

Word2Vec 的作用恐怕早已经大白于天下了,但是我们平时用的 Word2Vec 都是用文章来训练的,因为本人偏爱诗词,所有特意用五万多首唐诗和二十六万首宋词来训练 Word2Vec ,过程如下:

  • 只用到了每首诗或者词的主体内容,截去题目、作者、注释等无关内容
  • 因为诗词中的单字含义很丰富,所以将所有的诗或者词都分成单个汉字,写入 song_tang.txt ,每行是一首诗或者词,每个字之间用空格隔开
  • 因为诗词中也有不少词很有意境,所以用 jieba 将所有的诗或者词都分成词,每行是一首诗或者词,每个词之间用空格隔开,追加到 song_tang.txt 文件中
  • 使用 gensim 工具中的 Word2Vec 训练了 100 个 epoch 得到模型

具体代码看我的仓库,这里只是简单介绍训练代码:

# -*- coding: utf-8 -*-

import logging

from gensim.models import word2vec

def main():

    logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    sentences = word2vec.LineSentence("song_tang.txt")
    model = word2vec.Word2Vec(sentences, vector_size=250, epochs=100)

    #保存模型,供日後使用
    model.save("word2vec.model")

if __name__ == "__main__":
    main()
复制代码

测试代码也很简单:

# -*- coding: utf-8 -*-

from gensim.models import word2vec
from gensim import models
import logging

def main():
	model = models.Word2Vec.load('word2vec.model')

	try:
		for word in ['月','蟾','嫦娥','兔','中秋','赏月','桂花','花灯','饼','桂花']:
			q_list = word.split()
			if len(q_list) == 1:
				topn = 5
				print("相似詞前 %d 排序"%topn)
				res = model.wv.most_similar(q_list[0],topn = topn)

				for item in res:
					print(word,'-->',item[0]+","+str(item[1]))

	except Exception as e:
		print(repr(e))

if __name__ == "__main__":
	main()
复制代码

主要挑选了和中秋有关的常见意象包括:月、蟾、嫦娥、兔、中秋、赏月、桂花、花灯,本来还要测“月饼”,但是在这么大的诗词集中竟然没有切出来“月饼”这个词,难道古人称呼“月饼”另有其名?如果真的是这样那我凭借这一发现可以拿诺贝尔奖了吧。测试内容如下,从结果来看基本上意象是相近的:

相似詞前 5 排序
月 --> 影,0.5359682440757751
月 --> 雪,0.5294367074966431
月 --> 日,0.5167578458786011
月 --> 明月,0.5035041570663452
月 --> 晚,0.4992968440055847
相似詞前 5 排序
蟾 --> 月,0.4944111108779907
蟾 --> 蟾蜍,0.4766398072242737
蟾 --> 娥,0.4235338866710663
蟾 --> 星,0.41982918977737427
蟾 --> 嫦,0.41793638467788696
相似詞前 5 排序
嫦娥 --> 常娥,0.5356565117835999
嫦娥 --> 姮,0.46553120017051697
嫦娥 --> 素娥,0.44325411319732666
嫦娥 --> 蝉娟,0.44045501947402954
嫦娥 --> 嫦,0.4265734851360321
相似詞前 5 排序
兔 --> 鹿,0.46078577637672424
兔 --> 鼠,0.42531102895736694
兔 --> 狸,0.4184684455394745
兔 --> 獸,0.4146558344364166
兔 --> 兎,0.4029492437839508
相似詞前 5 排序
中秋 --> 重陽,0.5198861360549927
中秋 --> 今宵,0.5187360048294067
中秋 --> 清秋,0.5057112574577332
中秋 --> 今夕,0.4786747694015503
中秋 --> 元宵,0.478258341550827
相似詞前 5 排序
赏月 --> 吟风,0.42945602536201477
赏月 --> 不知今夕何夕,0.40893059968948364
赏月 --> 围棋,0.4009520709514618
赏月 --> 曾共赏,0.3729349374771118
赏月 --> 三国,0.3720923066139221
相似詞前 5 排序
桂花 --> 丹桂,0.46107402443885803
桂花 --> 桂子,0.44184908270835876
桂花 --> 菊花,0.4242440164089203
桂花 --> 桂香浮,0.40674737095832825
桂花 --> 桂枝,0.3999846577644348
相似詞前 5 排序
花灯 --> 宝幄,0.48819929361343384
花灯 --> 缟夜,0.48614564538002014
花灯 --> 暗记,0.450831800699234
花灯 --> 未晓,0.4482809007167816
花灯 --> 铜壶,0.4456891119480133
复制代码

LSTM 写藏头诗

人工智能写诗已经是一个很常见的操作,因为 LSTM 能很好捕捉到上下文的语义关系,诗词这种短小精悍的文本很适合用 LSTM ,如果对这个结构不懂可以去看我之前写的【LSTM 硬核基础讲解】。这里主要对数据的处理做简单的介绍,其他的模型搭建和训练过程套路基本不变,这里不再赘述。

文本是时间序列特征很强的数据,诗词也是如此,每句诗词都是靠含义丰富的字组成的,我们在输入当前字的时候,要预测下一个字,这就决定了我们的输入格式,例如:

原句:白日依山尽,黄河入海流

我们首先要使用"^"表示诗句的开始,"$"表示诗句的结束
变为:^白日依山尽,黄河入海流$

我们设置了最大的诗句长度为 20 ,使用"*"表示未知符号进行填充
变为:^白日依山尽,黄河入海流$*******

其对应的训练目标因为需要对当前时刻的输入来预测下一个时刻的输出,将上面的字符串整体右移,即:y[:-1] = x[1:]
目标:白日依山尽,黄河入海流$********

最后使用字典,将上面的字符串中的每个字映射为数字就完成了数据的预处理
复制代码

模型训练好,在用模型写诗的过程也和上面类似,每次输入上一个时刻的字以及上一个时刻的状态,来预测当前的字,知道满足结束条件,如够多少个字,或者遇到预测出句号为止。

那我们开始测试写藏头诗吧,主要使用了一些中秋常见的人物和话题,说实话有点人工智障的感觉,但是已经迈出了第一步了,之后可以继续完善写出诗的质量,毕竟模型也忒简单了点,就是应个景图个乐,给大家中秋助助兴。具体代码看我的仓库。

生成藏头诗 --->  嫦娥奔月
嫦娥属星汉,娥皇历七年。奔驰一千分,月下腾双翼。

生成藏头诗 --->  吴刚伐桂
吴转唐皇观,刚将镇选门。伐乏天上命,桂下朝建皇。

生成藏头诗 --->  中秋团圆
中庭窥砌木,秋风下帘绿。团圆粉扇衰,圆珰喷祥雨。

生成藏头诗 --->  中秋团圆阖家欢乐
中原风紧动明时,秋树三川带路长。团莺盖影寻仙籍,圆光丽月照霜轮。阖章合在唯前后,家在将齐退困浮。欢趣梦阑鼙鼓至,乐声幽鸟碧云空。

生成藏头诗 --->  嫦娥奔月广寒成仙
嫦娥几多拜,娥霜五百枝。奔郎避众地,月酒动纨扇。广皓清云表,寒光照夕风。成姿素羽翼,仙殿尚依然。
复制代码

其实我的模型还可以生成五言绝句和七言绝句,或者随机生成诗句

七言绝句:

 输入:我自横刀向天笑
 输出:我自横刀向天笑,有时苍虎皆久住
复制代码

五言绝句:

输入:床前明月光
输出:床前明月光,自恐奈归悲
复制代码

随机写诗:

巫峡红陵星别来,相公属望杳堪伤。盈浪临已解人去,今日江村弄云水。绿云虽出我真名,况值山川未死歌。但见西边断征客,又逢无事已千年。吴园肠断浦城北,八月曾归在路岐。
复制代码

Seq2Seq 写对联

之前已经写过诗了,这次就换个口味,用 Seq2Seq 写写对联。Seq2Seq 说简单点就是将左右两个 RNN 类型的结构连接起来,左边的 RNN 结构用来编码,将编码的结果传入右边的 RNN 结构进行解码,有基础不牢的同学可以移步看我的【Seq2Seq 训练和预测详解以及优化技巧】,这里有我实现的小案例【单词的翻译】很有意思,可以结合理解 Seq2Seq 原理和过程。该模型的经典应用一般都是用在机器翻译领域,用来写对联有点大材小用了。具体代码看我的仓库。

在搭建 Seq2Seq 也是经典套路,代码常规框架就是编写一个 encoder 和一个 decoder ,具体的细节可以深挖,还有很多可以提升性能的 trick ,比如测试的阶段加入了 beamsearch ,加入了 attention 机制,等等。

其实在搭建 Seq2Seq 的原理很简单,关键是实现的代码工程方面有许多细节需要注意。比如在于 decoder 阶段的在使用 beamsearch 或者用 greedysearch 的时候的输入需要做一番变化,数据的话这里用的是从网上下载的 77 万左右的对联。

写对联要有好的上联,看我用中秋做对,我出上联,模型出下联,这里的模型只是跑了大约一个 epoch ,GPU 跑了 2个小时,效果还不是很好,大家可以:

上联:嫦娥无言广寒宫
下联:玉女有幸福福门

上联:此去揽月几时回
下联:何处相思一夜来

上联:少年不识愁滋味
下联:无处无非苦读书

上联:登月成功
下联:出山成佛

上联:嫦娥偷药
下联:玉女出头

上联:广寒宫里屋两人
下联:大雅堂前有美人

上联:吴刚伐树
下联:李老登堂
复制代码

代码仓库

感谢

文章分类
人工智能
文章标签