Вычислить градиентную норму каждой части функции суммирования потерь

Предположим, что у меня есть следующая функция потерь:

loss_a = tf.reduce_mean(my_loss_fn(model_output, targets))
loss_b = tf.reduce_mean(my_other_loss_fn(model_output, targets))
loss_final = loss_a + tf.multiply(alpha, loss_b)

Чтобы визуализировать норму градиентов w.r.t до loss_final, можно было бы сделать это:

optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
grads_and_vars = optimizer.compute_gradients(loss_final)
grads, _ = list(zip(*grads_and_vars))
norms = tf.global_norm(grads)
gradnorm_s = tf.summary.scalar('gradient norm', norms)
train_op = optimizer.apply_gradients(grads_and_vars, name='train_op')

Однако мне хотелось бы построить график градиентов w.r.t до loss_a и loss_b отдельно. Как я могу сделать это наиболее эффективным способом? Должен ли я называть compute_gradients(..) на loss_a и loss_b отдельно, а затем добавлять эти два градиента вместе, прежде чем передавать их в optimizer.apply_gradients(..)? Я знаю, что это математически было бы правильным из-за правила суммирования, но это кажется немного громоздким, и я также не знаю, как правильно реализовать суммирование градиентов. Кроме того, loss_final довольно прост, потому что это просто суммирование. Что, если loss_final было более сложным, например. деление?

Я использую Tensorflow 0.12.

Ответы

Ответ 1

Вы правы, что объединение градиентов может стать беспорядочным. Вместо этого просто вычислите градиенты каждого из потерь, а также окончательную потерю. Поскольку tensorflow оптимизирует ориентированный ациклический граф (DAG) перед компиляцией, это не приводит к дублированию работы.

Например:

import tensorflow as tf

with tf.name_scope('inputs'):
    W = tf.Variable(dtype=tf.float32, initial_value=tf.random_normal((4, 1), dtype=tf.float32), name='W')
    x = tf.random_uniform((6, 4), dtype=tf.float32, name='x')

with tf.name_scope('outputs'):
    y = tf.matmul(x, W, name='y')

def my_loss_fn(output, targets, name):
    return tf.reduce_mean(tf.abs(output - targets), name=name)

def my_other_loss_fn(output, targets, name):
    return tf.sqrt(tf.reduce_mean((output - targets) ** 2), name=name)

def get_tensors(loss_fn):

    loss = loss_fn(y, targets, 'loss')
    grads = tf.gradients(loss, W, name='gradients')
    norm = tf.norm(grads, name='norm')

    return loss, grads, norm

targets = tf.random_uniform((6, 1))

with tf.name_scope('a'):
    loss_a, grads_a, norm_a = get_tensors(my_loss_fn)

with tf.name_scope('b'):
    loss_b, grads_b, norm_b = get_tensors(my_loss_fn)

with tf.name_scope('combined'):
    loss = tf.add(loss_a, loss_b, name='loss')
    grad = tf.gradients(loss, W, name='gradients')

with tf.Session() as sess:
    tf.global_variables_initializer().run(session=sess)

    writer = tf.summary.FileWriter('./tensorboard_results', sess.graph)
    res = sess.run([norm_a, norm_b, grad])

    print(*res, sep='\n')

Изменить. В ответ на ваш комментарий... Вы можете проверить DAG модели тензорного потока с помощью тензора. Я обновил код для хранения графика.

Запустите tensorboard --logdir $PWD/tensorboard_results в терминале и перейдите к URL-адресу, напечатанному на командной строке (обычно http://localhost:6006/). Затем перейдите на вкладку GRAPH, чтобы просмотреть DAG. Вы можете рекурсивно развернуть тензоры, ops, namespaces, чтобы увидеть подграфы, чтобы увидеть отдельные операции и их входы.

пример DAG-диаграммы