NLP基础实验⑧:TextRNN、HAN

1 TextRNN

import tensorflow as tf
import numpy as np

tf.reset_default_graph()

sentences = [ "i like dog", "i love coffee", "i hate milk"]

word_list = " ".join(sentences).split()
word_list = list(set(word_list))
word_dict = {w: i for i, w in enumerate(word_list)}
number_dict = {i: w for i, w in enumerate(word_list)}
n_class = len(word_dict)

# TextRNN Parameter
n_step = 2 # number of cells(= number of Step)
n_hidden = 5 # number of hidden units in one cell

def make_batch(sentences):
    input_batch = []
    target_batch = []
    
    for sen in sentences:
        word = sen.split()
        input = [word_dict[n] for n in word[:-1]]
        target = word_dict[word[-1]]

        input_batch.append(np.eye(n_class)[input])
        target_batch.append(np.eye(n_class)[target])

    return input_batch, target_batch

# Model
X = tf.placeholder(tf.float32, [None, n_step, n_class]) # [batch_size, n_step, n_class]
Y = tf.placeholder(tf.float32, [None, n_class])         # [batch_size, n_class]

W = tf.Variable(tf.random_normal([n_hidden, n_class]))
b = tf.Variable(tf.random_normal([n_class]))

cell = tf.nn.rnn_cell.BasicRNNCell(n_hidden)
outputs, states = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)

# outputs : [batch_size, n_step, n_hidden]
outputs = tf.transpose(outputs, [1, 0, 2]) # [n_step, batch_size, n_hidden]
outputs = outputs[-1] # [batch_size, n_hidden]
model = tf.matmul(outputs, W) + b # model : [batch_size, n_class]

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)

prediction = tf.cast(tf.argmax(model, 1), tf.int32)

# Training
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

input_batch, target_batch = make_batch(sentences)

for epoch in range(5000):
    _, loss = sess.run([optimizer, cost], feed_dict={X: input_batch, Y: target_batch})
    if (epoch + 1)%1000 == 0:
        print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
        
input = [sen.split()[:2] for sen in sentences]

predict =  sess.run([prediction], feed_dict={X: input_batch})
print([sen.split()[:2] for sen in sentences], '->', [number_dict[n] for n in predict[0]])

Bi-LSTM

import tensorflow as tf
import numpy as np

tf.reset_default_graph()

sentence = (
    'Lorem ipsum dolor sit amet consectetur adipisicing elit '
    'sed do eiusmod tempor incididunt ut labore et dolore magna '
    'aliqua Ut enim ad minim veniam quis nostrud exercitation'
)

word_dict = {w: i for i, w in enumerate(list(set(sentence.split())))}
number_dict = {i: w for i, w in enumerate(list(set(sentence.split())))}
n_class = len(word_dict)
n_step = len(sentence.split())
n_hidden = 5

def make_batch(sentence):
    input_batch = []
    target_batch = []

    words = sentence.split()
    for i, word in enumerate(words[:-1]):
        input = [word_dict[n] for n in words[:(i + 1)]]
        input = input + [0] * (n_step - len(input))
        target = word_dict[words[i + 1]]
        input_batch.append(np.eye(n_class)[input])
        target_batch.append(np.eye(n_class)[target])

    return input_batch, target_batch

# Bi-LSTM Model
X = tf.placeholder(tf.float32, [None, n_step, n_class])
Y = tf.placeholder(tf.float32, [None, n_class])

W = tf.Variable(tf.random_normal([n_hidden * 2, n_class]))
b = tf.Variable(tf.random_normal([n_class]))

lstm_fw_cell = tf.nn.rnn_cell.LSTMCell(n_hidden)
lstm_bw_cell = tf.nn.rnn_cell.LSTMCell(n_hidden)

# outputs : [batch_size, len_seq, n_hidden], states : [batch_size, n_hidden]
outputs, _ = tf.nn.bidirectional_dynamic_rnn(lstm_fw_cell,lstm_bw_cell, X, dtype=tf.float32)

outputs = tf.concat([outputs[0], outputs[1]], 2) # output[0] : lstm_fw, output[1] : lstm_bw
outputs = tf.transpose(outputs, [1, 0, 2]) # [n_step, batch_size, n_hidden]
outputs = outputs[-1] # [batch_size, n_hidden]

model = tf.matmul(outputs, W) + b

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)

prediction = tf.cast(tf.argmax(model, 1), tf.int32)

# Training
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

input_batch, target_batch = make_batch(sentence)

for epoch in range(10000):
    _, loss = sess.run([optimizer, cost], feed_dict={X: input_batch, Y: target_batch})
    if (epoch + 1)%1000 == 0:
        print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))

predict =  sess.run([prediction], feed_dict={X: input_batch})
print(sentence)
print([number_dict[n] for n in [pre for pre in predict[0]]])

尽管TextCNN能够在很多任务里面能有不错的表现,但CNN有个最大问题是固定 filter_size 的视野,一方面无法建模更长的序列信息,另一方面 filter_size 的超参调节也很繁琐。CNN本质是做文本的特征表达工作,而自然语言处理中更常用的是递归神经网络(RNN, Recurrent Neural Network),能够更好的表达上下文信息。具体在文本分类任务中,Bi-directional RNN(实际使用的是双向LSTM)从某种意义上可以理解为可以捕获变长且双向的的 "n-gram" 信息。

RNN算是在自然语言处理领域非常一个标配网络了,在序列标注/命名体识别/seq2seq模型等很多场景都有应用,Recurrent Neural Network for Text Classification with Multi-Task Learning文中介绍了RNN用于分类问题的设计,下图LSTM用于网络结构原理示意图,示例中的是利用最后一个词的结果直接接全连接层softmax输出了。

 

 

2 HAN:Hierarchical Attention Networks

CMU的工作,利用分层注意力网络做文本分类的task,发表在NAACL 2016,TextRNN + Attention 模型 https://www.aclweb.org/anthology/N16-1174.pdf

它一方面用层次化的结构保留了文档的结构,另一方面在word-level和sentence-level。淘宝标题场景只需要 word-level 这一层的 Attention 即可。加入Attention之后最大的好处自然是能够直观的解释各个句子和词对分类类别的重要性。

 

①分层

  • 文本由时序性的sentence组成,而sentence则是由时序性的word组成。
  • 如果我们通过unsupervised word2vec拿到了word embedding,那么document representation就变成了一个embedding aggregation的问题。
  • 最直接的可以构建一个分层的时序性神经网络(RNN,LSTM,GRU),一层把word aggregate成sentence一层把sentence aggregate成document

这就是这篇论文HAN:Hierarchical Attention Networks中hierarchical的意思

②Attention

(1)Word Encoder

有两个Bidirectional GRU encoder,一个是GRU for word sequence,另一个是GRU for sentence sequence。

(2)Word Attention

(3)Sentence Encoder

(4)Sentence Attention

Sentence attention的过程和word attention完全一致,也是需要一个 us 作为sentence context vector。得到了documentation representation就是 v。

(5)context vector

在两个attention module中,都各有一个context vector用来计算attention weight。

这个context vector其实是和随机初始化,并且也是在training过程中会根据梯度更新的。

那梯度会让这个vector往什么方向更新呢?

  • 直觉上说,我们可以理解这个context vector为一个针对word/sentence embedding的query,
  • 这个query的问题就是“什么是有用的信息”,这个context的目标就是使得有用的(informative)Uit 与 context vector做内积之后有更高的权重。
  • 在这篇文章中,使用了vector,应该也可以用神经网络来做映射。

(6)Document Classifification

(7)关于Attention

本文提出了一种基于层次化attention的文本分类模型,可以利用attention机制识别出一句话中比较重要的词语,利用重要的词语形成句子的表示,同样识别出重要的句子,利用重要句子表示来形成整篇文本的表示。

attention的提出就是为了选出这个序列里真正起作用的token做正例。HAN说明模型做出判断时关注到了那些词。

  • 注意力机制是如何学到模型所应注意的词呢?一个几何上的直觉解释是,在高维空间里,学习过程中模型不断拉进对任务有用的token向量attention向量的距离。
  • 最终学习到的就是当前任务下,以attention向量为中心的一个巨大高维球形空间,token向量距离中心越近的就是越与任务相关的token。换句话说,attention机制学到了和任务相关的特征词。
  • 内积的直观解释我觉得是注意力向量提供了一个高维空间的一个语义方向,而每个token向量在注意力的语义方向上的投影决定了模型的行为,从而简化了模型的复杂度。


 

参考文献

论文:https://arxiv.org/abs/1605.05101v1

论文解读:https://blog.csdn.net/sinat_33741547/article/details/84838877

概念简介:https://www.jianshu.com/p/a846c311d3ac

图解LSTM和GRU:https://blog.csdn.net/IOT_victor/article/details/88934316

HAN :

https://zhuanlan.zhihu.com/p/133487764

https://zhuanlan.zhihu.com/p/267773976

https://www.zhihu.com/question/444712435/answer/1734304145

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值