keras custom loss pure python (без бэкэнда keras)

В настоящее время я программирую автоэнкодер для сжатия изображений. Я хотел бы использовать настраиваемую функцию потерь, написанную на чистом питоне, то есть без использования бэкэнд-функций keras. Возможно ли это вообще, и если да, то как? Если можно, был бы очень признателен за минимально рабочий пример (MWE). Пожалуйста, посмотрите на этот MWE, в частности на функцию mse_keras:

# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt
import numpy as np
import keras.backend as K
from keras.datasets import mnist
from keras.models import Model, Sequential
from keras.layers import Input, Dense


def mse_keras(A,B):
    mse = K.mean(K.square(A - B), axis=-1)
    return mse


# Loads the training and test data sets (ignoring class labels)
(x_train, _), (x_test, _) = mnist.load_data()

# Scales the training and test data to range between 0 and 1.
max_value = float(x_train.max())
x_train = x_train.astype('float32') / max_value
x_test = x_test.astype('float32') / max_value


x_train.shape, x_test.shape
# ((60000, 28, 28), (10000, 28, 28))


x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))

(x_train.shape, x_test.shape)
# ((60000, 784), (10000, 784))


# input dimension = 784
input_dim = x_train.shape[1]
encoding_dim = 32

compression_factor = float(input_dim) / encoding_dim
print("Compression factor: %s" % compression_factor)

autoencoder = Sequential()
autoencoder.add(Dense(encoding_dim, input_shape=(input_dim,), activation='relu'))
autoencoder.add(Dense(input_dim, activation='sigmoid'))

autoencoder.summary()

input_img = Input(shape=(input_dim,))
encoder_layer = autoencoder.layers[0]
encoder = Model(input_img, encoder_layer(input_img))

encoder.summary()


autoencoder.compile(optimizer='adam', loss=mse_keras, metrics=['mse'])
history=autoencoder.fit(x_train, x_train,
                        epochs=3,
                        batch_size=256,
                        shuffle=True,
                        validation_data=(x_test, x_test))

num_images = 10
np.random.seed(42)
random_test_images = np.random.randint(x_test.shape[0], size=num_images)

decoded_imgs = autoencoder.predict(x_test)


#print(history.history.keys())

plt.figure()
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])

plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test', 'mse1', 'val_mse1'], loc='upper left')
plt.show()


plt.figure(figsize=(18, 4))

for i, image_idx in enumerate(random_test_images):
    # plot original image
    ax = plt.subplot(3, num_images, i + 1)
    plt.imshow(x_test[image_idx].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # plot reconstructed image
    ax = plt.subplot(3, num_images, 2*num_images + i + 1)
    plt.imshow(decoded_imgs[image_idx].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
plt.show()

Приведенный выше код представляет собой MWE для настраиваемой функции потерь с использованием бэкэнда Keras. Однако я хочу не этого! Я хотел бы заменить в своем коде функцию mse_keras примерно так:

def my_mse(A,B):
    mse = ((A - B) ** 2).mean(axis=None)
    return mse

Это опять же просто MWE. Это чистый питон и scipy. НЕТ КЕРАС НАЗАД! Можно ли использовать чистые функции python в качестве функций потерь (я пробовал использовать py_func, но у меня это не сработало). Я спрашиваю, потому что в конечном итоге я хотел бы использовать более сложную функцию потерь, которая является уже реализован на Python. И я не понимаю, как я мог бы повторно реализовать его, используя бэкэнд keras. (У меня тоже нет на это времени, если честно)

(Для любопытных: функции, которые я хотел бы использовать в качестве функции потерь, можно увидеть здесь: https://github.com/aizvorski/video-quality)

Любая помощь будет принята с благодарностью. Backend может быть theano, tensorflow, мне все равно. Если возможно, предоставьте мне MWE на python 3.X.

Спасибо заранее. Ваша помощь очень ценится.


person Boris Reif    schedule 24.06.2018    source источник
comment
theano больше не поддерживается, я рекомендую использовать тензорный поток или CNTK в качестве бэкэнда   -  person skjerns    schedule 24.06.2018
comment
Правда. На данный момент я использую тензорный поток. Но я думаю, cntk тоже в порядке. Спасибо.   -  person Boris Reif    schedule 25.06.2018


Ответы (1)


Вы не можете использовать чистую функцию Python в качестве потери для Кераса. Поскольку вы, вероятно, тренируетесь на графическом процессоре, а python использует процессор, это приведет к накладным расходам за счет передачи результатов из / в память графического процессора.

из https://keras.io/losses/

Вы можете передать имя существующей функции потерь или передать символическую функцию TensorFlow / Theano, которая возвращает скаляр для каждой точки данных и принимает следующие два аргумента: y_true, y_pred

Ваша функция будет (такой же, как и исходная)

def my_mse(A,B):
    mse = K.mean(K.pow(A - B, 2), axis=None)
    return mse

Однако проверьте API Keras, ему нужен скаляр для каждой точки данных, поэтому взятие среднего значения, вероятно, не будет работать таким образом с axis=None.

Я быстро взглянул на функции потерь, которые вы связали, и их реализация в Keras должна быть возможной и не слишком сложной. Keras (или на самом деле бэкэнд Tensorflow) имеет интерфейс, аналогичный numpy. Было бы полезно понять, как вычислительный граф бэкэнда (т. Е. Тензорного потока) работает для реализации потерь.

person skjerns    schedule 24.06.2018
comment
Спасибо за ваш быстрый ответ. То, что вы мне говорите, - это именно то, чего я боялся ;-) Я уже читал похожие сообщения в некоторых блогах, но хотел убедиться. Думаю, мне придется попытаться реализовать все это заново. Что ж, большое спасибо за ваш ответ, хотя это не то, что я хотел слышать ;-) - person Boris Reif; 25.06.2018