zoukankan      html  css  js  c++  java
  • Seq2Seq

    rnn结构
    根据输出和输入序列不同数量rnn可以有多种不同的结构,不同结构自然就有不同的引用场合。

    one to one 结构,仅仅只是简单的给一个输入得到一个输出,此处并未体现序列的特征,例如图像分类场景。
    one to many 结构,给一个输入得到一系列输出,这种结构可用于生产图片描述的场景。
    many to one 结构,给一系列输入得到一个输出,这种结构可用于文本情感分析,对一些列的文本输入进行分类,看是消极还是积极情感。
    many to many 结构,给一些列输入得到一系列输出,这种结构可用于翻译或聊天对话场景,对输入的文本转换成另外一些列文本。
    同步 many to many 结构,它是经典的rnn结构,前一输入的状态会带到下一个状态中,而且每个输入都会对应一个输出,我们最熟悉的就是用于字符预测了,同样也可以用于视频分类,对视频的帧打标签。如图所示:

    在 many to many 的两种模型中,上图可以看到第四和第五种是有差异的,经典的rnn结构的输入和输出序列必须要是等长,它的应用场景比较有限。所谓 Seq2Seq,即Sequence to Sequence,就是指一般的序列到序列的转换任务,比如机器翻译、自动文摘等等,这种任务的特点是输入序列和输出序列是不对齐的,如果对齐的话,那么我们称之为序列标注,这就比 Seq2Seq 简单很多了。所以尽管序列标注任务也可以理解为序列到序列的转换,但我们在谈到 Seq2Seq 时,一般不包含序列标注。要自己实现 Seq2Seq,主要是搞懂 Seq2Seq 的原理和架构,用什么框架和语言都是很easy的。

    其主要特色就是encoder-decoder结构:

    基本思想就是利用两个RNN,一个RNN作为encoder,另一个RNN作为decoder。encoder负责将输入序列压缩成指定长度的向量,这个向量就可以看成是这个序列的语义,这个过程称为编码,如下图,获取语义向量最简单的方式就是直接将最后一个输入的隐状态作为语义向量C。也可以对最后一个隐含状态做一个变换得到语义向量,还可以将输入序列的所有隐含状态做一个变换得到语义变量。这个可选择的模型就很多了,用 GRU、LSTM 等 RNN 结构或者 CNN+Pooling、Google 的纯 Attention 等都可以,这个固定大小的向量,理论上就包含了输入句子的全部信息。

    而decoder则负责根据语义向量生成指定的序列,这个过程也称为解码,如下图,最简单的方式是将encoder得到的语义变量作为初始状态输入到decoder的rnn中,得到输出序列。可以看到上一时刻的输出会作为当前时刻的输入,而且其中语义向量C只作为初始状态参与运算,后面的运算都与语义向量C无关

     decoder处理方式还有另外一种,就是语义向量C参与了序列所有时刻的运算,如下图,上一时刻的输出仍然作为当前时刻的输入,但语义向量C会参与所有时刻的运算

    训练过程

    事实上,上图也表明了一般的 Seq2Seq 的训练过程。由于训练的时候我们有标注数据对,因此我们能提前预知 decoder 每一步的输入和输出,因此整个结果实际上是“输入 X 和 Y,预测 Y[1:],即将目标 Y 错开一位来训练。

    而 decoder 同样可以用 GRU、LSTM 或 CNN 等结构,但注意再次强调这种“预知未来”的特性仅仅在训练中才有可能,在预测阶段是不存在的,因此 decoder 在执行每一步时,不能提前使用后面步的输入。

    所以,如果用 RNN 结构,一般都只使用单向 RNN;如果使用 CNN 或者纯 Attention,那么需要把后面的部分给 mask 掉(对于卷积来说,就是在卷积核上乘上一个 0/1 矩阵,使得卷积只能读取当前位置及其“左边”的输入,对于 Attention 来说也类似,不过是对 query 的序列进行 mask 处理)。

    Beam Search 

    前面已经多次提到了解码过程,但还不完整。事实上,对于 Seq2Seq 来说,我们是在建模:

    显然在解码时,我们希望能找到最大概率的 Y,那要怎么做呢? 

    如果在第一步 p(Y1|X) 时,直接选择最大概率的那个(我们期望是目标 P),然后代入第二步 p(Y2|X,Y1),再次选择最大概率的 Y2,依此类推,每一步都选择当前最大概率的输出,那么就称为贪心搜索,是一种最低成本的解码方案。但是要注意,这种方案得到的结果未必是最优的,假如第一步我们选择了概率不是最大的 Y1,代入第二步时也许会得到非常大的条件概率 p(Y2|X,Y1),从而两者的乘积会超过逐位取最大的算法。然而,如果真的要枚举所有路径取最优,那计算量是大到难以接受的(这不是一个马尔可夫过程,动态规划也用不了)。因此,Seq2Seq 使用了一种折中的方法:Beam Search

    这种算法类似动态规划,但即使在能用动态规划的问题下,它还比动态规划要简单,它的思想是:在每步计算时,只保留当前最优的 topk 个候选结果。比如取 topk=3,那么第一步时,我们只保留使得 p(Y1|X) 最大的前 3 个 Y1,然后分别代入 p(Y2|X,Y1),然后各取前三个 Y2,这样一来我们就有3*3=9个组合了,这时我们计算每一种组合的总概率,然后还是只保留前三个,依次递归,直到出现了第一个<end>。显然,它本质上还属于贪心搜索的范畴,只不过贪心的过程中保留了更多的可能性,普通的贪心搜索相当于 topk=1。(这种方法值得借鉴)。

    先验知识:encoder 和 decoder 的 Embedding 层可以共享参数(也就是用同一套词向量)。这使得模型的参数量大幅度减少了。此外,还有一个很有用的先验知识:标题中的大部分字词都在文章中出现过(注:仅仅是出现过,并不一定是连续出现,更不能说标题包含在文章中,不然就成为一个普通的序列标注问题了)这样一来,我们可以用文章中的词集作为一个先验分布,加到解码过程的分类模型中,使得模型在解码输出时更倾向选用文章中已有的字词。

  • 相关阅读:
    [课程设计]任务进度条&开发日志目录
    《软件工程》课程设计-团队成立
    软件工程学期总结
    第三次冲刺及课程设计 617
    学术诚信与职业道德
    第二个冲刺
    操作系统 实验四主存空间的分配和回收
    0526 《构建之法》第8-10章读后感
    SCRUM项目 6.0
    SCRUM项目 5.0
  • 原文地址:https://www.cnblogs.com/limingqi/p/12669601.html
Copyright © 2011-2022 走看看