继续整理之前看过的论文,这一次看又明白了很多之前没有细究的问题,也参考了不少资料,昨晚看high了看到了2点多,学习大概就是这样一个过程吧。
参考代码:https://github.com/Njust-taoye/transformer-tensorflow 感谢
开头先说创新点:
- 提出self-attention,自己和自己做attention,使得每个词都有全局的语义信息(长依赖):
- 由于 Self-Attention 是每个词和所有词都要计算 Attention,所以不管他们中间有多长距离,最大的路径长度也都只是 1。可以捕获长距离依赖关系
- 提出multi-head attention,可以看成attention的ensemble版本,不同head学习不同的子空间语义。
废话不多说,直接带着代码看论文介绍的网络结构。
下面总结是以论文实验 机器翻译来说的。
上面这个图看的很清楚整个transformer的架构。
我们分部分来看:
Stage1 Encode Input
和普遍的做法一样,对文本输入做word embedding 操作,
embedding_encoder = tf.get_variable("embedding_encoder", [Config.data.source_vocab_size, Config.model.model_dim], self.dtype)(注意这里的model_dim)
embedding_inputs = embedding_encoder
上面其实就是做个输入文本的embedding
矩阵而已。
模型里已经剔除了RNN,CNN,如何体现输入文本的先后关系呢?而这种序列的先后关系对模型有着至关重要的作用,于是论文中提出了Position Encoding骚操作~,论文是这样做的:
这里的dmodel指的是上面word embedding
的维度,pos就是当前的词在整个句子中的位置,例如第一个词还是第二个词等,i就是遍历dmodel
时的值,在代码中是这样做的:
def positional_encoding(dim, sentence_length, dtype=tf.float32):
encoded_vec = np.array([pos/np.power(10000, 2*i/dim) for pos in range(sentence_length) for i in range(dim)])#对每个位置处都产生一个维度为dim的向量。
encoded_vec[::2] = np.sin(encoded_vec[::2])#偶数位置处
encoded_vec[1::2] = np.cos(encoded_vec[1::2])#奇数位置处
return tf.convert_to_tensor(encoded_vec.reshape([sentence_length, dim]), dtype=dtype)
# Positional Encoding
with tf.variable_scope("positional-encoding"):
positional_encoded = positional_encoding(Config.model.model_dim, Config.data.max_seq_length, dtype=self.dtype)
上面生成的positional_encoded其