NELSONZHAO / zhihu

This repo contains the source code in my personal column (https://zhuanlan.zhihu.com/zhaoyeyu), implemented using Python 3.6. Including Natural Language Processing and Computer Vision projects, such as text generation, machine translation, deep convolution GAN and other actual combat code.
https://zhuanlan.zhihu.com/zhaoyeyu
3.5k stars 2.14k forks source link

关于encode和decode 字向量问题 #14

Open liyonglion opened 6 years ago

liyonglion commented 6 years ago

在encode阶段,使用tf.contrib.layers.embed_sequence函数来生成字向量。在decode阶段使用tf.random_uniform、tf.nn.embedding_lookup来生成和转换成字向量。 有两个疑问: 1.编码阶段和解码阶段不是同一个字向量,为什么需要这么做?不能是同一个字向量吗? 2.tf.contrib.layers.embed_sequence转换的字向量每次都不同,例如每次ids = [1,2,3,4],每次调用该函数,转换的字向量都是不一样的。这样会有一个问题,相同的字对应的不同的字向量。 先谢谢了

NELSONZHAO commented 6 years ago

1.编码端和解码端是不同的任务,并且是不同的语料。例如encoder端是英文,decoder端是法语,分别对应两个不同的embedding去捕捉不同的信息。 2.这个问题麻烦再稍微描述更具体一些哈,我没太看懂。

liyonglion commented 6 years ago

例如第一次调用embed_sequence函数,传入的第一个参数是[1,2,3,4],返回的值为a。第二次再调用embed_sequence,同样传入[1,2,3,4],返回值b,此时a是不等于的b的吧~ 在问一个问题:在训练解码端,为什么要在target前面添加呢?不能直接使用target作为解码端的input吗?

NELSONZHAO commented 6 years ago

关于embed_sequence我去查了一下官方文档,对这一点没说明,我自己再terminal里开了个sess跑了一下确实不一样,这个写法我也是参考了别人的代码,如果你找到了关于embed_sequence的具体解析欢迎提下issue。 第二个问题:在训练解码端,要在target前面添加,这是因为在预测的时候模型并不知道第一个input是什么。也就是说,训练时候我们有target数据,所以可以将其作为input直接输入,但是预测阶段模型是不知道第一个词的,所以要给一个初始化的token。

liyonglion commented 6 years ago

我写的代码和你的差不多,但是我没有用tf.contrib.layers.embed_sequence,这个,而是使用tf.nn.embedding_lookup,第一个参数我使用变量共享。例如: def get_embedding(ids): with variable_scope('embedding',reuse=tf.AUTO_REUSE) : embedding = tf.get_variable('vocab', [vocab_size, embedding_size]) return tf.nn.embedding_lookup(embedding, ids) 第二个问题:在预测阶段是无法知道target的,也不能添加token,而是直接把编码的最后一个时间步骤 output作为解码的的输入,然后预测的。还是无法理解为什么在训练解码端,给target开头添加一个token。

NELSONZHAO commented 6 years ago

添加token这个我是看吴恩达的实现和Youtute上的一个实现写的,我觉得是合理的。吴恩达写的时候也是在Decoder端添加了一个0向量作为输入。其实这个就是类似于LSTM的initial state一样的东西,你要告诉它怎么开始。但是我觉得用Encoder端最后一个时间步的output作为输入不合理呀,如果是翻译问题,最后一个output单词对于Decoder端是没啥意义的。个人见解,欢迎讨论哈~

liyonglion commented 6 years ago

我并不认为最后的output 等效于单词,从LSTM的原型来看,当前的Ht = f(Ct,Xt),Ct = g(Ct-1,Xt),这里H表示输出,C表示状态,t表示时间步骤。可以从上面的简化公式理解:当前的输出,是综合了上一个状态(可以理解为记忆)和当前的输入,表示当从t0开始到tn输入的“理解”而已,当然可以用来预测当前的时间步输出单词而已,这里的预测也是用类似于全连接层,进行分类而已。

NELSONZHAO commented 6 years ago

Encoder-Decoder模型里面,本身学习到的context-vector就是对输入序列的信息抽取,我觉得你说的Encoder的输出和context-vector本身是高度相关的。从具体来说,如果给一个0向量作为Decoder的启动,那么其实相当于什么input信息都没给他,他能依赖的只有context-vector;如果按照你说的不加token,用Encoder的output给Decoder来启动,相当于增加了它的一部分启动信息,这么来看效果应该会好点,但是我始终认为这个output和context-vector是高度相关的。不过我还没尝试过,你这边用Encoder的output来启动Decoder有什么好的效果吗?

liyonglion commented 6 years ago

目前我还没有测试。我也是在前天加了token,这个我后面再试。目前我正在做文本摘要,从目前的训练结果来看,可以提取文章的中心思想,但是有些重要的词抓的不准确,有些头疼。不知道如何改进。context-vector这个词用的好传神。如果给一个0向量作为Decoder的启动,那么其实相当于什么input信息都没给他,他能依赖的只有context-vector这句话说的很有些道理。