У меня есть модель обучения с глубоким подкреплением градиента политики. Модель выбирает из действия 1 logits и action 2 logits при прямом распространении на каждом шаге. В конце эпизода я распространял информацию о потере. Я использую разные настройки среды (изучение учебного плана) в каждом эпизоде, и, следовательно, разница от каждого эпизода велика. Поэтому я решил использовать пакетное обучение, обновляя градиенты, например, один раз в 4 эпизодах. У меня всего 21 обучаемая переменная. Сначала я пытался вычислить градиент для каждого шага, умноженный на количество эпизодов (размер партии), и найти среднее значение всех градиентов для каждой обучаемой переменной и обратного распространения один раз в 4 эпизодах. Тем не менее, это оказалось тяжелым для памяти, так как у меня длина эпизода 2000 и размер пакета 4. Это 8000 градиентов умножить на 21 переменную, и многие из этих переменных, естественно, многомерны. Вот функция, которую я написал для того же
def average_gradients(self,tower_grads):
average_grads = []
count = 0
for grad_and_vars in zip(*tower_grads):
# Note that each grad_and_vars looks like the following:
# ((grad0_gpu0, var0_gpu0), ... , (grad0_gpuN, var0_gpuN))
grads = []
for g, _ in grad_and_vars:
g = self.flat_gradients(g)
# Add 0 dimension to the gradients to represent the tower.
expanded_g = tf.expand_dims(g, 0)
# Append on a 'tower' dimension which we will average over below.
grads.append(expanded_g)
# Average over the 'tower' dimension.
grad = tf.concat(axis=0, values=grads)
grad = tf.reduce_mean(grad, 0)
# Keep in mind that the Variables are redundant because they are shared
# across towers. So .. we will just return the first tower's pointer to
# the Variable.
# v = grad_and_vars[0][1]
v = self._grad_placeholders[count]
count += 1
grad_and_var = (grad, v)
average_grads.append(grad_and_var)
return average_grads
# This is needed for tf.gather like operations.
def flat_gradients(self,grads_or_idx_slices: tf.Tensor) -> tf.Tensor:
'''Convert gradients if it's tf.IndexedSlices.
When computing gradients for operation concerning `tf.gather`, the type of gradients
'''
if not hasattr(grads_or_idx_slices, 'shape'):
# if type(grads_or_idx_slices) == tf.IndexedSlices or type(grads_or_idx_slices) == tf.IndexedSlicesValue:
return tf.scatter_nd(
tf.expand_dims(grads_or_idx_slices.indices, 1),
grads_or_idx_slices.values,
grads_or_idx_slices.dense_shape
)
return grads_or_idx_slices
Таким образом, вместо сохранения градиентов в памяти, я решил вычислить его среднее значение, как и когда я получаю новый градиент из шага. Таким образом, у меня всегда будет только один градиент в памяти. Вот как я это реализовал:
if self.batch_size == 1:
loss_, _, logits = sess.run([self.loss, self.train_op,self.action_distribution_0], feed_dict=feed_dict)
else:
loss, grads = sess.run([self.loss, self._grad_op], feed_dict=feed_dict)
if(i == 0): # first step
for grad,var in grads:
grad = self.flat_gradients(grad)
# print(type(grad))
if not type(grad) == np.ndarray:
grad = grad.eval()
# print(grad)
self.gradient.append(grad)
else:
for k,(grad,_) in enumerate(grads):
grad = self.flat_gradients(grad)
if not type(grad) == np.ndarray:
grad = grad.eval()
self.gradient[k] = np.stack([grad, self.gradient[k]]).mean(axis=0)
Итак, из каждого эпизода я получаю только один градиент, независимо от количества шагов, которые он предпринял. Я снова делаю среднее значение между эпизодами и, наконец, применяю свой градиент.
Этот метод, хотя и в вычислительном отношении, очень дорогой. У меня приличный 8 Гб оперативной памяти Ram и i7 Kaby Lake, но для вычисления среднего значения градиента из одного эпизода с 2000 шагов требуется до 30 минут.
Есть ли умный способ сделать это? Любая помощь будет оценена.