【问题标题】:Python, Keras custom loss function based on prediction, which is not the inputPython,Keras基于预测的自定义损失函数,不是输入
【发布时间】:2019-08-30 13:13:52
【问题描述】:

我正在尝试在 keras 中编写自定义损失函数,该函数基于训练期间模型的多次预测。 我有一个以前的列表/字典,例如 dict = {X1: [X2,X3,X4], X2:[X1, X6, X7]} 等。

给定输入 X1,我需要在训练期间预测 X2、X3、X4。

model.predict 不工作,报错 ValueError:将符号张量提供给模型时,我们希望张量具有静态批量大小。得到具有形状的张量:(None, 36)

from keras.layers import * 
from keras.models import Model
import keras.backend as K

input_tensor = Input(shape=(36,))
hidden       = Dense(100, activation='relu')(input_tensor)
out          = Dense(1, activation='linear')(hidden)

def custom_loss(input_tensor, dict):
    def inner(y_true, y_pred):
        X2 = dict[input_tensor][0]
        X3 = dict[input_tensor][1]
        X4 = dict[input_tensor][2]
        X2_pred = model.predict(X2)
        X3_pred = model.predict(X3)
        X4_pred = model.predict(X4)
        return K.mean(max(X2_pred, X3_pred, X4_pred)-y_true)

    return inner

custom_loss_final = custom_loss(input_tensor = input_tensor, dict = dict)

model        = Model(input_tensor, out)
model.compile(loss = custom_loss_final, optimizer='adam')

model.fit(x = Train_X, y = Train_y, batch_size= 100)

根据 Anakin 的解决方案进行编辑: 我试过你的代码,实际上在 np.append 我需要使用axis = 0。

现在我有: INPUT_X.shape (100, 36) INPUT_Y.shape (100,3,36)

INPUT_X:我有 100 个训练样本,每个都是 36 len 数组。
INPUT_Y:这些是 X2、X3 等。

实际上我的代码中甚至不需要 Y_true,因为我将使用模型(X2)等。

我按照你的建议将它们传递给 model.fit,在损失函数中我打印了一些类型/形状:
(输入张量)
(?, 36)
("y_true")
(?, ?)
(pred_y)
(?, 1)

我不知道为什么 y_true 形状是 (?,?) 而不是 (3,36)。我不能放模型(pred_y[:,0]),因为我得到:

ValueError:形状必须为 2 级,但对于“loss_56/dense_114_loss/model_57/dense_113/MatMul”(操作:“MatMul”)的输入形状为 1 级:[?]、[36,300]。
##为了清楚起见,现在隐藏层的大小是 300。

【问题讨论】:

  • 我不确定您到底想做什么。您想在自定义损失中使用输入张量吗?
  • 我想使用输入张量来查找 X2,X3,X4,但是正如您在下面建议的那样,直接使用 Train_X 传递会更容易,而不是在里面寻找它。
  • 您能否在类似于我的extra = data[:, 1:] 的自定义损失函数中以 numpy 数组的形式获取额外数据?你可以做x2 = data[ :, 0, :]x3 = data[:. 1, :]。验证检查切片。那么也许你需要将它们重塑为 (100, 36)。这是我的直觉。
  • 我想你的每个 X2、X3 等都有(None, 36)的形状
  • 不完全是,X2、X3 等具有 (36,) 形状。 (100,3,36) 表示 100 个训练样本,每个有 3 个 X-es,每个有 36 个 len。我在将张量 int 转换为数组时遇到问题(而且我不知道为什么要这样做,因为我可以 model() 一个张量。主要问题是它以错误的形式传递给函数(?,?形状,而不是 ? 36)

标签: python-3.x keras


【解决方案1】:

您可以使用输入中的额外数据列填充标签并编写自定义损失。您可以传递额外的预测信息 w.r.t.您的输入是像这样的 numpy 数组

    def custom_loss(data, y_pred):

        y_true = data[:, 0]
        extra = data[:, 1:]
        return K.mean(K.square(y_pred - y_true), axis=-1) + something with extra...


    def baseline_model():
        # create model
        i = Input(shape=(5,))
        x = Dense(5, kernel_initializer='glorot_uniform', activation='linear')(i)
        o = Dense(1, kernel_initializer='normal', activation='linear')(x)
        model = Model(i, o)
        model.compile(loss=custom_loss, optimizer=Adam(lr=0.0005))
        return model


    model.fit(X, np.append(Y_true, extra, axis =1), batch_size = batch_size, epochs=90, shuffle=True, verbose=1)

这个例子来自我的部分代码,但我希望你能明白。

【讨论】:

  • 谢谢!它将解决字典问题,因为我将输入及其对一起传递。 “如何预测”的另一个问题是另一个问题。我同时尝试了,也许如果我使用 model() 而不是 model.predict() 来完成这项工作。我会尝试并在这里写。
  • 我不认为在自定义损失函数中使用model.predict() 是一个特别好的主意。但我可能错了。如果您在当前训练过程之前已经知道其他预测值,您可以像我展示的那样用您的标签填充它们。不知道你有没有其他的限制。
  • 我认为使用 model 可以完成这项工作,确保 X2、X3 等是 numpy 数组而不是张量
  • 您能否在类似于我的extra = data[:, 1:] 的自定义损失函数中以 numpy 数组的形式获取额外数据?你可以做x2 = data[ :, 0, :]x3 = data[:. 1, :]。验证检查切片。那么也许你需要将它们重塑为 (100, 36)。这是我的直觉。
  • 只是一个更新,您的解决方案确实是正确的,我设法破解 X_... 值,方法是将它们附加到一维数组中,并输入 model.fit 二维(等级/形状)数组,如您所建议的。所以: np.append(Y_true, extra, axis =1) 必须是二维的。首先,我尝试使用超过 1 个维度 [每个 X 分成单独的维度],但它没有用。在那之后,在自定义损失中,我设法建立了它们。 x2 = data[ :, 0, :] 不起作用,因为无论我做什么,自定义损失中 y_true 的维度都是二维的。谢谢!
猜你喜欢
  • 2019-08-22
  • 1970-01-01
  • 2020-01-24
  • 2021-05-23
  • 1970-01-01
  • 2020-12-19
  • 2017-12-18
  • 2020-03-27
  • 1970-01-01
相关资源
最近更新 更多