keras自定义函数不会评估/编译/拟合

时间:2019-02-13 09:29:01

标签: python tensorflow keras loss-function

我正在尝试使用以下(自定义)损失函数来训练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)

我想念什么?这个错误是从哪里来的?

解决方案1 ​​

对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))

迭代1

现在,模型可以编译但不适合,我收到此错误消息(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)))

迭代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 /:

  

与矩阵大小不兼容:In [0]:[40,40],In [1]:[32,40]

最终解决方案

AnnaKrogager的积分

成分

  1. 使用比*合适的矩阵乘积K.dot ratter。
  2. 尽管w应该应用于y_true,但是不要使用K.dot(w,y_true),因为 它与批处理轴混乱。说话者,使用K.dot(y_true,w)并转置为具有匹配形状。
  3. 如果要使用np.arrays测试损失函数,请说y_true和y_pred,请确保将其重铸为K.constant。

这是代码

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 :(得分: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