Я пытаюсь использовать следующую (пользовательскую) функцию потерь для обучения нейронной сети 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
Ингредиенты
- Используйте правильный матричный продукт K.dot ratter чем *.
- Хотя w предназначался для применения к y_true, don 'не используйте K.dot (w, y_true), поскольку он портится с осью пакета.Повторите, используйте K.dot (y_true, w) и транспонируйте, чтобы получить совпадающие фигуры.
- Если вы хотите проверить функцию потерь с помощью 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