Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

苏剑林作者广州火焰信息科技有限公司单位NLP,神经网络研究方向

基于CNN和序列标注的对联机器人 | 附数据集 & 开源代码

缘起

前几天看到了这个脑洞清奇的对联AI,大家都玩疯了一文,觉得挺有意思,难得的是作者还整理并公开了数据集,所以决定自己尝试一下。

动手

“对对联”,我们可以看成是一个句子生成任务,可以用 Seq2Seq 完成,跟我之前写的玩转Keras之Seq2Seq自动生成标题一样,稍微修改一下输入即可。上面提到的文章所用的方法也是 Seq2Seq,可见这算是标准做法了。

分析

然而,我们再细想一下就会发现,相对于一般的句子生成任务,“对对联”有规律得多:1)上联和下联的字数一样;2)上联和下联的每一个字几乎都有对应关系。

如此一来,其实对对联可以直接看成一个序列标注任务,跟分词、命名实体识别等一样的做法即可。这便是本文的出发点。 

说到这,其实本文就没有什么技术含量了,序列标注已经是再普通不过的任务了,远比一般的Seq2Seq 来得简单。

所谓序列标注,就是指输入一个向量序列,然后输出另外一个通常长度的向量序列,最后对这个序列的“每一帧”进行分类。相关概念来可以在简明条件随机场CRF介绍 | 附带纯Keras实现一文进一步了解。

模型

本文直接边写代码边介绍模型。如果需要进一步了解背后的基础知识的读者,还可以参考《中文分词系列:基于双向LSTM的Seq2Seq字标注》[1]、《中文分词系列:基于全卷积网络的中文分词》[2]、《基于CNN和VAE的作诗机器人:随机成诗》[3]。

我们所用的模型代码如下:

x_in = Input(shape=(None,))
x = x_in
x = Embedding(len(chars)+1, char_size)(x)
x = Dropout(0.25)(x)

x = gated_resnet(x)
x = gated_resnet(x)
x = gated_resnet(x)
x = gated_resnet(x)
x = gated_resnet(x)
x = gated_resnet(x)

x = Dense(len(chars)+1, activation='softmax')(x)

model = Model(x_in, x)
model.compile(loss='sparse_categorical_crossentropy',
              optimizer='adam')

其中 gated_resnet 是我定义的门卷积模块:

def gated_resnet(x, ksize=3):
    # 门卷积 + 残差
    x_dim = K.int_shape(x)[-1]
    xo = Conv1D(x_dim*2, ksize, padding='same')(x)
    return Lambda(lambda x: x[0] * K.sigmoid(x[1][..., :x_dim]) \
                            + x[1][..., x_dim:] * K.sigmoid(-x[1][..., :x_dim]))([x, xo])

仅此而已,就这样完了,剩下的都是数据预处理的事情了。当然,读者也可以尝试也可以把 gated_resnet 换成普通的层叠双向 LSTM,但我实验中发现层叠双向 LSTM 并没有层叠 gated_resnet 效果好,而且 LSTM 相对来说也很慢。

效果

训练的数据集来自以下链接,感谢作者的整理。

https://github.com/wb14123/couplet-dataset

完整代码:

https://github.com/bojone/seq2seq/blob/master/couplet_by_seq_tagging.py

训练过程:

对联机器人训练过程

部分效果:

看起来还是有点味道的。注意“晚风摇树树还挺”是训练集的上联,标准下联是“晨露润花花更红”,而模型给出来的是“夜雨敲花花更香”,说明模型并不是单纯地记住训练集的,还是有一定的理解能力;甚至我觉得模型对出来的下联更生动一些。

总的来说,基本的字的对应似乎都能做到,就缺乏一个整体感。总体效果没有下面两个好,但作为一个小玩具,应该能让人满意了。

王斌版AI对联:https://ai.binwang.me/couplet/

微软对联:https://duilian.msra.cn/default.htm

结语

最后,也没有什么好总结的。我就是觉得这个对对联应该算是一个序列标注任务,所以就想着用一个序列标注的模型来试试看,结果感觉还行。

当然,要做得更好,需要在模型上做些调整,还可以考虑引入 Attention 等,然后解码的时候,还需要引入更多的先验知识,保证结果符合我们对对联的要求。这些就留给有兴趣做下去的读者继续了。

相关链接

[1] https://kexue.fm/archives/3924

[2] https://kexue.fm/archives/4195

[3] https://kexue.fm/archives/5332

PaperWeekly
PaperWeekly

推荐、解读、讨论和报道人工智能前沿论文成果的学术平台。

工程CNN序列标注机器人Seq2Seq自然语言处理
2
暂无评论
暂无评论~