首先观察以下诗句,你觉得写得怎么样,有什么发现吗?
'深宫娥向秦人间', '度江水辽天帝自', '学士大征鞍马嘶', '习气秪鬻不回首'
'深坞帛头泷吏问', '度春水一望一相', '学养养子君一枝', '习不见一年一夜'
没错,这是两首“七言绝句”,藏头是“深度学习”,而且是本实验所训练的模型写出来的!是不是不仔细瞧还像模像样的呢!
这背后的原理,无非是基于循环神经网络训练一个语言模型,如何训练呢?我们只需要将诗句相隔一个词分别作为网络的输入及输出,如下图所示:
在上图中,黄圈代表一个循环神经网络单元,s 表示诗句的开头,e 表示诗句的结束符。由于循环神经网络的每一步都有输出,我们可以再接一层全连接,基于此预测下一个单词是什么,也就是做一个基于词典大小的分类,而且是每一步都做分类(实际上称为序列标注任务)。对于模型而言,相当于给它看“s”,让它预测“城”,给它看“s城”,让它预测“春”,给它看“s城春”,让它预测“草”,以此类推,在经历大量语料训练之后,我们给定模型上文,其便可预测下文,这便是诗歌生成的基本原理。
古诗词中一般以字为词,因为对文本数据,统计其中的字构成字典:
查看字典量(此处以字为单位,因此字典大小不是非常大,不需要去除低频字):
接下来构建字与 id 的对应表,因为字要转换为 id 才能输入模型,而模型预测出 id 的形式,在生成时需要重新转换为 id。
接下来读取数据,并且添加首尾符号和转化为 id 的形式,由于诗的长度统一,因此不需要 padding 操作。
针对数据构建数据迭代器,注意在设计数据的输入输出时,假设诗句长度为 n,输入取前 n-1 个字符,输出取后 n-1 个字符。
对训练及验证数据批次化处理:
接下来搭建 LSTM 模型,前后分别接词向量层和输出层:
设置相关参数,模型及损失器初始化:
在以上过程中,定义了数据迭代器以及模型,接下来进行模型训练。首先定义训练函数:
定义测试函数:
设置随机种子,保证结果可复现:
综合以上,对模型进行训练及训练过程可视化,并且保存最佳模型:
由于在线环境运行较慢,上面只训练了 1 个 EPOCH (每个 EPOCH 大概 15 分钟)作为演示。
在训练好语言模型之后,我们希望基于此构建一个藏头诗生成器,输入 4 个藏头,模型生成以这些字为开头的诗句,为了达到这个目的,只需要取语言模型所预测的概率最高的字即可。另一方面,我们还希望,诗词能够体现不一样的文风,可以将某些文风强烈的诗句 prefix_words 预先输出语言模型得到相应的 hidden,cell,再将其作为初始化的状态输入语言模型生成藏头诗,之后所生成的诗句便可能带有 prefix_words 的风格。
载入模型:
由于在线环境运行较慢,上面只训练了 1 个 EPOCH 作为演示。接下来,你可以下载我在本地训练了 30 个 EPOCH 的模型用于推理: