Keras版Sequence2Sequence对对联实战——自然语言处理技术(3)

今天我们来做NLP(自然语言处理)中Sequence2Sequence的任务。其中Sequence2Sequence任务在生活中最常见的应用场景就是机器翻译。除了机器翻译之外,现在很流行的对话机器人任务,摘要生成任务都是典型的Sequence2Sequence。Sequence2Sequence的难点在于模型需要干两件比较难的事情:

  • 语义理解(NLU:Natural Language Understanding):模型必须理解输入的句子。
  • 句子生成(NLG:Natural Language Generation):模型生成的句子需符合句法,不能是人类觉得不通顺的句子。

想想看,让模型理解输入句子的语义已经很困难了,还得需要它返回一个符合人类造句句法的序列。不过还是那句话,没有什么是深度学习不能解决的,如果有,当我没说上句话。

Sequence2Sequence任务简介

Sequence2Sequence是一个给模型输入一串序列,模型输出同样是一串序列的任务和序列标注有些类似。但是序列标注的的输出是定长的,标签于输入一一对应,而且其标签类别也很少。Sequence2Sequence则不同,它不需要输入与输出等长。

Sequence2Sequence算法简介

Sequence2Sequence是2014年由Google 和 Yoshua Bengio提出的,这里分别是Google论文Yoshua Bengio论文的下载地址。从此之后seq2seq算法就开始不断演化发展出不同的版本,不过万变不离其宗,其整体架构永远是一个encode-decode模型。下面简要介绍四种seq2seq的架构。
1.basic encoder-decoder :将encode出来的编码全部丢给decode每个step。

basic encoder-decoder

2.encoder-decoder with feedback :将encode出来的编码只喂给decode的初始step,在解码器端,需将每个step的输出,输入给下一个step。
encoder-decoder with feedback

3.encoder-decoder with peek:1和2的组合,不仅将encode出来的编码全部丢给decode每个step,在解码器端,也将每个step的输出,输入给下一个step。
encoder-decoder with peek

4.encoder-decoder with attention:将3模型的encode端做了一个小小的改进,加入了attention机制,简单来说,就是对encode端每个step的输入做了一个重要性打分。
encoder-decoder with attention

本次实验采用的是basic encoder-decoder架构,下面开始实战部分。

对对联实战

数据加载

数据样式如下图所示是一对对联。模型的输入时一句"晚 风 摇 树 树 还 挺",需要模型生成" 晨 露 润 花 花 更 红"。这个数据集有个特点,就是输入输出是等长的,序列标注算法在这个数据集上也是适用的。


data.png
with open ("./couplet/train/in.txt","r") as f:
    data_in = f.read()
with open ("./couplet/train/out.txt","r") as f:
    data_out = f.read()    
data_in_list = data_in.split("\n")
data_out_list = data_out.split("\n")
data_in_list = [data.split() for data in data_in_list]
data_out_list = [data.split() for data in data_out_list]

执行上方代码将数据变成list,其格式如下:
data_in_list[1:3] :
[['愿', '景', '天', '成', '无', '墨', '迹'], ['丹', '枫', '江', '冷', '人', '初', '去']]
data_out_list[1:3]:
[['万', '方', '乐', '奏', '有', '于', '阗'], ['绿', '柳', '堤', '新', '燕', '复', '来']]

构造字典

import itertools
words_all = list(itertools.chain.from_iterable(data_in_list))+list(itertools.chain.from_iterable(data_out_list))
words_all = set(words_all)
vocab = {j:i+1 for i ,j in enumerate(words_all)}
vocab["unk"] = 0

通过上方代码构造一个字典,其格式如下所示,字典的作用就是将字变成计算机能处理的id。

{'罇': 1,
 '鳣': 2,
 '盘': 3,
 ...
 '弃': 168,
 '厌': 169,
 '楞': 170,
 '杋': 171,
  ...
}

数据预处理

from keras.preprocessing.sequence import pad_sequences
data_in2id = [[vocab.get(word,0) for word in sen] for sen in data_in_list]
data_out2id = [[vocab.get(word,0) for word in sen] for sen in data_out_list]
train_data = pad_sequences(data_in2id,100)
train_label = pad_sequences(data_out2id,100)
train_label_input = train_label.reshape(*train_label.shape, 1)

执行上方代码将数据padding成等长(100维),后续方便喂给模型。其中需要注意的是需要给train_label扩充一个维度,原因是由于keras的sparse_categorical_crossentropy loss需要输入的3维的数据。

模型构建

from keras.models import Model,Sequential
from keras.layers import GRU, Input, Dense, TimeDistributed, Activation, RepeatVector, Bidirectional
from keras.layers import Embedding
from keras.optimizers import Adam
from keras.losses import sparse_categorical_crossentropy

def seq2seq_model(input_length,output_sequence_length,vocab_size):
    model = Sequential()
    model.add(Embedding(input_dim=vocab_size,output_dim = 128,input_length=input_length))
    model.add(Bidirectional(GRU(128, return_sequences = False)))
    model.add(Dense(128, activation="relu"))
    model.add(RepeatVector(output_sequence_length))
    model.add(Bidirectional(GRU(128, return_sequences = True)))
    model.add(TimeDistributed(Dense(vocab_size, activation = 'softmax')))
    model.compile(loss = sparse_categorical_crossentropy, 
                  optimizer = Adam(1e-3))
    model.summary()
    return model
model = seq2seq_model(train_data.shape[1],train_label.shape[1],len(vocab))

模型构建,keras可以很方便的帮助我们构建seq2seq模型,这里的encode 和decode采用的都是双向GRU。其中RepeatVector(output_sequence_length) 这一步,就是执行将encode的编码输入给decode的每一个step的操作。从下图的模型可视化输出可以看到这个basic的seq2seq有39万多个参数需要学习,简直可怕。


model

模型训练

模型构建好之后,就可以开始训练起来了。需要做的是将输入数据喂给模型,同时定义好batch_size和epoch。

model.fit(train_data,train_label_input, batch_size =32, epochs =1, validation_split = 0.2) 

下图是模型训练的过程,一个epoch大概需要近1小时,loss缓慢降低中。


train

模型预测

import numpy as np
input_sen ="国破山河在"
char2id = [vocab.get(i,0) for i in input_sen]
input_data = pad_sequences([char2id],100)
result = model.predict(input_data)[0][-len(input_sen):]
result_label = [np.argmax(i) for i in result]
dict_res = {i:j for j,i in vocab.items()}
print([dict_res.get(i) for i in  result_label])

训练10个epoch后,是时候考考模型的对对联实力了,运行上方代码,就可以看到模型的预测效果。
“国破山河在”对出“人来日月长”,确实很工整。看来模型学习得不错,晋升为江湖第一对穿肠啦。

对对联效果

结语

Seq2Seq在解决句子生成任务确实实力雄厚,仅仅只用了最basic的ecode和decode就能对出如此工整的句子(当然不是所有的句子都能对得这么好)。如果使用更强的模型训练对对联模型,实力应该可以考个古代状元。所以,大家有没有开始对深度学习处理NLP问题产生好奇,学习起来吧。

参考:
https://kexue.fm/archives/6270
https://blog.csdn.net/sinat_26917383/article/details/75050225

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 1 什么是 Seq2Seq ? Seq2Seq 是一个 Encoder-Decoder 结构的神经网络,它的输入是...
    DejavuMoments阅读 18,430评论 0 11
  • 近日,谷歌官方在 Github开放了一份神经机器翻译教程,该教程从基本概念实现开始,首先搭建了一个简单的NMT模型...
    MiracleJQ阅读 6,246评论 1 11
  • 智能机器人在生活中随处可见:iPhone里会说话的siri、会下棋的阿法狗、调皮可爱的微软小冰……她们都具有一定的...
    宇哥聊AI阅读 1,986评论 1 7
  • 要学会坚强,这个世界除了你自己,别人不能替你扛你应该面对的责任。父母虽是避风港但他们也有老去的一天,张亚林曾说过父...
    杨格_阅读 363评论 0 0
  • 今天我由衷的开心和激动,因为我要结婚了。一时间纵有千言万语,不知如何表达。最终只能汇聚成两个字,那就是“感谢”。 ...
    杨涛_f2ac阅读 308评论 0 0