循环神经网络系列之ConvLSTMCell在TensorFlow中的应用

前面一文​我们简单得介绍了​​ConvLSTM​​​得原理和应用场景,现在来看看在​​Tensorflow​​​它具体是如何实现得。 值得一说得是​​Tensorflow​​​在实现这个算法得时候并没有使用​​peepholes​​​,即下面的红色部分,而是基于原始的LSTM网络结构改变的。不过在最后,我也会给出一个仿照Tensorflow实现的基于​​peepholes​​的ConvLSTM版本。



循环神经网络系列(七)Tensorflow中ConvLSTMCell_卷积



1.用法

在接受具体用法前,先来大致解释一下参数。由于该算法是CNN与LSTM的一个结合,所以在说到对其中各个参数理解的时候,我会将其类比于CNN和LSTM中对应的参数。



def __init__(self,               conv_ndims,               input_shape,               
output_channels,               kernel_shape,               use_bias=True,              
skip_connection=False,               forget_bias=1.0,               
initializers=None,               name="conv_lstm_cell"):1.2.3.4.5.6.7.8.9.10.


参数:

​conv_ndims:​​卷积维度,对于平面卷积来说都为2,例如图片的卷积处理;

​input_shape:​​输入维度(除去batch_size),例如当​​conv_ndims=2​​时,输入维度就应该为​​[weight,high,channel]​​,最简单的就是将它想象成一个图片;

​output_channels:​​最终输出时的深度;就像是在​​conv2d​​中卷积核的深度一样,它决定了最终提取特征后的图像的深度

​kernel_shape:​​卷积核的平面大小例如​​[3,3]​​;熟悉​​conv2d​​的都知道卷积核的维度应该是4,这儿怎么才2,原因就是剩下的两个维度直接通过计算就可以得到,这部分在​​ConvLSTM​​的内部实现中完成

​use_bias:​​这个很好理解,是否要使用偏置



剩下的参数保持默认就好。



1.1 单个单元​​cell.call()​

import tensorflow.contrib as contribimport tensorflow as tfinputs = tf.placeholder(dtype=tf.float32, 
shape=[64, 10, 10, 28])  # [batch_size,width,high,channeals] cell = contrib.rnn.ConvLSTMCell(conv_ndims=2, 
input_shape=[10, 10, 28], output_channels=6, kernel_shape=[3, 3])initial_state = cell.zero_state(batch_size=64
dtype=tf.float32)output, final_state=cell.call(inputs=inputs,
state=initial_state)print(output)print(final_state)>>Tensor("mul_2:0", shape=(64, 10, 10, 6), 
dtype=float32)LSTMStateTuple(c=<tf.Tensor 'add_2:0' shape=(64, 10, 10, 6) dtype=float32>, h=<tf.
Tensor 'mul_2:0' shape=(64, 10, 10, 6) dtype=float32>)1.2.3.4.5.6.7.8.9.10.11.12.13.



循环神经网络系列(七)Tensorflow中ConvLSTMCell_卷积_02

从图中我们可以看到每个输出结果的维度是由哪些参数所确定的。



1.2 按时间维度展开​​dynamic_rnn()​

inputs = tf.placeholder(dtype=tf.float32, shape=[64, 100, 10, 10, 28])  # [batch_size,time_setp,width,high,channeals] 5Dcell = contrib.rnn.ConvLSTMCell(conv_ndims=2, input_shape=[10, 10, 28], output_channels=6, kernel_shape=[3, 3])initial_state = cell.zero_state(batch_size=64, dtype=tf.float32)output, final_state = tf.nn.dynamic_rnn(cell, inputs, dtype=tf.float32, time_major=False, initial_state=initial_state)print(output)print(final_state)>>Tensor("rnn/transpose_1:0", shape=(64, 100, 10, 10, 6), dtype=float32)LSTMStateTuple(c=<tf.Tensor 'rnn/while/Exit_3:0' shape=(64, 10, 10, 6) dtype=float32>, h=<tf.Tensor 'rnn/while/Exit_4:0' shape=(64, 10, 10, 6) dtype=float32>)1.2.3.4.5.6.7.8.9.10.

同其它RNN一样,在使用​​dynamic_rnn​​​时​​inputs​​​接受两种形式的输入,并且通过参数​​time_major​​​来控制。如果inputs的​​shape=[time_setp,batch_size,width,high,channeals]​​​,则必须有​​time_major=True​​​。同时,从上面的代码可知,在时间轴上的展开有100个,所以最后输出​​shape=(64, 100, 10, 10, 6)​​​表示的含义是100个单元,每个单元对应输出部分的大小为​​[64,10,10,6]​​。

2.Tensorflow中的实现细节

接下来,我们就来大致看看​​ConvLSTM​​​的内部实现部分。同RNN、LSTM一样,其核心部分都是在于实现​​call()​​​这个类方法,然后通过调用​​call()​​​来完成一次前向传播的任务。而对应​​call()​​​这个方法来说,其核心部分就是里面的卷积操作(由​​_conv()​​这个函数来实现),当计算得到卷积后的结果后,剩下的就是各种激活函数的线性组合了,如下:

def call(self, inputs, state, scope=None):    cell, hidden = state    new_hidden = _conv([inputs, hidden],                       self._kernel_shape,                       4*self._output_channels,                       self._use_bias)    input_gate, new_input, forget_gate, output_gate = gates    new_cell = math_ops.sigmoid(forget_gate + self._forget_bias) * cell    new_cell += math_ops.sigmoid(input_gate) * math_ops.tanh(new_input)    output = math_ops.tanh(new_cell) * math_ops.sigmoid(output_gate)    new_state = rnn_cell_impl.LSTMStateTuple(new_cell, output)    return output, new_state1.2.3.4.5.6.7.8.9.10.11.12.13.

所以此时的关注的重点就转移到了​​_conv()​​这个函数上来了。同时我们知道,在写卷积网络的时候,我们需要指定每一个卷积核的shape,可是在ConvLSTM中似乎并没有完全指定,这到底怎么回事呢?

由前面的的计算公式可知一共应该有8个卷积核,分别是 w x i , w h i , w x f , w h f , w x c , w h c , w x o , w h o w_{xi},w_{hi},w_{xf},w_{hf},w_{xc},w_{hc},w_{xo},w_{ho} wxi,whi,wxf,whf,wxc,whc,wxo,who。假设我们现在输入的形状​​input:[1,10,10,28],output_channels=2,kernel_size=[3,3]​​,则按照一般思路我们应该是进行如下计算(进行8次卷积操作)。



循环神经网络系列(七)Tensorflow中ConvLSTMCell_卷积核_03

有没有发现这样计算太麻烦了,我在画图的时候都觉得麻烦。不过Tensorflow的实现从来没让我们失望过,其在实现的时候同样采用了先叠加,然后进行卷积的原则,大大减少了计算复杂程度:



循环神经网络系列(七)Tensorflow中ConvLSTMCell_卷积核_04

new_hidden = _conv([inputs, hidden],                   self._kernel_shape,                   4*self._output_channels,                   self._use_bias)---------------------------------------------------------------------------def _conv(args, filter_size, num_features, bias, bias_start=0.0):    total_arg_size_depth = 0    shapes = [a.get_shape().as_list() for a in args]        shape_length = len(shapes[0])# 得到args[0],也就是inputs的维度    total_arg_size_depth += shape[-1]    kernel = vs.get_variable(      "kernel",      filter_size + [total_arg_size_depth, num_features],      dtype=dtype)    res = conv_op(array_ops.concat(axis=shape_length-1, values=args),              kernel,              strides,              padding='SAME')1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.

如上代码所示:

第3行对应的即使计算图p0048中的8;

第11行对应的就是计算图p0048中的30;

第17行中的​​concat​​对应的就是将图p0048中的 x , H x,H x,H堆叠起来;

从以上代码我们也确实可以发现,Tensorflow在实现ConvLSTM时,确实基于的是原始的LSTM。

3.Tensorflow实现基于’peepholes LSTM’的ConvLSTM

由于​​contrib.rnn.ConvLSTMCell​​中对于​​ConvLSTMCell​​的实现本没有基于原作者的所引用的带有 "peepholes connection"的LSTM。因此,这里就照着葫芦画瓢,直接在原来的​​contrib.rnn.ConvLSTMCell​​的​​call()​​实现中上添加了​​peepholes​​这一步。

添加的代码为:

w_ci = vs.get_variable(            "w_ci", cell.shape, inputs.dtype)        w_cf = vs.get_variable(            "w_cf", cell.shape, inputs.dtype)        w_co = vs.get_variable(            "w_co", cell.shape, inputs.dtype)        new_cell = math_ops.sigmoid(forget_gate + self._forget_bias + w_cf * cell) * cell        new_cell += math_ops.sigmoid(input_gate + w_ci * cell) * math_ops.tanh(new_input)        output = math_ops.tanh(new_cell) * math_ops.sigmoid(output_gate + w_co * new_cell)1.2.3.4.5.6.7.8.9.10.

引用时,将 ​​ConvLSTM​​​中的​​BasicConvLSTM​​导入即可:

from ConvLSTM import BasicConvLSTM1.

用法同​​ConvLSTMCell​​一模一样!


免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空