Отладка промежуточного слоя keras или объектных переменных с помощью тензорного потока

Я пишу пользовательскую задачу по обучению модели Keras (с тензорным потоком), но мне нужно отлаживать некоторые промежуточные вычисления. Для простоты позвольте сказать, что у меня есть:

def custom_loss(y_pred, y_true):
    diff = y_pred - y_true
    return K.square(diff)

Я не мог найти простой способ доступа, например, промежуточную переменную diff или ее форму во время обучения. В этом простом примере я знаю, что я могу вернуть diff для печати своих значений, но мои фактические потери сложнее, и я не могу вернуть промежуточные значения, не получая компиляцию ошибок.

Есть ли простой способ отладки промежуточных переменных в Keras?

Ответы

Ответ 1

Насколько я знаю, это не то, что разрешено в Keras, поэтому вам нужно прибегать к функциональности, зависящей от бэкэнд. Оба Theano и TensorFlow имеют узлы Print которые являются узлами идентификации (т.е. Возвращают входной узел) и имеют побочный эффект печати ввода (или некоторого тензора входа).

Пример для Theano:

diff = y_pred - y_true
diff = theano.printing.Print('shape of diff', attrs=['shape'])(diff)
return K.square(diff)

Пример для TensorFlow:

diff = y_pred - y_true
diff = tf.Print(diff, [tf.shape(diff)])
return K.square(diff)

Обратите внимание, что это работает только для промежуточных значений. Keras ожидает, что тензоры, которые передаются другим слоям, имеют определенные атрибуты, такие как _keras_shape. Значения, обрабатываемые бэкэнд, то есть через Print, обычно не имеют этого атрибута. Чтобы решить эту проблему, вы можете, например, обернуть операторы отладки в слое Lambda.

Ответ 2

В TensorFlow 2 теперь можно добавлять точки останова IDE в модели/слои/потери TensorFlow Keras, в том числе при использовании методов подбора, оценки и прогнозирования. Однако вы должны добавить model.run_eagerly = True после вызова model.compile(), чтобы значения тензора были доступны в отладчике в точке останова. Например,

import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam

def custom_loss(y_pred, y_true):
    diff = y_pred - y_true
    return tf.keras.backend.square(diff)  # Breakpoint in IDE here. =====

class SimpleModel(Model):

    def __init__(self):
        super().__init__()
        self.dense0 = Dense(2)
        self.dense1 = Dense(1)

    def call(self, inputs):
        z = self.dense0(inputs)
        z = self.dense1(z)
        return z

x = tf.convert_to_tensor([[1, 2, 3], [4, 5, 6]], dtype=tf.float32)
y = tf.convert_to_tensor([0, 1], dtype=tf.float32)

model0 = SimpleModel()
model0.run_eagerly = True
model0.compile(optimizer=Adam(), loss=custom_loss)
y0 = model0.fit(x, y, epochs=1)  # Values of diff *not* shown at breakpoint. =====

model1 = SimpleModel()
model1.compile(optimizer=Adam(), loss=custom_loss)
model1.run_eagerly = True
y1 = model1.fit(x, y, epochs=1)  # Values of diff shown at breakpoint. =====

Это также работает для отладки выходов промежуточных сетевых уровней (например, добавление точки останова в call SimpleModel).

Примечание: это было проверено в TensorFlow 2.0.0-rc0.