Пользовательская функция keras не будет вычисляться / компилироваться / соответствовать - PullRequest
0 голосов
/ 13 февраля 2019

Я пытаюсь использовать следующую (пользовательскую) функцию потерь для обучения нейронной сети keras:

y_pred и y_true - массивы длиной 40. Скажем, y_true равен 0 везде, кроме j-го компонента, где онравно 1, запишите y и z для y_true и y_pred соответственнозатем:

blank "> {i <40} (| ij | +1) \ cdot (y_i-z_i) ^ 2" title = "boostSquare (y, z) = \ sum_ {i <40}(| ij | +1) \ cdot (y_i-z_i) ^ 2 "/>

Вот код, который я намеревался использовать:

import keras.backend as K
def boost_square(y_true, y_pred):
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in 
                            range(40)]), dtype=np.float64)
    return K.sum(K.transpose(w * y_true) * K.square(y_true - y_pred))

Запуск этого работает и печатает 2,25, как и ожидалось:

y_true = np.array([int(i == 2) for i in range(40)])
y_pred = np.array([0.5 * int(i < 2) for i in range(40)])
print(K.eval(boost_square(y_true, y_pred)

Тем не менее, это не может быть скомпилировано со следующим сообщением об ошибке:

from keras.layers import Input, Dense
input_layer = Input(shape=(40,), name='input_layer')
output_layer = Dense(units=40, name='output_layer')(input_layer)
model = Model([input_layer], [output_layer])
model.compile(optimizer='adam', loss=boost_square, 
              metrics=['accuracy'])

TypeError: Вход 'y' из 'Mul' Op имеет тип float32, который делаетне соответствует типу float64 аргумента 'x'.

Так как я упрямый, я тоже попробовал это, что ничего не исправило и может снизить производительность:

def boost_square_bis(y_true, y_pred):
    z_true = K.cast(y_true, np.float64)
    z_pred = K.cast(y_pred, np.float64)
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in 
                   range(40)]), dtype=np.float64)
    boost = K.transpose(w * z_true)
    boost = K.cast(boost, dtype=np.float64)
    square = K.square(z_true - z_pred)
    square = K.cast(square, np.float64)
    ret = K.sum(boost * square)
    return K.cast(ret, dtype=np.float64)

Что мне не хватает?Откуда возникает эта ошибка?

Решение 1

Кредиты AnnaKrogager : d-тип w не совместим с моделью.Модель компилируется, когда определяется:

def boost_square(y_true, y_pred):
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in 
                            range(40)]), dtype=np.float64)
    return K.sum(K.transpose(w * y_true) * K.square(y_true - y_pred))

Итерация 1

Теперь модель компилируется, но не подходит, я получаю это сообщение об ошибке (128 - это batch_size):

ValueError: Размеры должны быть равны, но равны 40 и 128 для 'mul_2' (op: 'Mul') с входными формами: [40,40], [128,40].

Моя пользовательская функция потерь ведет себя странно по отношению к этой первой оси, этот код вызовет ту же ошибку:

fake_input = np.random.rand(128,40)
fake_output = np.random.rand(128,40)
print(K.eval(boost_square(fake_intput,fake_output)))

Итерация 2

Как указала AnnaKrogager, онаболее правильно использовать правильный np.dot, чем * с последующей транспозицией (которая портится с осью пакета).Итак, я придумал это новое определение boost_square:

def boost_square(y_true, y_pred):
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in 
                              range(40)]), dtype=np.float32)
    return K.sum(K.dot(w, y_true) * K.square(y_true - y_pred))

Но это вызывает следующее, когда я пытаюсь подогнать модель:

AttributeError: 'numpy.ndarray 'объект не имеет атрибута' get_shape '

Следовательно, я попытался

def boost_square(y_true, y_pred):
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in 
                             range(40)]), dtype=np.float32)
    return K.sum(K.dot(K.dot(w, y_true), K.square(y_true - y_pred)))

И получил новое сообщение об ошибке \ o /:

Размер матрицы несовместим: в [0]: [40,40], в [1]: [32,40]

Окончательное решение

Кредитыto AnnaKrogager

Ингредиенты

  1. Используйте правильный матричный продукт K.dot ratter чем *.
  2. Хотя w предназначался для применения к y_true, don 'не используйте K.dot (w, y_true), поскольку он портится с осью пакета.Повторите, используйте K.dot (y_true, w) и транспонируйте, чтобы получить совпадающие фигуры.
  3. Если вы хотите проверить функцию потерь с помощью np.arrays, скажем, y_true и y_pred, убедитесь, что вы изменили их как K.константа.

Вот код :

def boost_square(y_true, y_pred):
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in
                range(40)]), dtype=np.float32)
    return K.sum(K.dot(K.dot(y_true, w), K.transpose(K.square(y_true - 
                                                              y_pred))))

А для теста:

y_true = K.constant(np.array([[int(i == 2) for i in range(40)]], 
                             dtype=np.float32))
y_pred = K.constant(np.array([[0.5 * int(i < 2) for i in range(40)]], 
                    dtype=np.float32))
print(K.eval(boost_square(y_true,y_pred)))
>>2.25

1 Ответ

0 голосов
/ 13 февраля 2019

Проблема в том, что ваша модель выводит float32, тогда как константа w внутри вашей функции потерь имеет тип float64.Вы можете исправить это, просто изменив тип данных w:

def boost_square(y_true, y_pred):
    w = K.constant(np.array([[np.abs(i - j) + 1 for i in range(40)] for j in 
                            range(40)]), dtype=np.float32)
    return K.sum(K.transpose(w * y_true) * K.square(y_pred))

Ответ на второй вопрос: Если вы умножаете тензоры в Keras, это означает, что тензоры получают умноженный элементмудро, следовательно, они должны иметь одинаковую форму.Вам нужен матричный продукт, поэтому вы должны использовать K.dot(y, w) вместо w * y.

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