繁体   English   中英

Tensorflow:如何在批处理中获得每个实例的渐变?

[英]Tensorflow: How to get gradients per instance in a batch?

我在看这个笔记本中的政策渐变样本: https//github.com/ageron/handson-ml/blob/master/16_reinforcement_learning.ipynb

相关代码在这里:

X = tf.placeholder(tf.float32, shape=[None, n_inputs])

hidden = tf.layers.dense(X, n_hidden, activation=tf.nn.elu, kernel_initializer=initializer)
logits = tf.layers.dense(hidden, n_outputs)
outputs = tf.nn.sigmoid(logits)  # probability of action 0 (left)
p_left_and_right = tf.concat(axis=1, values=[outputs, 1 - outputs])
action = tf.multinomial(tf.log(p_left_and_right), num_samples=1)

y = 1. - tf.to_float(action)
cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits)
optimizer = tf.train.AdamOptimizer(learning_rate)
grads_and_vars = optimizer.compute_gradients(cross_entropy)
gradients = [grad for grad, variable in grads_and_vars]
gradient_placeholders = []
grads_and_vars_feed = []
for grad, variable in grads_and_vars:
    gradient_placeholder = tf.placeholder(tf.float32, shape=grad.get_shape())
    gradient_placeholders.append(gradient_placeholder)
    grads_and_vars_feed.append((gradient_placeholder, variable))
training_op = optimizer.apply_gradients(grads_and_vars_feed)

...
# Run training over a bunch of instances of inputs
            for step in range(n_max_steps):
                action_val, gradients_val = sess.run([action, gradients], feed_dict={X: obs.reshape(1, n_inputs)})
...
# Then weight each gradient by the action values, average, and feed them back into training_op to apply_gradients()

以上工作正常,因为每个run()返回不同的渐变。

我想批处理所有这些,并将一个输入数组一次输入run()而不是一个输入(我的环境与示例中的环境不同,所以我批处理并提高性能是有意义的)。 即:

action_val, gradients_val = sess.run([action, gradients], feed_dict={X: obs_array})

obs_array的形状[n_instances, n_inputs]

问题是optimizer.compute_gradients(cross_entropy)似乎返回单个渐变,即使cross_entropy是1d张量的形状[None,1]。 action_val确实返回1d张量的操作,正如预期的那样 - 批处理中每个实例一个操作。

有没有办法让我获得一系列渐变,批量中每个实例一个?

问题是optimizer.compute_gradients(cross_entropy)似乎返回单个渐变,即使cross_entropy是1d张量的形状[None, 1]

这通过设计发生,因为每个张量的梯度项是自动聚合的。 根据默认的AddN聚合方法,梯度计算操作(例如optimizer.compute_gradients和低级原语tf.gradients构成所有梯度操作的总和。 这适用于大多数随机梯度下降的情况。

不幸的是,最终必须在一个批次上进行梯度计算。 当然,除非构建自定义渐变函数,否则扩展TensorFlow API以提供没有完全聚合的渐变计算。 更改tf.gradients实现来执行此操作似乎并不是非常简单。

您可能希望用于强化学习模型的一个技巧是并行执行多个会话运行。 根据FAQ ,Session API支持多个并发步骤,并将利用现有资源进行并行计算。 TensorFlow中的异步计算问题显示了如何执行此操作。

我提出的一个弱解决方案是创建一个梯度操作数组,批处理中每个实例一个,然后我可以同时运行所有:

X = tf.placeholder(tf.float32, shape=[minibatch_size, n_inputs])

hidden = tf.layers.dense(X, n_hidden, activation=tf.nn.elu, kernel_initializer=initializer)
hidden2 = tf.layers.dense(hidden, n_hidden, activation=tf.nn.elu, kernel_initializer=initializer)
logits = tf.layers.dense(hidden2, n_outputs)
outputs = tf.nn.sigmoid(logits)  # probability of action 0
p_left_and_right = tf.concat(axis=1, values=[outputs, 1 - outputs])
action = tf.multinomial(tf.log(p_left_and_right), num_samples=1)

y = 1. - tf.to_float(action)
cross_entropy = tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits)
optimizer = tf.train.AdamOptimizer(learning_rate)

# Calculate gradients per batch instance - for minibatch training
batch_gradients = []
for instance_cross_entropy in tf.unstack(cross_entropy):
    instance_grads_and_vars = optimizer.compute_gradients(instance_cross_entropy)
    instance_gradients = [grad for grad, variable in instance_grads_and_vars]
    batch_gradients.append(instance_gradients)

# Calculate gradients for just one instance - for single instance training
grads_and_vars = optimizer.compute_gradients(cross_entropy)
gradients = [grad for grad, variable in grads_and_vars]

# Create gradient placeholders
gradient_placeholders = []
grads_and_vars_feed = []
for grad, variable in grads_and_vars:
    gradient_placeholder = tf.placeholder(tf.float32, shape=grad.get_shape())
    gradient_placeholders.append(gradient_placeholder)
    grads_and_vars_feed.append((gradient_placeholder, variable))

# In the end we only apply a single set of averaged gradients
training_op = optimizer.apply_gradients(grads_and_vars_feed)

...

while step < len(obs_array) - minibatch_size:
    action_array, batch_gradients_array = sess.run([action, batch_gradients], feed_dict={X: obs_array[step:step+minibatch_size]})
    for action_val, gradient in zip(action_array, batch_gradients_array):
    action_vals.append(action_val)
    current_gradients.append(gradient)
    step += minibatch_size

要点是我需要为占位符X指定批量大小,我不能让它开放结束,否则unstack不知道有多少元素要取消堆叠。 我卸载cross_entropy以获得每个实例的cross_entropy,然后我为每个实例调用compute_gradients。 在训练过程中,我运行([action,batch_gradients],feed_dict = {X:obs_array [step:step + minibatch_size]}),它为每个批次提供了单独的渐变。

这一切都很好,但它并没有给我带来很大的性能提升。 我只获得2倍的最大加速。 增加批量大小超过5只是线性地缩放run()的运行时间,并且没有增益。

令人遗憾的是,Tensorflow能够快速地计算和聚合数百个实例的渐变,但逐个请求渐变的速度要慢得多。 可能需要深入挖掘源头......

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM