Skip to main content
 首页 » 编程设计

python之Tensorflow:使用不同的 "call"函数创建 LSTM 单元的自定义子类

2025年02月15日28tuyile006

当前对输入序列使用 dynamic_rnn 会返回输出序列和最后的单元状态。

对于手头的任务(可以在序列中的任何索引处开始/结束的截断后向传播),我不仅需要访问最后一个单元状态,还需要访问整个中间状态序列.快速在线查看我发现了以下线程:

https://github.com/tensorflow/tensorflow/issues/5731

线程建议最好的办法是扩展原始 LSTM 单元的功能,让它返回整个状态作为输出的一部分,因此调用 dynamic_rnn 的第一个返回值也将包含输出序列。

编辑 3:

在网上四处寻找解决方案 4 小时后,看来我需要更新 output_size 属性。这是更新后的代码:

class SSLSTMCell(tf.contrib.rnn.LSTMCell): 
  @property 
  def output_size(self): 
    return self.state_size * 2 
 
  def __call__(self, inputs, state): 
    cell_out, cell_state = super(SSLSTMCell, self).__call__(inputs, state) 
    together = tf.concat([cell_state.c, cell_state.h], axis=1) 
    return together, cell_state 

我想为 stackedLSTM 实现类似的结果,我会使用相同的技巧,修改 __call__ 函数并修改 output_size。

但是,这样做我遇到了一个真正的问题,现在“输出”是所有内容的串联并且丢失了元组的结构,因为我看不到在保留元组结构的同时让它工作的方法.我知道我可以执行一些 reshape 以使它们回到元组形式,然后可以再次将其用作 stackedLSTM 的初始状态,但如果无论如何都可以保留元组结构,那就太好了。

可能提供上下文但可能不再与讨论相关的旧编辑

This is what I have done so far:

class SSLSTMCell(tf.contrib.rnn.LSTMCell): 
 
  def call(self, inputs, state): 
    cell_out, cell_state = super(SSLSTMCell, self).call(inputs, state) 
    return cell_state, cell_state 

As you can see, instead of outputting the (output, state) tuple at each time-step I'm simply outputting the (state, state) output, which would give me the capability of accessing all the intermediate states.

However, it doesn't seem like the "call" function of my custom sub-class SSLSTMCell is being invoked at all during the dynamic_rnn function call, indeed when I try to put an "assert 0" in the body of the call function my program doesn't crash.

So what could be wrong? I looked up the implementation on dynamic_rnn the "call"function is definitely being used, but somehow it doesn't use the one defined by my custom sub-class

Thanks in advance.

edit 1:

It seems I should put some under-scores on the "call" function, I am not sure why but this is my updated code:

class SSLSTMCell(tf.contrib.rnn.LSTMCell): 
  def __call__(self, inputs, state): 
    cell_out, cell_state = super(SSLSTMCell, self).__call__(inputs, state) 
    return cell_state, cell_state 

This worked out better as the "__call__" function is being called this time (putting an assert 0 inside this function crashes python). However, I am getting a different error:

  File "/home/evan/tensorflow/local/lib/python2.7/site-packages/tensorflow/contrib/rnn/python/ops/core_rnn_cell_impl.py", 

line 655, in call cur_inp, new_state = cell(cur_inp, cur_state) File "try1.py", line 10, in call cell_out, cell_state = super(SSLSTMCell, self).call(inputs, state) File "/home/evan/tensorflow/local/lib/python2.7/site-packages/tensorflow/contrib/rnn/python/ops/core_rnn_cell_impl.py", line 327, in call input_size = inputs.get_shape().with_rank(2)[1] AttributeError: 'LSTMStateTuple' object has no attribute 'get_shape'

edit 2:

It seems the output must be a regular tensor for the next step of the computation, and a LSTM-Tuple-State is a tuple of tensors. So I tried putting them together

class SSLSTMCell(tf.contrib.rnn.LSTMCell): 
  def __call__(self, inputs, state): 
    cell_out, cell_state = super(SSLSTMCell, self).__call__(inputs, state) 
    together = tf.concat([cell_state.c, cell_state.h], axis=1) 
    return together, cell_state 

However now I have a different error:

ValueError: Dimension 1 in both shapes must be equal, but are 10 and 20 for 'rnn/while/Select' (op: 'Select') with input shapes: [?], 

Clearly the framework does not expect an output to be suddenly bigger... But I do not understand why that should be the case, shouldn't ouput simply be output and has no bearing on the computation? This is very confusing why "output" should affect the computation.

Is this simply a bad idea of trying to extend the LSTMCell class to do what I wanted to do? I do like the interfact to dynamic_rnn but if I could just get to the intermediate states...

请您参考如下方法:

似乎没有一种简单的方法来保存元组。似乎 RNNCell 子类的用户假设输出是大小为 [batch x output_size] 的二维张量。我认为他们不会使用元组。此外,恢复原始值应该很简单 c, h = tf.split(c, num_or_size_splits=2, axis=1)