【问题标题】:Which loss function to use in Keras Sequential Model在 Keras 序列模型中使用哪种损失函数
【发布时间】:2021-09-08 13:14:25
【问题描述】:

我正在使用 Keras 顺序模型,预测输出的形状为 (1, 5)(5 个特征)。

我有一个准确度指标定义如下:

对于 N 个预测,模型的准确度将是预测样本的百分比,使得:对于每个预测及其各自的真实标签,所有特征的差异不超过 10。

例如,如果 y_i = [1, 2, 3, 4, 5]ypred_i = [1, 2, 3, 4, 16] 不匹配,因为最后一个特征的差异为 11。如果 y_i = [1, 2, 3, 4, 5]ypred_i = [10, 8, 0, 5, 7] 是匹配的,因为所有特征与其各自的差异不超过 10真实的特征。

我想知道在我的 Keras 序列模型中使用哪个损失函数来最大程度地提高解释的准确性。我应该定义一个自定义损失函数,它应该是什么样子,或者我应该如何进行?

我的代码是:

class NeuralNetMulti(Regressor):
    def __init__(self):
        self.name = 'keras-sequential'
        self.model = Sequential()
        # self.earlystopping = callbacks.EarlyStopping(monitor="mae",
        #                                              mode="min", patience=5,
        #                                              restore_best_weights=True)

    def fit(self, X, y):
        print('Fitting into the neural net...')
        n_inputs = X.shape[1]
        n_outputs = y.shape[1]
        self.model.add(Dense(400, input_dim=n_inputs, kernel_initializer='he_uniform', activation='relu'))
        # self.model.add(Dense(20, activation='relu'))
        self.model.add(Dense(200, activation='relu'))
        # self.model.add(Dense(10, activation='relu'))
        self.model.add(Dense(n_outputs))
        self.model.summary()
        self.model.compile(loss='mae', optimizer='adam', metrics=['mse', 'mae', 'accuracy'])
        history = self.model.fit(X, y, verbose=1, epochs=200, validation_split=0.1)
        # self.model.fit(X, y, verbose=1, epochs=1000, callbacks=[self.earlystopping])
        print('Fitting completed!')

    def predict(self, X):
        print('Predicting...')
        predictions = self.model.predict(X, verbose=1)
        print('Predicted!')
        return predictions

我对损失函数的建议:

def N_distance(y_true, y_pred):
    score = 0
    vals = abs(y_true - y_pred)
    if all(a <= 10 for a in vals):
            return 0
return 1

返回:

  • 0 如果条件成立
  • 1 否则。

【问题讨论】:

  • 请注意,使用当前方法(使用 mae 函数),我可以达到 55% 的准确度(55% 的样本符合上述条件)。但是我得到的rmse好像是7.5,非常不错,考虑到输出特征范围从0到100,感觉只需要使用更合适的损失函数即可。
  • 如果你推荐一个方法,我会使用它并运行它,看看它的执行情况。
  • 尝试使用阈值为 10 的 Huber loss 可能会有所帮助。tensorflow.org/api_docs/python/tf/keras/losses/Huber
  • 所以设置 self.model.compile(loss=tf.keras.losses.Huber(delta=10), optimizer='adam', metrics=['mse', 'mae', 'accuracy ']) ?
  • 我认为 Huber 损失与您的目标相反。 Huber 损失对异常值不太敏感,因为它返回二次损失,对于低于阈值的误差,但对于异常值是线性的。如果你对异常值比较敏感(10 以上),可以从 huber loss 中获取灵感,反向实现。

标签: python tensorflow keras neural-network loss-function


【解决方案1】:

首先,您的损失需要是可微的,以便可以计算相对于权重的梯度。然后可以使用梯度来优化权重,这是基于梯度的优化算法(如梯度下降)的重点。如果你写自己的损失,这是你需要记住的第一件事。这就是为什么你的损失不起作用的原因。你需要重新考虑你的损失或整个问题。

接下来,不要忘记,你需要在你的损失中使用 keras 或 tensorflow 函数,所以使用的函数定义了梯度并且可以应用链式法则。只使用abs() 不是一个好主意。这个问题可能会为您指明正确的方向https://ai.stackexchange.com/questions/26426/why-is-tf-abs-non-differentiable-in-tensorflow

此外,根据您的问题和 cmets,我看到预期的输出应该在 0 到 100 之间。在这种情况下,我会尝试缩放输出和网络的标签,使它们始终位于该范围内。有多种方法可以解决。将您的标签除以 100,然后在输出上使用 sigmoid 激活,或者检查例如这个答案How to restrict output of a neural net to a specific range?

然后你可以开始思考如何写你的损失。根据您的描述,尚不清楚在这种情况下会发生什么:y_i = [1, 2, 3, 4, 100]pred = [1, 2, 3, 4, 110]。 110 的值是否仍然可以接受,即使它在理论上是不可能的?

无论如何,您可以只使用maemse 作为损失。您的网络会尝试完美拟合,然后您可以使用特殊的不可微函数作为衡量您的网络根据您的规则训练的好坏的指标。

一个明确的例子:

  • 网络的最后一层需要像 self.model.add(Dense(n_outputs, activation='sigmoid')) 那样指定激活,它将所有网络输出缩放到从 0 到 1 的区间。
  • 由于您的标签是在 0 到 100 的区间内定义的,因此您只需将标签划分为也在 0 到 1 的区间内,然后再按y \= 100 在网络中使用它们。
  • 然后您可以使用maemse 作为损失,并将您的特殊函数用作度量。 self.model.compile(loss='mae', optimizer='adam', metrics=[custom_metric])

custom_metric 函数可能如下所示:

def custom_metric(y_true, y_pred):
    valid_distance = 0.1
    valid = tf.abs(y_true - y_pred) <= valid_distance
    return tf.reduce_mean(tf.cast(tf.reduce_all(valid, axis=1), tf.float32))

【讨论】:

  • 好的,所以使用 MSE 函数。是的,110 不是有效值。我尝试限制输出,但没有得到太大改善。还有其他想法吗?
  • 您是否使用sigmoid 激活函数限制了网络的输出,同时还将您的标签除以100,同时使用MSE 作为损失?在这种情况下,它应该学习。如果没有,问题可能出在其他地方。
  • sigmoid函数应该放在哪里?另外,在使用 MSE 时将标签除以 100 是什么意思?你能帮我解决这个问题吗? :)
  • 我用一个明确的例子更新了答案。
  • 我已经在“显式示例”的第二个要点中回答了这个问题。您应该划分以使所有内容都在同一范围内。
猜你喜欢
  • 2021-09-08
  • 2018-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-15
  • 1970-01-01
  • 2018-06-02
  • 2021-12-14
相关资源
最近更新 更多