如何在 MultiRNNCell 中重用权重?

How to reuse weights in MultiRNNCell?

我想在重用旧权重的同时创建一个新的 MultiRNNCell。

从 TensorFlow 1.1 开始,当您创建 MultiRNNCell 时,您必须明确地创建新的单元格。要重用权重,您必须提供 reuse=True 标志。在我的代码中,我目前有:

import tensorflow as tf
from tensorflow.contrib import rnn

def create_lstm_multicell():
    lstm_cell = lambda: rnn.LSTMCell(nstates, reuse=tf.get_variable_scope().reuse)
    lstm_multi_cell = rnn.MultiRNNCell([lstm_cell() for _ in range(n_layers)])
    return lstm_multi_cell

当我创建第一个多单元时,函数应该按预期工作,多层元素中的每个单元都有独立的权重和偏差。

with tf.variable_scope('lstm') as scope:
    lstm1 = create_lstm_multicell()

现在我想创建另一个:

with tf.variable_scope('lstm') as scope:
    scope.reuse_variables()
    lstm2 = create_lstm_multicell()

我希望 lstm2 中的第一个单元格使用 lstm1 中第一个单元格的权重和偏差,第二个单元格重用第二个单元格的权重和偏差,等等。但我怀疑因为我用 reuse=True 调用 rnn.LSTMCell 第一个 单元格的权重和偏差将一直重复使用。

  1. 如何确保正确地重复使用权重?
  2. 如果不是,如何强制执行此所需行为?

P.S。出于架构原因,我不想重复使用 lstm1,我想创建一个具有相同权重的新多单元 lstm2

TL;DR

似乎在代码中来自问题单元格的权重和偏差将被正确地重用。多单元 lstm1lstm2 将具有相同的行为,并且 MultiRNNCell 内的单元将具有独立的权重和偏差。 IE。 伪代码:

lstm1._cells[0].weights == lstm2._cells[0].weights
lstm1._cells[1].weights == lstm2._cells[1].weights

更长的版本

到目前为止,这还不是一个确定的答案,但这是我迄今为止所做的研究的结果。

这看起来像是 hack,但我们可以覆盖 get_variable 方法以查看访问了哪些变量。例如像这样:

from tensorflow.python.ops import variable_scope as vs

def verbose(original_function):
    # make a new function that prints a message when original_function starts and finishes
    def new_function(*args, **kwargs):
        print('get variable:', '/'.join((tf.get_variable_scope().name, args[0])))
        result = original_function(*args, **kwargs)
        return result
    return new_function

vs.get_variable = verbose(vs.get_variable)

现在我们可以运行修改以下代码:

def create_lstm_multicell(name):
    def lstm_cell(i, s):
        print('creating cell %i in %s' % (i, s))
        return rnn.LSTMCell(nstates, reuse=tf.get_variable_scope().reuse)
    lstm_multi_cell = rnn.MultiRNNCell([lstm_cell(i, name) for i in range(n_layers)])
    return lstm_multi_cell

with tf.variable_scope('lstm') as scope:
    lstm1 = create_lstm_multicell('lstm1')
    layer1, _ = tf.nn.dynamic_rnn(lstm1, x, dtype=tf.float32)
    val_1 = tf.reduce_sum(layer1)

with tf.variable_scope('lstm') as scope:
    scope.reuse_variables()
    lstm2 = create_lstm_multicell('lstm2')
    layer2, _ = tf.nn.dynamic_rnn(lstm2, x, dtype=tf.float32)
    val_2 = tf.reduce_sum(layer2)

输出将如下所示(我删除了重复的行):

creating cell 0 in lstm1
creating cell 1 in lstm1
get variable: lstm/rnn/multi_rnn_cell/cell_0/lstm_cell/weights
get variable: lstm/rnn/multi_rnn_cell/cell_0/lstm_cell/biases
get variable: lstm/rnn/multi_rnn_cell/cell_1/lstm_cell/weights
get variable: lstm/rnn/multi_rnn_cell/cell_1/lstm_cell/biases
creating cell 0 in lstm2
creating cell 1 in lstm2
get variable: lstm/rnn/multi_rnn_cell/cell_0/lstm_cell/weights
get variable: lstm/rnn/multi_rnn_cell/cell_0/lstm_cell/biases
get variable: lstm/rnn/multi_rnn_cell/cell_1/lstm_cell/weights
get variable: lstm/rnn/multi_rnn_cell/cell_1/lstm_cell/biases

此输出表明 lstm1lstm2 单元格将使用相同的权重和偏差,对于 MultiRNNCell 中的第一个和第二个单元格,两者都有单独的权重和偏差。

另外,作为lstm1lstm2的输出的val_1val_2在优化过程中是相同的。

我认为 MultiRNNCell 在其中创建了名称空间 cell_0cell_1 等。因此 lstm1lstm2 之间的权重将被重用。