web-dev-qa-db-fra.com

Que sont c_state et m_state dans Tensorflow LSTM?

La documentation de tensorflow r0.12 pour tf.nn.rnn_cell.LSTMCell décrit cela comme l'init:

tf.nn.rnn_cell.LSTMCell.__call__(inputs, state, scope=None)

state est la suivante:

state: si state_is_Tuple est à False, il doit s'agir d'un état tensor, 2D, lot x taille_état. Si state_is_Tuple a la valeur True, il doit s'agir d'un tuple d'état, tous deux bidimensionnels, de tailles de colonne c_state et m_state.

Qu'est-ce qu'un c_state et un m_state et comment s'intègrent-ils dans les LSTM? Je ne trouve aucune référence à ces documents dans la documentation.

Voici un lien vers cette page dans la documentation.

15
Haziq Nordin

Je suis tombé sur la même question, voici comment je le comprends! Exemple de LSTM minimaliste:

import tensorflow as tf

sample_input = tf.constant([[1,2,3]],dtype=tf.float32)

LSTM_CELL_SIZE = 2

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(LSTM_CELL_SIZE, state_is_Tuple=True)
state = (tf.zeros([1,LSTM_CELL_SIZE]),)*2

output, state_new = lstm_cell(sample_input, state)

init_op = tf.global_variables_initializer()

sess = tf.Session()
sess.run(init_op)
print sess.run(output)

Notez que state_is_Tuple=True donc lorsque vous passez state à cette cell, il doit être sous la forme Tuple. c_state et m_state sont probablement "Etat de la mémoire" et "Etat de la cellule", bien que je ne sois honnêtement pas sûr, car ces termes ne sont mentionnés que dans la documentation. Dans le code et les articles sur LSTM - les lettres h et c sont couramment utilisées pour désigner "valeur de sortie" et "état de cellule" . http://colah.github.io/posts/2015-08-Understanding- LSTMs/ Ces tenseurs représentent l'état interne combiné de la cellule et doivent être transmis ensemble. L'ancienne façon de le faire était simplement de les concaténer, et une nouvelle façon consiste à utiliser des n-uplets.

VIEILLE VOIE:

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(LSTM_CELL_SIZE, state_is_Tuple=False)
state = tf.zeros([1,LSTM_CELL_SIZE*2])

output, state_new = lstm_cell(sample_input, state)

NOUVELLE FAÇON:

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(LSTM_CELL_SIZE, state_is_Tuple=True)
state = (tf.zeros([1,LSTM_CELL_SIZE]),)*2

output, state_new = lstm_cell(sample_input, state)

Donc, pratiquement tout ce que nous avons fait, la variable state est remplacée par 1 tenseur de longueur 4 en deux tenseurs de longueur 2. Le contenu est resté le même. [0,0,0,0] devient ([0,0],[0,0]). (Ceci est censé le rendre plus rapide)

12
avloss

Je conviens que la documentation n'est pas claire. En regardant tf.nn.rnn_cell.LSTMCell.__call__ clarifie (j'ai pris le code de TensorFlow 1.0.0):

def __call__(self, inputs, state, scope=None):
    """Run one step of LSTM.

    Args:
      inputs: input Tensor, 2D, batch x num_units.
      state: if `state_is_Tuple` is False, this must be a state Tensor,
        `2-D, batch x state_size`.  If `state_is_Tuple` is True, this must be a
        Tuple of state Tensors, both `2-D`, with column sizes `c_state` and
        `m_state`.
      scope: VariableScope for the created subgraph; defaults to "lstm_cell".

    Returns:
      A Tuple containing:

      - A `2-D, [batch x output_dim]`, Tensor representing the output of the
        LSTM after reading `inputs` when previous state was `state`.
        Here output_dim is:
           num_proj if num_proj was set,
           num_units otherwise.
      - Tensor(s) representing the new state of LSTM after reading `inputs` when
        the previous state was `state`.  Same type and shape(s) as `state`.

    Raises:
      ValueError: If input size cannot be inferred from inputs via
        static shape inference.
    """
    num_proj = self._num_units if self._num_proj is None else self._num_proj

    if self._state_is_Tuple:
      (c_prev, m_prev) = state
    else:
      c_prev = array_ops.slice(state, [0, 0], [-1, self._num_units])
      m_prev = array_ops.slice(state, [0, self._num_units], [-1, num_proj])

    dtype = inputs.dtype
    input_size = inputs.get_shape().with_rank(2)[1]
    if input_size.value is None:
      raise ValueError("Could not infer input size from inputs.get_shape()[-1]")
    with vs.variable_scope(scope or "lstm_cell",
                           initializer=self._initializer) as unit_scope:
      if self._num_unit_shards is not None:
        unit_scope.set_partitioner(
            partitioned_variables.fixed_size_partitioner(
                self._num_unit_shards))
      # i = input_gate, j = new_input, f = forget_gate, o = output_gate
      lstm_matrix = _linear([inputs, m_prev], 4 * self._num_units, bias=True,
                            scope=scope)
      i, j, f, o = array_ops.split(
          value=lstm_matrix, num_or_size_splits=4, axis=1)

      # Diagonal connections
      if self._use_peepholes:
        with vs.variable_scope(unit_scope) as projection_scope:
          if self._num_unit_shards is not None:
            projection_scope.set_partitioner(None)
          w_f_diag = vs.get_variable(
              "w_f_diag", shape=[self._num_units], dtype=dtype)
          w_i_diag = vs.get_variable(
              "w_i_diag", shape=[self._num_units], dtype=dtype)
          w_o_diag = vs.get_variable(
              "w_o_diag", shape=[self._num_units], dtype=dtype)

      if self._use_peepholes:
        c = (sigmoid(f + self._forget_bias + w_f_diag * c_prev) * c_prev +
             sigmoid(i + w_i_diag * c_prev) * self._activation(j))
      else:
        c = (sigmoid(f + self._forget_bias) * c_prev + sigmoid(i) *
             self._activation(j))

      if self._cell_clip is not None:
        # pylint: disable=invalid-unary-operand-type
        c = clip_ops.clip_by_value(c, -self._cell_clip, self._cell_clip)
        # pylint: enable=invalid-unary-operand-type

      if self._use_peepholes:
        m = sigmoid(o + w_o_diag * c) * self._activation(c)
      else:
        m = sigmoid(o) * self._activation(c)

      if self._num_proj is not None:
        with vs.variable_scope("projection") as proj_scope:
          if self._num_proj_shards is not None:
            proj_scope.set_partitioner(
                partitioned_variables.fixed_size_partitioner(
                    self._num_proj_shards))
          m = _linear(m, self._num_proj, bias=False, scope=scope)

        if self._proj_clip is not None:
          # pylint: disable=invalid-unary-operand-type
          m = clip_ops.clip_by_value(m, -self._proj_clip, self._proj_clip)
          # pylint: enable=invalid-unary-operand-type

    new_state = (LSTMStateTuple(c, m) if self._state_is_Tuple else
                 array_ops.concat([c, m], 1))
    return m, new_state

Les lignes clés sont:

c = (sigmoid(f + self._forget_bias) * c_prev + sigmoid(i) *
         self._activation(j))

et 

m = sigmoid(o) * self._activation(c)

et 

new_state = (LSTMStateTuple(c, m) 

Si vous comparez le code pour calculer c et m avec les équations LSTM (voir ci-dessous), vous pouvez voir qu'il correspond à l'état de la cellule (généralement noté c) et à l'état masqué (généralement noté h), respectivement:

 enter image description here

new_state = (LSTMStateTuple(c, m) indique que le premier élément de l'état retourné Tuple est c (état de la cellule a.k.a. c_state) et que le deuxième élément de l'état renvoyé Tuple est m (état caché a.k.a. m_state).

16
Franck Dernoncourt

Peut-être que cet extrait du code aidera

def __call__(self, inputs, state, scope=None):
  """Long short-term memory cell (LSTM)."""
  with vs.variable_scope(scope or type(self).__name__):  # "BasicLSTMCell"
    # Parameters of gates are concatenated into one multiply for efficiency.
    if self._state_is_Tuple:
      c, h = state
    else:
      c, h = array_ops.split(1, 2, 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(1, 4, concat)

    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(1, [new_c, new_h])
    return new_h, new_state
2
Dmitry Chaplinsky

https://github.com/tensorflow/tensorflow/blob/r1.2/tensorflow/python/ops/rnn_cell_impl.py

Ligne # 308 - 314

classe LSTMStateTuple (_LSTMStateTuple): "" "Tuple utilisé par les cellules LSTM pour state_size, zero_state et l'état de sortie . Stocke deux éléments: (c, h), dans cet ordre . Uniquement utilisé lorsque state_is_Tuple=True." "

0
Z Chen