我正在尝试使用以下(自定义)损失函数来训练keras神经网络:
y_pred和y_true是长度为40的数组。 假设y_true在所有地方都为0,但在第j个分量上等于1, 为y_true和y_pred分别写y和z。然后:
空白> {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:“ Mul” Op的输入“ y”具有类型float32,与参数“ x”的类型float64不匹配。
由于我很固执,所以我也尝试过此方法,它不能解决任何问题,并且可能会影响性能:
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)
我想念什么?这个错误是从哪里来的?
对AnnaKrogager的致谢:w的dtype与模型不兼容。的 模型在定义时进行编译:
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))
现在,模型可以编译但不适合,我收到此错误消息(128是batch_size):
ValueError:尺寸必须相等,但对于输入形状为[40,40],[128,40]的“ mul_2”(操作数:“ Mul”),尺寸应分别为40和128。
我的自定义损失函数相对于第一个轴的行为确实很奇怪, 该代码将引发非常相同的错误:
fake_input = np.random.rand(128,40)
fake_output = np.random.rand(128,40)
print(K.eval(boost_square(fake_intput,fake_output)))
正如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 /:
与矩阵大小不兼容:In [0]:[40,40],In [1]:[32,40]
AnnaKrogager的积分
这是代码:
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
答案 0 :(得分:1)
问题是模型输出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
。