zoukankan      html  css  js  c++  java
  • seq2seq

    seq2seq:

    seq2seq就是将输入序列经过encoder-decoder变成目标序列。

        

    如图所示,输入序列是 [A, B, C, <EOS>],输出序列是  [W, X, Y, Z, <EOS>]

    encoder-decoder:

        主要过程就是用RNN对输入序列进行编码,然后再用RNN对上下文向量进行解码。

    实现方式:

    1、tf.nn.dynamic_rnn

        参考:https://github.com/ematvey/tensorflow-seq2seq-tutorials/blob/master/1-seq2seq.ipynb

        流程:

        输入序列: [A,B,C,EOS],其中A,B,C, EOS都要进行embedding,encoder部分的代码如下所示:

    encoder_cell = tf.contrib.rnn.LSTMCell(encoder_hidden_units)
    
    encoder_outputs, encoder_final_state = tf.nn.dynamic_rnn(
        encoder_cell, encoder_inputs_embedded,
        dtype=tf.float32, time_major=True,
    )
    

     encoder_outputs是一个时间步的输出,这个在decoder中用不到。encoder_final_stata是最后一层的输出结果,encoder_final_state是一个二元组,(整体的记忆c,隐藏层状态h),然后用encoder_final_state来初始化decoder的状态,而decoder的输入序列为 [EOS, A, B, C],因为dynamic_rnn不能根据上一步的输出来作为当前的输入,所以对于输入来说是固定,而非动态变化的。

    decoder_cell = tf.contrib.rnn.LSTMCell(decoder_hidden_units)
    
    decoder_outputs, decoder_final_state = tf.nn.dynamic_rnn(
        decoder_cell, decoder_inputs_embedded,
    
        initial_state=encoder_final_state,
    
        dtype=tf.float32, time_major=True, scope="plain_decoder",
    )
    

    2、tf.nn.raw_rnn

    这种方法不像dynamic_rnn那样固定,它比较灵活,可以通过迭代函数改变每一个时间步的 输入状态、输入。

    offical document 

    tf.nn.raw_rnn(
        cell, //基础神经元
        loop_fn, //迭代函数,每次的状态与输入都可以在这里定义
        parallel_iterations=None,
        swap_memory=False,
        scope=None
    )
    输出:
    (emit_ta, final_state, final_loop_state),其中emit_ta是TensorArray类型,其实就是每一个时间步输出的tensor的数组,final_state最后的状态,final_loop_state这个好像是None,不知道啥作用

     实现步骤

    整体:

    decoder_outputs_ta, decoder_final_state, _ = tf.nn.raw_rnn(decoder_cell, loop_fn) //decoder_cell是基础神经单元,loop_fn是迭代函数

    迭代函数:

    //迭代函数包含time, previous_output, previous_state, previous_loop_state(这个相当于LSTM中那个全局的记忆)
    def loop_fn(time, previous_output, previous_state, previous_loop_state):
    if previous_state is None: # time == 0, 初始化 assert previous_output is None and previous_state is None return loop_fn_initial() else: return loop_fn_transition(time, previous_output, previous_state, previous_loop_state) //在上一个时间步结束后,即将进入当前时间步时会执行该函数,目的就是确定要将哪些内容传给下一步作为状态输入和输入向量

    初始化函数:

    def loop_fn_initial():
        initial_elements_finished = (0 >= decoder_lengths)  # all False at the initial step
        initial_input = eos_step_embedded #第一步的输入是EOS
        initial_cell_state = encoder_final_state #状态输入就是encoder的最终输出状态,包括(c,h)
        initial_cell_output = None
        initial_loop_state = None  # we don't need to pass any additional information
        return (initial_elements_finished,
                initial_input,
                initial_cell_state,
                initial_cell_output,
                initial_loop_state)

    迭代函数:

    def loop_fn_transition(time, previous_output, previous_state, previous_loop_state):
        #如何获取上一步的输出
    yhat = softmax(previous_output * W + b)
    然后概率最大的那个yhat即为上一步的输出结果,并对这个结果进行embedding,作为下一步的输入

    def get_next_input(): output_logits
    = tf.add(tf.matmul(previous_output, W), b) prediction = tf.argmax(output_logits, axis=1) next_input = tf.nn.embedding_lookup(embeddings, prediction) return next_input
    #判断是否停止,常数 >= tensor向量,tensor中每个位置都要和常数进行比较,结果是一个布尔型的tensor向量 elements_finished
    = (time >= decoder_lengths) # this operation produces boolean tensor of [batch_size] # defining if corresponding sequence has ended #因为这是一个batch块,所以该batch完成的标志是 所有的item都finish,所以需要reduce_all finished = tf.reduce_all(elements_finished) # -> boolean scalar
    #当前步的输入 = 上一步的输出(get_next_input)
    #tf.cond(条件,True时调用的函数, False时调用的函数) input
    = tf.cond(finished, lambda: pad_step_embedded, get_next_input) state = previous_state #状态不用改变直接传过去 output = previous_output #previous_output也不用变,好像这个output是一个TensorArray吧? loop_state = None return (elements_finished, input, state, output, loop_state)

     调用过程:

    decoder_outputs_ta, decoder_final_state, _ = tf.nn.raw_rnn(decoder_cell, loop_fn)
    

     这样就实现了将上一步decoder出来的结果作为下一步的输入,真正实现上图中的过程。

    待补充Attention机制

    参考:

    https://github.com/ematvey/tensorflow-seq2seq-tutorials

    https://hanxiao.github.io/2017/08/16/Why-I-use-raw-rnn-Instead-of-dynamic-rnn-in-Tensorflow-So-Should-You-0/

  • 相关阅读:
    CSS:命名规范心得分享
    css中用一张背景图做页面的技术有什么优势?
    ie8 css hack
    简单介绍几个CSSReset的方法
    牛人也得看的CSS常识
    DIV+CSS网页布局常用的一些基础知识整理
    font-size:100%有什么作用?
    为什么无法定义1px左右高度的容器
    Div+CSS常见错误总结
    从数字千分位处理认识(?<=)、(?=)、(?:)
  • 原文地址:https://www.cnblogs.com/zhaopAC/p/10200742.html
Copyright © 2011-2022 走看看