循环神经网络系列(五)Tensorflow中BasicLSTMCell

1.结论

2.怎么来的?

让我们一步一步从Tensorflow的源码中来获得这些信息!

2.1 cell.state_size

首先,需要明白Tensorflow中,state表示的是cell中有几个状态。例如在BasicRNNCell中,state就只有h这一个状态;而在BasicLSTMCell中,state就有h和c这两个状态。其次,state_size表示的是每个状态的第二维度,也就是output_size。

import tensorflow as tf

output_size = 10
batch_size = 32
dim = 50
cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=output_size)
print(cell.state_size)

>>
LSTMStateTuple(c=10, h=10) 

LSTMStateTuple(c=10, h=10)就表示,c和h的output_size都为10,即[batch_size,10]。另外Tensorflow在实现的时候,都将c,h困在一起了,即以Tuple的方式,这也是Tensorflow所推荐的。

2.2 cell.zero_state

在LSTM中,zero_state就自然对应两个部分了,h0,c0

import tensorflow as tf

output_size = 10
batch_size = 32
dim = 50
cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=output_size)
input = tf.placeholder(dtype=tf.float32, shape=[batch_size, 50])
h0 = cell.zero_state(batch_size=batch_size, dtype=tf.float32)
print(h0)

>>
LSTMStateTuple(c=<tf.Tensor 'BasicLSTMCellZeroState/zeros:0' shape=(32, 10) dtype=float32>,
h=<tf.Tensor 'BasicLSTMCellZeroState/zeros_1:0' shape=(32, 10) dtype=float32>)

2.3 关键性的一步cell.call

先说明一点,由于源码很多,所有在下面的讲解中只会列出函数名和对应核心的代码,具体可以跳转至call的实现部分。

import tensorflow as tf

output_size = 10
batch_size = 32
dim = 50
cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=output_size)
input = tf.placeholder(dtype=tf.float32, shape=[batch_size, 50])
h0 = cell.zero_state(batch_size=batch_size, dtype=tf.float32)
new_h, new_state = cell.call(input, h0)


------------------------------------------------------------------


def call(self, inputs, state):
    if self._state_is_tuple:
        c, h = state
    concat = _linear([inputs, h], 4 * self._num_units, True)
    # i = input_gate, j = new_input, f = forget_gate, o = output_gate
    i, j, f, o = array_ops.split(value=concat, num_or_size_splits=4, axis=1)
    new_c = (
            c * sigmoid(f + self._forget_bias) + sigmoid(i) * self._activation(j))
    new_h = self._activation(new_c) * sigmoid(o)
    if self._state_is_tuple:
        new_state = LSTMStateTuple(new_c, new_h)
    else:
        new_state = array_ops.concat([new_c, new_h], 1)
    return new_h, new_state

首先,从call()中的第17行代码可知,首先从state中得到传进来的c,h,然后就开始进行第18行的操作了,为了弄清楚里面到底干了啥,于是我们再次进入_linear()这个函数。

总的来说,_linear()这个函数实现了:先将h,xh,xh,x进行concat,然后进行线性变换;如下图所示:


而与上面两个步骤对应代码就是下面的

concat = _linear([inputs, h], 4 * self._num_units, True)

def _linear(args,
            output_size,
            bias, # 是否要添加偏置
            bias_initializer=None,
            kernel_initializer=None):
            
    shapes = [a.get_shape() for a in args]# 得到传进来的inputs,h的shape
    total_arg_size += shape[1].value # 得到inputs和h一共有多少列
    res = math_ops.matmul(array_ops.concat(args, 1), weights)# 同时计算得到4个部分的线性映射

其中w_{i},w_{f},w_{j},w_{o}就是LSTM cell中的4个权重参数。

现在我们已经清楚了_linear()的作用,接下来我们就再次回到call()call()call()这个函数中:

def call(self, inputs, state):
    if self._state_is_tuple:
        c, h = state
    concat = _linear([inputs, h], 4 * self._num_units, True)
    # i = input_gate, j = new_input, f = forget_gate, o = output_gate
    i, j, f, o = array_ops.split(value=concat, num_or_size_splits=4, axis=1)
    new_c = (
            c * sigmoid(f + self._forget_bias) + sigmoid(i) * self._activation(j))
    new_h = self._activation(new_c) * sigmoid(o)
    if self._state_is_tuple:
        new_state = LSTMStateTuple(new_c, new_h)
    else:
        new_state = array_ops.concat([new_c, new_h], 1)
    return new_h, new_state

经过上面第4行代码,我们得到了4个部分线性变换后的结果;然后根据第6行代码可以看出,将concat又分割成了四个部分,而这四个部分对应关系如下图所示:

接着第7,9行代码就分别计算出了new_c,new_h

3. 总结

import tensorflow as tf

output_size = 10
batch_size = 32
dim = 50
cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=output_size)
input = tf.placeholder(dtype=tf.float32, shape=[batch_size, 50])
h0 = cell.zero_state(batch_size=batch_size, dtype=tf.float32)
new_h, new_state = cell.call(input, h0)


对于一个基本的LSTM cell,在定义的时候,通过上面第6行代码的num_units,第8行的batch_size和第7行的input我们就得到了cell中所有参数的shape。

对于LSTM按时间维度展开的方法和多层堆叠同BasicRNNCell一致,在此就不赘述,可参见本系列文章的(二)(三)。
 


​    

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值