Нетерпеливый tf.GradientTape() возвращает только нули

#tensorflow

#tensorflow

Вопрос:

Я пытаюсь вычислить градиенты с помощью Tensorflow в режиме ожидания, но tf.GradientTape () возвращает только значения None. Я не могу понять, почему. Градиенты вычисляются в функции update_policy () .

Вывод строки:

 grads = tape.gradient(loss, self.model.trainable_variables)
  

является

 {list}<class 'list'>:[None, None, ... ,None]
  

Вот код.

 import tensorflow as tf
from keras.backend.tensorflow_backend import set_session

import numpy as np

tf.enable_eager_execution()
print(tf.executing_eagerly())

config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
set_session(sess)


class PGEagerAtariNetwork:
    def __init__(self, state_space, action_space, lr, gamma):
        self.state_space = state_space
        self.action_space = action_space
        self.gamma = gamma

        self.model = tf.keras.Sequential()
        # Conv
        self.model.add(
            tf.keras.layers.Conv2D(filters=32, kernel_size=[8, 8], strides=[4, 4], activation='relu',
                                   input_shape=(84, 84, 4,),
                                   name='conv1'))
        self.model.add(
            tf.keras.layers.Conv2D(filters=64, kernel_size=[4, 4], strides=[2, 2], activation='relu', name='conv2'))
        self.model.add(
            tf.keras.layers.Conv2D(filters=128, kernel_size=[4, 4], strides=[2, 2], activation='relu', name='conv3'))
        self.model.add(tf.keras.layers.Flatten(name='flatten'))

        # Fully connected
        self.model.add(tf.keras.layers.Dense(units=512, activation='relu', name='fc1'))
        self.model.add(tf.keras.layers.Dropout(rate=0.4, name='dr1'))
        self.model.add(tf.keras.layers.Dense(units=256, activation='relu', name='fc2'))
        self.model.add(tf.keras.layers.Dropout(rate=0.3, name='dr2'))
        self.model.add(tf.keras.layers.Dense(units=128, activation='relu', name='fc3'))
        self.model.add(tf.keras.layers.Dropout(rate=0.1, name='dr3'))

        # Logits
        self.model.add(tf.keras.layers.Dense(units=self.action_space, activation=None, name='logits'))

        self.model.summary()

        # Optimizer
        self.optimizer = tf.train.AdamOptimizer(learning_rate=lr)

    def get_probs(self, s):
        s = s[np.newaxis, :]
        logits = self.model.predict(s)
        probs = tf.nn.softmax(logits).numpy()
        return probs

    def update_policy(self, s, r, a):
        with tf.GradientTape() as tape:
            logits = self.model.predict(s)
            policy_loss = tf.nn.softmax_cross_entropy_with_logits_v2(labels=a, logits=logits)
            policy_loss = policy_loss * tf.stop_gradient(r)
            loss = tf.reduce_mean(policy_loss)
        grads = tape.gradient(loss, self.model.trainable_variables)
        self.optimizer.apply_gradients(zip(grads, self.model.trainable_variables))
  

Комментарии:

1. predict() возвращает numpy тип. Он должен быть тензорным. Это первая проблема. Удалить .numpy() predict() .

2. update_policy () Функция не вызывает predict () функцию. Это не зависит от вычисления градиентов. update_policy () Функция вызывает self.model.predict () . Я меняю функцию, чтобы избежать недоразумений

3. Извините, я не говорю по-немецки.

4. Извините, это был мой переводчик

5. Выглядит нормально. Вы уверены, что за переменными следят? Попробуйте добавить tape.watch(self.model.trainable_variables) перед вызовом self.model.predict() update_policy()

Ответ №1:

У вас нет прямого прохода в вашей модели. Model.predict() Метод возвращает numpy() массив без записи прямого прохода. Взгляните на этот пример:

Учитывая следующие данные и модель:

 import tensorflow as tf
import numpy as np

x_train = tf.convert_to_tensor(np.ones((1, 2), np.float32), dtype=tf.float32)
y_train = tf.convert_to_tensor([[0, 1]])

model = tf.keras.models.Sequential([tf.keras.layers.Dense(2, input_shape=(2, ))])
  

Сначала мы используем predict() :

 with tf.GradientTape() as tape:
    logits = model.predict(x_train)
    print('`logits` has type {0}'.format(type(logits)))
    # `logits` has type <class 'numpy.ndarray'>
    xentropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_train, logits=logits)
    reduced = tf.reduce_mean(xentropy)
    grads = tape.gradient(reduced, model.trainable_variables)
    print('grads are: {0}'.format(grads))
    # grads are: [None, None]
  

Теперь мы используем входные данные модели:

 with tf.GradientTape() as tape:
    logits = model(x_train)
    print('`logits` has type {0}'.format(type(logits)))
    # `logits` has type <class 'tensorflow.python.framework.ops.EagerTensor'>
    xentropy = tf.nn.softmax_cross_entropy_with_logits(labels=y_train, logits=logits)
    reduced = tf.reduce_mean(xentropy)
    grads = tape.gradient(reduced, model.trainable_variables)
    print('grads are: {0}'.format(grads))
    # grads are: [<tf.Tensor: id=2044, shape=(2, 2), dtype=float32, numpy=
    # array([[ 0.77717704, -0.777177  ],
    #        [ 0.77717704, -0.777177  ]], dtype=float32)>, <tf.Tensor: id=2042, 
    # shape=(2,), dtype=float32, numpy=array([ 0.77717704, -0.777177  ], dtype=float32)>]

  

Поэтому используйте model __call__() (т.Е. model(x) ) Для прямого прохода, а не predict() .

Комментарии:

1. Мы написали то же самое с разницей менее чем в 30 секунд). Это должно сработать, хотя я бы сказал, что это просто потому .predict , что возвращает массив numpy, который нельзя дифференцировать по TF . __call__ возвращает тензор

2. @Sharky, извините за это 😉 Вы правы, что numpy нельзя дифференцировать, но он также не записывает прямой проход, иначе вызовы в predict() конечном итоге переполнят буфер.

3. @Sharky, спасибо, я тоже у тебя в долгу.

4. @Sharky вы правы, голос более чем заслужен. Для меня это невозможно, мне нужно как минимум 15 репутации, прежде чем я смогу проголосовать.

5. Теперь вы делаете. Вопрос также стоит того.