Tensorflow:具有另一个LSTM权重移动平均值的LSTM
我想在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
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_行为用于更新
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作业
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”。具体而言,您可以按以下不同顺序完成此项工作:
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
})