В следующем примере я попытался заменить функции .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.