tensorflow学习之BasicLSTMCell详解

tf.contrib.rnn.BasicLSTMCell
继承自:LayerRNNCell

Aliases:

Class tf.contrib.rnn.BasicLSTMCell
Class tf.nn.rnn_cell.BasicLSTMCell
基础的LSTM循环网络单元,基于http://arxiv.org/abs/1409.2329.实现。将forget_bias(默认值:1)添加到忘记门的偏差(biases)中以便在训练开始时减少以往的比例(scale)。该神经元不允许单元裁剪(cell clipping),投影层,也不使用peep-hole连接,它是一个基本的LSTM神经元。想要更高级的模型可以使用:tf.nn.rnn_cell.LSTMCell。

__init__(
 
    num_units,
 
    forget_bias=1.0,
 
    state_is_tuple=True,
 
    activation=None,
 
    reuse=None,
 
    name=None,
 
    dtype=None
 
)
参数说明:

num_units:int类型,LSTM单元中的神经元数量,即输出神经元数量
forget_bias:float类型,偏置增加了忘记门。从CudnnLSTM训练的检查点(checkpoin)恢复时,必须手动设置为0.0。
state_is_tuple:如果为True,则接受和返回的状态是c_state和m_state的2-tuple;如果为False,则他们沿着列轴连接。后一种即将被弃用。
activation:内部状态的激活函数。默认为tanh
reuse:布尔类型,描述是否在现有范围中重用变量。如果不为True,并且现有范围已经具有给定变量,则会引发错误。
name:String类型,层的名称。具有相同名称的层将共享权重,但为了避免错误,在这种情况下需要reuse=True.
dtype:该层默认的数据类型。默认值为None表示使用第一个输入的类型。在call之前build被调用则需要该参数。
源码:

class BasicLSTMCell(LayerRNNCell):
 
  """Basic LSTM recurrent network cell.
  The implementation is based on: http://arxiv.org/abs/1409.2329.
  We add forget_bias (default: 1) to the biases of the forget gate in order to
  reduce the scale of forgetting in the beginning of the training.
  It does not allow cell clipping, a projection layer, and does not
  use peep-hole connections: it is the basic baseline.
  For advanced models, please use the full @{tf.nn.rnn_cell.LSTMCell}
  that follows.
  """
 
 
 
  def __init__(self, num_units, forget_bias=1.0,
               state_is_tuple=True, activation=None, reuse=None, name=None):
 
    """初始化基础的 LSTM cell.
    Args:
      num_units:int类型,LSTM单元中的神经元数量,即输出神经元数量
forget_bias:float类型,偏置增加了忘记门。从CudnnLSTM训练的检查点(checkpoin)恢复时,必须手动设置为0.0。
state_is_tuple:如果为True,则接受和返回的状态是c_state和m_state的2-tuple;如果为False,则他们沿着列轴连接。后一种即将被弃用。
activation:内部状态的激活函数。默认为tanh
reuse:布尔类型,描述是否在现有范围中重用变量。如果不为True,并且现有范围已经具有给定变量,则会引发错误。
name:String类型,层的名称。具有相同名称的层将共享权重,但为了避免错误,在这种情况下需要reuse=True.
      When restoring from CudnnLSTM-trained checkpoints, must use
      `CudnnCompatibleLSTMCell` instead.
    """
 
    super(BasicLSTMCell, self).__init__(_reuse=reuse, name=name)
 
    if not state_is_tuple:
 
      logging.warn("%s: Using a concatenated state is slower and will soon be "
 
                   "deprecated.  Use state_is_tuple=True.", self)
 
 
 
    # Inputs must be 2-dimensional.
 
    self.input_spec = base_layer.InputSpec(ndim=2)
 
 
 
    self._num_units = num_units
 
    self._forget_bias = forget_bias
 
    self._state_is_tuple = state_is_tuple
 
    self._activation = activation or math_ops.tanh
 
 
 
  @property
 
  def state_size(self):
 
    return (LSTMStateTuple(self._num_units, self._num_units)
 
            if self._state_is_tuple else 2 * self._num_units)
 
 
 
  @property
 
  def output_size(self):
 
    return self._num_units
 
 
 
  def build(self, inputs_shape):
 
    if inputs_shape[1].value is None:
 
      raise ValueError("Expected inputs.shape[-1] to be known, saw shape: %s"
 
                       % inputs_shape)
 
 
 
    input_depth = inputs_shape[1].value
 
    h_depth = self._num_units
 
    self._kernel = self.add_variable(
 
        _WEIGHTS_VARIABLE_NAME,
 
        shape=[input_depth + h_depth, 4 * self._num_units])
 
    self._bias = self.add_variable(
 
        _BIAS_VARIABLE_NAME,
 
        shape=[4 * self._num_units],
 
        initializer=init_ops.zeros_initializer(dtype=self.dtype))
 
 
 
    self.built = True
 
 
 
  def call(self, inputs, state):
 
    """Long short-term memory cell (LSTM).
    Args:
      inputs: `2-D` tensor with shape `[batch_size, input_size]`.
      state: An `LSTMStateTuple` of state tensors, each shaped
        `[batch_size, self.state_size]`, if `state_is_tuple` has been set to
        `True`.  Otherwise, a `Tensor` shaped
        `[batch_size, 2 * self.state_size]`.
    Returns:
      A pair containing the new hidden state, and the new state (either a
        `LSTMStateTuple` or a concatenated state, depending on
        `state_is_tuple`).
    """
 
    sigmoid = math_ops.sigmoid
 
    one = constant_op.constant(1, dtype=dtypes.int32)
 
    # Parameters of gates are concatenated into one multiply for efficiency.
 
    if self._state_is_tuple:
 
      c, h = state
 
    else:
 
      c, h = array_ops.split(value=state, num_or_size_splits=2, axis=one)
 
 
 
    gate_inputs = math_ops.matmul(
 
        array_ops.concat([inputs, h], 1), self._kernel)
 
    gate_inputs = nn_ops.bias_add(gate_inputs, self._bias)
 
 
 
    # i = input_gate, j = new_input, f = forget_gate, o = output_gate
 
    i, j, f, o = array_ops.split(
 
        value=gate_inputs, num_or_size_splits=4, axis=one)
 
 
 
    forget_bias_tensor = constant_op.constant(self._forget_bias, dtype=f.dtype)
 
    # Note that using `add` and `multiply` instead of `+` and `*` gives a
 
    # performance improvement. So using those at the cost of readability.
 
    add = math_ops.add
 
    multiply = math_ops.multiply
 
    new_c = add(multiply(c, sigmoid(add(f, forget_bias_tensor))),
 
                multiply(sigmoid(i), self._activation(j)))
 
    new_h = multiply(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
 
实现了下面的操作:

tensorflow学习之BasicLSTMCell详解_第1张图片

用公式表示就是:

tensorflow学习之BasicLSTMCell详解_第2张图片

从图片和公式可知,LSTM单元有单个输入(Ct-1,ht-1,xt),三个输出(Ct,ht,ht)。

构造函数init有个state_is_tuple=True,如果为True,则接受和返回的状态是c_state和m_state的2-tuple;如果为False,则他们沿着列轴连接。

if self._state_is_tuple:
  new_state = LSTMStateTuple(new_c, new_h)
else:
  new_state = array_ops.concat([new_c, new_h], 1)
LSTM单元的隐藏状态是(Ct,ht)元组。

再来看call函数,下面这一行代码就是计算遗忘门、输入门、和输出门(未经过激活函数)。

# i = input_gate, j = new_input, f = forget_gate, o = output_gate
 
    i, j, f, o = array_ops.split(
 
        value=gate_inputs, num_or_size_splits=4, axis=one)
计算输出Ct和ht:

new_c = add(multiply(c, sigmoid(add(f, forget_bias_tensor))),
 
                multiply(sigmoid(i), self._activation(j)))
 
    new_h = multiply(self._activation(new_c), sigmoid(o))

代码实例:

import tensorflow as tf
 
 
 
output_dim=128
 
lstm=tf.nn.rnn_cell.BasicLSTMCell(output_dim)
 
batch_size=10 #批处理大小
 
timesteps=40 #时间步长
 
embedding_dim=300 #词向量维度
 
inputs=tf.Variable(tf.random_normal([batch_size,embedding_dim]))
 
previous_state = (tf.random_normal(shape=(batch_size, output_dim)), tf.random_normal(shape=(batch_size, output_dim)))
 
output,(new_h, new_state)=lstm(inputs,previous_state)
 
 
 
print(output.shape) #(10, 128)
 
print(new_h.shape) #(10, 128)
 
print(new_state.shape) #(10, 128)
 



关于tensorflow里面的tf.contrib.rnn.BasicLSTMCell 中num_units参数问题

这里的num_units参数并不是指这一层油多少个相互独立的时序lstm,而是lstm单元内部的几个门的参数,这几个门其实内部是一个神经网络,答案来自知乎: 
tensorflow学习之BasicLSTMCell详解_第3张图片
tensorflow学习之BasicLSTMCell详解_第4张图片

class TRNNConfig(object):
    """RNN配置参数"""

    # 模型参数
    embedding_dim = 100      # 词向量维度
    seq_length = 100        # 序列长度
    num_classes = 2        # 类别数
    vocab_size = 10000       # 词汇表达小

    num_layers= 2           # 隐藏层层数
    hidden_dim = 128        # 隐藏层神经元
    rnn = 'lstm'             # lstm 或 gru

    dropout_keep_prob = 0.8 # dropout保留比例
    learning_rate = 1e-3    # 学习率

    batch_size = 128         # 每批训练大小
    num_epochs = 5          # 总迭代轮次

    print_per_batch = 20    # 每多少轮输出一次结果
    save_per_batch = 10      # 每多少轮存入tensorboard


class TextRNN(object):
    """文本分类,RNN模型"""
    def __init__(self, config):
        self.config = config

        # 三个待输入的数据
        self.input_x = tf.placeholder(tf.int32, [None, self.config.seq_length], name='input_x')
        self.input_y = tf.placeholder(tf.float32, [None, self.config.num_classes], name='input_y')
        self.keep_prob = tf.placeholder(tf.float32, name='keep_prob')

        self.rnn()

    def rnn(self):
        """rnn模型"""

        def lstm_cell():   # lstm核
            return tf.contrib.rnn.BasicLSTMCell(self.config.hidden_dim, state_is_tuple=True)

        def gru_cell():  # gru核
            return tf.contrib.rnn.GRUCell(self.config.hidden_dim)

        def dropout():  # 为每一个rnn核后面加一个dropout层
            if (self.config.rnn == 'lstm'):
                cell = lstm_cell()
            else:
                cell = gru_cell()
            return tf.contrib.rnn.DropoutWrapper(cell, output_keep_prob=self.keep_prob)

        # 词向量映射
        with tf.device('/cpu:0'):
            embedding = tf.get_variable('embedding', [self.config.vocab_size, self.config.embedding_dim])
            embedding_inputs = tf.nn.embedding_lookup(embedding, self.input_x)

        with tf.name_scope("rnn"):
            # 多层rnn网络
            cells = [dropout() for _ in range(self.config.num_layers)]
            rnn_cell = tf.contrib.rnn.MultiRNNCell(cells, state_is_tuple=True)

            _outputs, _ = tf.nn.dynamic_rnn(cell=rnn_cell, inputs=embedding_inputs, dtype=tf.float32)
            last = _outputs[:, -1, :]  # 取最后一个时序输出作为结果
            # last = _outputs  # 取最后一个时序输出作为结果

        with tf.name_scope("score"):
            # 全连接层,后面接dropout以及relu激活
            fc = tf.layers.dense(last, self.config.hidden_dim, name='fc1')
            fc = tf.contrib.layers.dropout(fc, self.keep_prob)
            fc = tf.nn.relu(fc)

            # 分类器
            self.logits = tf.layers.dense(fc, self.config.num_classes, name='fc2')
            self.y_pred_cls = tf.argmax(tf.nn.softmax(self.logits), 1)  # 预测类别

        with tf.name_scope("optimize"):
            # 损失函数,交叉熵
            cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.input_y)
            self.loss = tf.reduce_mean(cross_entropy)
            # 优化器
            self.optim = tf.train.AdamOptimizer(learning_rate=self.config.learning_rate).minimize(self.loss)

        with tf.name_scope("accuracy"):
            # 准确率
            correct_pred = tf.equal(tf.argmax(self.input_y, 1), self.y_pred_cls)
            self.acc = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

前言
关于LSTM原理: http://colah.github.io/posts/2015-08-Understanding-LSTMs/
关于LSTM原理(译文):https://blog.csdn.net/Jerr__y/article/details/58598296
关于Tensorflow+LSTM的使用:https://www.knowledgemapper.com/knowmap/knowbook/[email protected](MNISTdataset)
关于Tensorflow+LSTM的使用(译文):https://yq.aliyun.com/articles/202939
正文
本文只是介绍tensorflow中的BasicLSTMCell中num_units,关于LSTM和如何使用请看前言的教程。
在使用Tensorflow跑LSTM的试验中, 有个num_units的参数,这个参数是什么意思呢?

先总结一下,num_units这个参数的大小就是LSTM输出结果的维度。例如num_units=128, 那么LSTM网络最后输出就是一个128维的向量。

我们先换个角度举个例子,最后再用公式来说明。

假设在我们的训练数据中,每一个样本 x 是 28*28 维的一个矩阵,那么将这个样本的每一行当成一个输入,通过28个时间步骤展开LSTM,在每一个LSTM单元,我们输入一行维度为28的向量,如下图所示。

tensorflow学习之BasicLSTMCell详解_第5张图片
那么,对每一个LSTM单元,参数 num_units=128 的话,就是每一个单元的输出为 128*1 的向量,在展开的网络维度来看,如下图所示,对于每一个输入28维的向量,LSTM单元都把它映射到128维的维度, 在下一个LSTM单元时,LSTM会接收上一个128维的输出,和新的28维的输入,处理之后再映射成一个新的128维的向量输出,就这么一直处理下去,知道网络中最后一个LSTM单元,输出一个128维的向量。

tensorflow学习之BasicLSTMCell详解_第6张图片
从LSTM的公式的角度看是什么原理呢?我们先看一下LSTM的结构和公式:

tensorflow学习之BasicLSTMCell详解_第7张图片
参数 num_units=128 的话,

对于公式 (1) ,h=128∗1 h=128*1h=128∗1维, x=28∗1 x=28*1x=28∗1 维,[h,x]便等于156∗1 156*1156∗1维,W=128∗156 W=128*156W=128∗156 维,所以 W∗[h,x]=128∗156∗156∗1=128∗1,b=128∗1 W*[h,x]=128*156 * 156*1=128*1, b=128*1W∗[h,x]=128∗156∗156∗1=128∗1,b=128∗1 维, 所以 f=128∗1+128∗1=128∗1 f=128*1+128*1=128*1f=128∗1+128∗1=128∗1 维;
对于公式 (2) 和 (3),同上可分析得 i=128∗1 i=128*1i=128∗1 维,C˜=128∗1 \widetilde{C}=128*1 
C
 =128∗1 维;
对于公式 (4) ,f(t)=128∗1,C(t−1)=128∗1,f(t).∗C(t−1)=128∗1.∗128∗1=128∗1 f(t)=128*1, C(t-1)=128*1, f(t) .* C(t-1) = 128*1 .* 128*1 = 128*1f(t)=128∗1,C(t−1)=128∗1,f(t).∗C(t−1)=128∗1.∗128∗1=128∗1 , 同理可得 C(t)=128∗1 C(t)=128*1C(t)=128∗1 维;
对于公式 (5) 和 (6) , 同理可得 O=128∗1 O=128*1O=128∗1 维, h=O.∗tanh(C)=128∗1 h=O.*tanh(C)=128*1h=O.∗tanh(C)=128∗1 维。
所以最后LSTM单元输出的h就是 128∗1 128*1128∗1 的向量。

以上就是 num_units 参数的含义。

如有错误请指出谢谢

参考链接:
https://stackoverflow.com/questions/37901047/what-is-num-units-in-tensorflow-basiclstmcell
https://www.zhihu.com/question/64470274
--------------------- 

原文:https://blog.csdn.net/notHeadache/article/details/81164264 

原文:https://blog.csdn.net/u013230189/article/details/82808362 

         https://blog.csdn.net/u014518506/article/details/80445283

你可能感兴趣的:(深度学习,TensorFlow)