Ошибка размера ввода пользовательской функции потерь (потеря фокуса) в Keras

Я использую нейтральную сеть для классификации по нескольким классам. Есть 3 несбалансированных класса, поэтому я хотел бы использовать фокусные потери, чтобы справиться с дисбалансом. Поэтому я использую настраиваемую функцию потерь, чтобы соответствовать последовательной модели Keras. Я пробовал несколько версий кода для функции фокальных потерь, которые нашел в Интернете, но они возвращают одно и то же сообщение об ошибке, в основном говоря, что размер ввода - это размер ванны, хотя ожидалось 1. Может ли кто-нибудь взглянуть на проблему и сообщить мне, если вы можете почини это? Я очень ценю это!!!

model = build_keras_model(x_train, name='training1')

class FocalLoss(keras.losses.Loss):
    def __init__(self, gamma=2., alpha=4.,
             reduction = tf.keras.losses.Reduction.AUTO, name='focal_loss'):

    super(FocalLoss, self).__init__(reduction=reduction,
                                    name=name)
    self.gamma = float(gamma)
    self.alpha = float(alpha)

def call(self, y_true, y_pred):

        epsilon = 1.e-9
        y_true = tf.convert_to_tensor(y_true, tf.float32)
        y_pred = tf.convert_to_tensor(y_pred, tf.float32)
        model_out = tf.add(y_pred, epsilon)
        ce = tf.multiply(y_true, -tf.math.log(model_out))
        weight = tf.multiply(y_true, tf.pow(
            tf.subtract(1., model_out), self.gamma))
        fl = tf.multiply(self.alpha, tf.multiply(weight, ce))
        reduced_fl = tf.reduce_max(fl, axis=1)
        return tf.reduce_mean(reduced_fl)

model.compile(optimizer = tf.keras.optimizers.Adam(0.001),
          loss = FocalLoss(alpha=1),
          metrics=['accuracy'])
​
class_weight = {0: 1.,
            1: 6.,
            2: 6.}

# fit the model (train for 5 epochs) history = model.fit(x=x_train, y=y_train, batch_size=64, epochs=5, class_weight = class_weight)

ValueError: Can not squeeze dim[0], expected a dimension of 1, got 64 for 'loss/output_1_loss/weighted_loss/Squeeze' (op: 'Squeeze') with input shapes: [64].

person user12328630    schedule 06.11.2019    source источник


Ответы (2)


Вы столкнулись с проблемой, заключающейся в том, что вы используете некий вспомогательный класс, который предназначен для выполнения некоторой логики за вас, но, к сожалению, в его документации не очень ясно, что именно он делает для вас и, следовательно, < em> что именно нужно делать самостоятельно.

В этом случае вы используете tf.keras.losses.Loss. Все, что вам нужно сделать, это реализовать call() (и, возможно, __init__). К сожалению, в документации вообще не говорится, что это ожидает возвращения call(). Но поскольку вам нужно указать reduction в __init__(), мы можем предположить, что ожидается, что call() вернет не только одно число. Иначе reduction был бы бесполезен. Другими словами: ошибка сообщает вам, что call() возвращает одно число, в то время как ожидается, что он вернет 64 числа (размер вашего пакета).

Итак, вместо того, чтобы самостоятельно сокращать пакет до одного числа (путем вызова tf.reduce_mean(reduced_fl)), позвольте вспомогательному классу сделать это за вас и просто вернуть reduced_f1 напрямую. В настоящее время вы используете reduction=tf.keras.losses.Reduction.AUTO, что, вероятно, вам и нужно.

person sebrockm    schedule 06.11.2019

Функции потерь Keras принимают пакет прогнозов и обучающих данных и используют их для создания тензора потерь. Один из способов реализации этого - просто определение функции с двумя тензорными входами, которая возвращает число, например

def mse(y_true, y_pred):
    return K.mean(K.square(y_pred - y_true), axis=-1)

Затем передайте это модели при компиляции, например

model.compile(optimizer = tf.keras.optimizers.Adam(0.001), loss = mse)
person Groger    schedule 06.11.2019