Tensorflow:具有另一个LSTM权重移动平均值的LSTM

Tensorflow:具有另一个LSTM权重移动平均值的LSTM,tensorflow,moving-average,lstm,Tensorflow,Moving Average,Lstm,我想在tensorflow中有一个LSTM,它的权重是另一个LSTM权重的指数移动平均值。基本上,我有一些输入占位符和一些初始状态占位符的代码: def test_lstm(input_ph, init_ph, scope): cell = tf.nn.rnn_cell.LSTMCell(128, use_peepholes=True) input_ph = tf.transpose(input_ph, [1, 0, 2]) input_list

我想在tensorflow中有一个LSTM,它的权重是另一个LSTM权重的指数移动平均值。基本上,我有一些输入占位符和一些初始状态占位符的代码:

def test_lstm(input_ph, init_ph, scope):
        cell = tf.nn.rnn_cell.LSTMCell(128, use_peepholes=True)
        input_ph = tf.transpose(input_ph, [1, 0, 2])
        input_list = tf.unpack(input_ph)

        with tf.variable_scope(scope) as vs:
            outputs, states = tf.nn.rnn(cell, input_list, initial_state=init_ph)

        theta = [v for v in tf.all_variables() if v.name.startswith(vs.name)]

        return outputs, theta

lstm_1, theta_1 = test_lstm(input_1, state_init_1, scope="lstm_1")
我现在想做的是沿着这些线做一些类似的事情(这实际上不起作用,因为指数移动平均值将标记“ema”放在权重的变量名称后面,并且它们不会出现在变量范围中,因为它们不是用tf.get_variable创建的):

最终θu 2_1等于θu 2_2(或者抛出异常,因为变量已经存在)。

  • 变更(2018年5月3日):我在旧答案的基础上增加了一行。对于这个问题,旧的网络本身是自给自足的,但实际上我们将“目标网络”初始化为与“行为网络”相同的值。我补充了这一点。搜索具有“Change0”的行:在目标网络的参数刚刚初始化之后,只需执行一次。如果没有“Change0”,第一轮基于梯度的更新将变得很糟糕,因为Q_目标和Q_行为不相关,而您需要两者都有一定的相关性(例如)TD=r+gamma*Q_目标-Q_行为用于更新
似乎有点晚了,但希望这能有所帮助。 TF-RNN系列的关键问题是,与普通前馈或卷积NNs不同,我们无法直接指定RNN的变量,因此我们无法进行简单的工作—获取EMAed变量并插入网络

让我们进入真正的交易(我附上了一个实践代码来查找这个,所以请参考)

我们可以说,有一个包含LSTM的网络函数:

def network(in_x,in_h):
   # Input: 'in_x' is the input sequence, 'in_h' is the initial hidden cell(c,m)
   # Output: 'hidden_outputs' is the output sequence(c-sequence), 'net' is the list of parameters used in this network function
   cell = tf.nn.rnn_cell.BasicLSTMCell(3, state_is_tuple=True)
   in_h = tf.nn.rnn_cell.LSTMStateTuple(in_h[0], in_h[1])
   hidden_outputs, last_tuple = tf.nn.dynamic_rnn(cell, in_x, dtype=tf.float32, initial_state=in_h)
   net = [v for v in tf.trainable_variables() if tf.contrib.framework.get_name_scope() in v.name]
   return hidden_outputs, net 
然后为必要的输入声明tf.placeholder,这些输入是:

in_x = tf.placeholder("float", [None,None,6])
in_c = tf.placeholder("float", [None,3])
in_m = tf.placeholder("float", [None,3])
in_h = (in_c, in_m)
最后,我们运行一个会话,使用指定的输入执行network()函数:

init_cORm = np.zeros(shape=(1,3))
input = np.ones(shape=(1,1,6))

print '========================new-1(beh)=============================='
with tf.Session() as sess:    
    with tf.variable_scope('beh', reuse=False) as beh:
        result, net1 = network(in_x,in_h)
        sess.run(tf.global_variables_initializer())
        list = sess.run([result, in_x, in_h, net1], feed_dict={
            in_x : input,
            in_c : init_cORm,
            in_m : init_cORm
        })
    print 'result:', list[0]
    print 'in_x:' , list[1]
    print 'in_h:', list[2]
    print 'net1:', list[3][0][0][:4]
现在,我们将创建名为“net4”的var_列表,其中包含“net1”的指数移动平均值(EMA)-ed值,如下所示,原始“net1”首先在上面的beh会话中分配,然后通过添加1在下面新分配。对于每个元素:

ema = tf.train.ExponentialMovingAverage(decay=0.5)
target_update_op = ema.apply(net1)
init_new_vars_op = tf.initialize_variables(var_list=[v for v in tf.global_variables() if 'ExponentialMovingAverage' in v.name]) # 'initialize_variables' will be replaced with 'variables_initializer' in 2017
sess.run(init_new_vars_op)
sess.run([param4.assign(param1.eval()) for param4, param1 in zip(net4,net1)]) # Change0

len_net1 = len(net1)
net1_ema = [[] for i in range(len_net1)]
for i in range(len_net1):
    sess.run(net1[i].assign(1. + net1[i]))

sess.run(target_update_op)
注意

  • 我们仅初始化(通过声明“init_new_vars_op”,然后运行声明作业)其名称中包含“指数移动平均值”的变量,如果不是,net1中的变量也将被新初始化

  • 对于“net1”中变量的每个元素,新为“net1”分配了+1。如果“net1”的元素是-0.5,现在是0.5乘以+1,那么我们希望“net4”为0。当EMA衰减率为0.5时

  • 最后,我们使用“sess.run(target_update_op)”运行EMA作业

最后,我们首先使用“network()”函数声明“net4”,然后将EMA(net1)值分配并运行到“net4”中。当您运行“sess.run(result)”时,它将是带有EMA(net1)-ed变量的

with tf.variable_scope('tare', reuse=False) as tare:
    result, net4 = network(in_x,in_h)
    len_net4 = len(net4)

    target_assign = [[] for i in range(len_net4)]
    for i in range(len_net4):
        target_assign[i] = net4[i].assign(ema.average(net1[i]))
        sess.run(target_assign[i].op)
    list = sess.run([result, in_x, in_h, net4], feed_dict={
        in_x : input,
        in_c : init_cORm,
        in_m : init_cORm
    })
这里发生了什么事?您只是在“network()”函数中将LSTM变量间接声明为“net4”。然后在for循环中,我们指出net4实际上是“net1”和“net1+1”的EMA。最后,在net4指定了要处理的内容(通过“network()”)和它所接受的值(通过“for loop of.assign(ema.average())to itself)”)之后,您可以运行该进程

我们首先声明“结果”,然后指定参数值,这有点违反直觉。然而,这正是TF的本质所在,因为设置变量、流程及其关系总是合乎逻辑的,首先是赋值,然后是运行流程

最后,对于真正的机器学习代码,有几点需要进一步研究:

  • 在这里,我刚刚用“net1+1”二次分配了“net1”。在实际情况中,这个“+1.”步骤是“sess.run()”(在某个地方“声明”之后)您的优化程序。因此,每次在“sess.run(Optimizer)”之后,“sess.run(target_update_op)”和“sess.run(target_assign[i].op)”都应该沿着“net1”的EMA更新“net4”。具体而言,您可以按以下不同顺序完成此项工作:

最后,请注意,您必须在网络发生变化后立即运行sess.run(ema.apply(net)),然后运行sess.run(net\u ema.assign(ema.average(net)).W/O.apply,net\u ema不会被分配平均值

len_net1 = len(net1)
net1_ema = [[] for i in range(len_net1)]
for i in range(len_net1):
    sess.run(net1[i].assign(1. + net1[i]))
sess.run(target_update_op)

for i in range(len_net4):
    sess.run(target_assign[i].op)
list = sess.run([result, in_x, in_h, net4], feed_dict={
    in_x : input,
    in_c : init_cORm,
    in_m : init_cORm
})

非常感谢您提供的详细答案。事实上,这有点太晚了,因为我在硕士论文(关于Deep RL)中对此进行了研究。不过,我肯定会对您的实现感兴趣。
ema = tf.train.ExponentialMovingAverage(decay=0.5)
target_update_op = ema.apply(net1)

with tf.variable_scope('tare', reuse=False) as tare:
    result, net4 = network(in_x,in_h)
    len_net4 = len(net4)
    target_assign = [[] for i in range(len_net4)]
    for i in range(len_net4):
        target_assign[i] = net4[i].assign(ema.average(net1[i]))

init_new_vars_op = tf.initialize_variables(var_list=[v for v in tf.global_variables() if 'ExponentialMovingAverage' in v.name]) # 'initialize_variables' will be replaced with 'variables_initializer' in 2017
sess.run(init_new_vars_op)
sess.run([param4.assign(param1.eval()) for param4, param1 in zip(net4,net1)]) # Change0
len_net1 = len(net1)
net1_ema = [[] for i in range(len_net1)]
for i in range(len_net1):
    sess.run(net1[i].assign(1. + net1[i]))
sess.run(target_update_op)

for i in range(len_net4):
    sess.run(target_assign[i].op)
list = sess.run([result, in_x, in_h, net4], feed_dict={
    in_x : input,
    in_c : init_cORm,
    in_m : init_cORm
})