Концептуальный пример: MNIST с керасами с использованием backend.function - ошибка градиента при попытке определить обновление - PullRequest
0 голосов
/ 16 апреля 2019

В следующем примере я попытался заменить функции .compile и .fit, определив шаг обновления вручную (иногда требуется в моделях RL). Независимо от того, что я пробовал, я получаю ошибку, утверждая, что градиент не определен в строке, где он устанавливает "updates_op" .

Некоторые реализации keras алгоритмов градиента политики, таких как A3C или DDQN, пропускают вызовы .compile и .fit, обычно используемые с кератами, но вместо этого используют keras.backend.function с определениями потерь вручную. Это позволяет использовать вывод модели в качестве переменной для того, для чего она нужна.

Я пытаюсь лучше понять этот подход, написав таким образом пример классификатора MNIST по умолчанию. К сожалению, он завершается неудачно в строке «updates_op =» о том, что не все операции дифференцируемы (градиент не определен).

Я почти уверен, что это мое концептуальное недоразумение, но я не смог найти никакого решения или хорошего объяснения. Буду признателен за помощь в том, как я смог бы обучить этот простой пример Mnist.

Я пробовал заполнители и входные объекты и другие способы, но всегда один и тот же результат.

Импорт и получение данных:

from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
#get data
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

определить слои, потери и функцию поезда:

input_node = tf.keras.Input(shape=(28,28),name = 'input_node')
flat = tf.keras.layers.Flatten(name= 'faltten1')(input_node)
dense1 = tf.keras.layers.Dense(128,activation='relu', name = 'dense1')(flat)
dropout = tf.keras.layers.Dropout(0.2, name = 'dropout1')(dense1)
output_node = tf.keras.layers.Dense(10,activation='softmax',name='out')(dropout)

model = tf.keras.Model(inputs=input_node, outputs=output_node)
model.summary()

#define loss function manually
y_true_obj = tf.keras.Input(shape=(1,),name='y_true_placeholder')
y_pred_obj = tf.keras.Input(shape=(1,),name='y_pred_placeholder')
#also tried: tf.keras.backend.placeholder instead of input
loss = tf.keras.losses.sparse_categorical_crossentropy(y_true_obj,y_pred_obj)
#also tried: loss = tf.keras.backend.mean(tf.keras.backend.square(y_true-y_pred))

#define an update function which we get from an optimizer object
optimizer = tf.keras.optimizers.Adam()
updates_op = optimizer.get_updates(params=model.trainable_weights, loss=loss)

#the next function replaces the model.fit
train_fn = tf.keras.backend.function(inputs=[model.input, y_true_obj,y_pred_obj], outputs=[], updates=updates_op)

Теперь все определено. Но поскольку model.fit не существует, нам нужно зациклить и вызвать поезд вручную.

for x_train_this,y_train_this in zip(x_train,y_train):
    y_pred = model.predict(x_train_this)
    train_fn([x_train_this,y_train_this,y_pred])

Ожидается, что будет запущена одна тренировочная эпоха, но она не сможет интерпретироваться при updates_op = ... с:

ValueError: Операция имеет None для градиента. Пожалуйста, убедитесь, что все ваши операции имеют определенный градиент (то есть, дифференцируемы). Обычные операции без градиента: K.argmax, K.round, K.eval.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...