首页 > 解决方案 > 如何在小批量上累积我的损失然后计算我的梯度

问题描述

我的主要问题是;平均损失与平均梯度相同吗?我如何在小批量上累积损失然后计算我的梯度?

我一直在尝试在 Tensorflow 中实现策略梯度,但遇到了无法将所有游戏状态一次输入网络然后更新的问题。问题是如果我降低我的网络大小然后一次在所有帧上训练并取损失的平均值然后它开始很好地收敛。但是如果我在小批量上累积梯度然后平均它们,我的梯度会爆炸并且我的权重溢出。

任何帮助或见解将不胜感激。

还要记住,这是我第一次在这里提问。

标签: pythontensorflowreinforcement-learningtensorflow-gradientpolicy-gradient-descent

解决方案


您可以做的是在每个小批量之后累积梯度,然后根据梯度平均值更新权重。考虑使用单层感知器拟合 50 个高斯斑点的简单案例:

from sklearn.datasets import make_blobs
import tensorflow as tf
import numpy as np

x_train, y_train = make_blobs(n_samples=50,
                              n_features=2,
                              centers=[[1, 1], [-1, -1]],
                              cluster_std=0.5)

with tf.name_scope('x'):
    x = tf.placeholder(tf.float32, [None, 2])
    y = tf.placeholder(tf.int32, [None])

with tf.name_scope('layer'):
    logits = tf.layers.dense(x,
                             units=2,
                             kernel_initializer=tf.contrib.layers.xavier_initializer())
with tf.name_scope('loss'):
    xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=logits)
    loss_op = tf.reduce_mean(xentropy)

张量流优化器的minimize()方法调用compute_gradients()然后apply_gradients(). minimize()我将直接调用这两种方法,而不是调用。首先,为了得到我们调用的梯度compute_gradients()(它返回一个元组列表grads_and_vars),apply_gradients()而不是梯度,我将为未来梯度的平均值提供占位符:

optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
grads_and_vars = optimizer.compute_gradients(loss_op)
grads = [g for g, v in grads_and_vars]

# placeholders for gradients averages
placeholder_grads = [tf.placeholder(tf.float32, [None] + g.get_shape().as_list())
                     for g in grads]

new_grads_and_vars = [(tf.reduce_mean(p, axis=0), gv[1])
                      for p, gv in zip(placeholder_grads, grads_and_vars)]

apply_grads_op = optimizer.apply_gradients(new_grads_and_vars)

在小批量期间,我们只计算损失(您也可以累积损失 - 附加到某个列表,然后计算平均值)和梯度,而不将梯度应用于权重。在每个 epoch 结束时,我们执行apply_grads_op操作,同时将累积的梯度提供给它的占位符:

data = tf.data.Dataset.from_tensor_slices({'x':x_train, 'y':y_train}).batch(10)
iterator = data.make_initializable_iterator()
n_epochs = 2
with tf.Session() as sess:
    _ = sess.run([tf.global_variables_initializer(), iterator.initializer])
    next_batch = iterator.get_next()
    for epoch in range(n_epochs):
        epoch_grads = []
        while True:
            try:
                batch = sess.run(next_batch)
                evaled = sess.run([loss_op] + grads,
                                  feed_dict={x:batch['x'], y:batch['y']})
                epoch_grads.append(evaled[1:])
                print('batch loss:', evaled[0])
            except tf.errors.OutOfRangeError:
                _ = sess.run(iterator.initializer)
                feed_dict = {p:[g[i] for g in epoch_grads]
                             for i, p in enumerate(placeholder_grads)}
                _ = sess.run(apply_grads_op, feed_dict=feed_dict)

                break

推荐阅读