自定义损失函数,Keras \\ ValueError:无渐变

时间:2020-09-04 21:39:29

标签: python tensorflow object keras

我正在尝试将我的Keras神经网络包装在class对象中。我已经在类设置之外实现了以下内容,但我想使其更加对象友好。 总而言之,我的model调用了函数sequential_model,该函数创建了一个sequential模型。在compile步骤中,我定义了自己的损失函数weighted_categorical_crossentropy,我希望该模型能够实现。 但是,当我运行下面的代码时,出现以下错误:ValueError: No gradients provided for any variable:

我怀疑问题出在我如何定义weighted_categorical_crossentropy使用sequential函数的地方。

同样,我能够以非面向对象的方式来完成这项工作。任何帮助将不胜感激。

from tensorflow.keras import Sequential, backend as K

class MyNetwork(): 
        
    def __init__(self, file, n_output=4, n_hidden=20, epochs=3,
                 dropout=0.10, batch_size=64, metrics = ['categorical_accuracy'],
                 optimizer = 'rmsprop', activation = 'softmax'):

    [...] //Other Class attributes
 
    def model(self):
        self.model = self.sequential_model(False)
        self.model.summary()


    def sequential_model(self, val):
        K.clear_session()
        if val == False:
            self.epochs = 3
        regressor = Sequential()
        #regressor.run_eagerly = True
        regressor.add(LSTM(units = self.n_hidden, dropout=self.dropout, return_sequences = True, input_shape = (self.X.shape[1], self.X.shape[2])))
        regressor.add(LSTM(units = self.n_hidden, dropout=self.dropout, return_sequences = True))
        regressor.add(Dense(units = self.n_output, activation=self.activation))
    
        self.weights = np.array([0.025,0.225,0.78,0.020])

        regressor.compile(optimizer = self.optimizer, loss = self.weighted_categorical_crossentropy(self.weights), metrics = [self.metrics])
        regressor.fit(self.X, self.Y*1.0,batch_size=self.batch_size, epochs=self.epochs, verbose=1, validation_data=(self.Xval, self.Yval*1.0))

        return regressor

    def weighted_categorical_crossentropy(self, weights):
        weights = K.variable(weights)
        def loss(y_true, y_pred):
            y_pred /= K.sum(y_pred, axis=-1, keepdims=True)
            y_pred = K.clip(y_pred, K.epsilon(), 1 - K.epsilon())
            loss = y_true * K.log(y_pred) * weights
            loss = -K.sum(loss, -1)
            return loss

1 个答案:

答案 0 :(得分:2)

上述代码存在一些问题,但最值得注意的是您没有从loss返回weighted_categorical_crossentropy。它看起来应该更像:

    def weighted_categorical_crossentropy(self, weights):
        weights = K.variable(weights)
        def loss(y_true, y_pred):
            y_pred /= K.sum(y_pred, axis=-1, keepdims=True)
            y_pred = K.clip(y_pred, K.epsilon(), 1 - K.epsilon())
            loss = y_true * K.log(y_pred) * weights
            loss = -K.sum(loss, -1)
            return loss
        return loss # Return the callable function!

错误为ValueError: No gradients provided for any variable,因为丢失方法 不返回任何内容,它返回None!如果尝试使用loss=None拟合方法,则该模型将无法计算梯度,因此将引发相同的确切误差。

下一步是在非经常性图层之前的图层中使用return_sequences = True。这将导致Dense层在格式错误的数据上被调用,这仅适用于循环层。不要那样使用。
如果您有充分的理由使用return_sequences = True,则必须添加Dense层,例如:

model.add(keras.layers.TimeDistributed(keras.layers.Dense(...)))

这将导致Dense层在每个时间步 上分别作用于输出序列。这也意味着您的y_true必须具有适当的形状。

您定义的自定义损失函数可能还有其他问题,但是我无法推断出输入/输出形状,因此您必须运行它并添加它是否有效。可能会出现矩阵乘法形状不匹配的情况。

最后但并非最不重要的一点,请考虑使用Sub-classing API。它可以使您的任何操作更容易编写吗?

感谢您的阅读,我将在得到该信息后更新此答案。干杯。