Пользовательская взвешенная функция потерь MSE в Keras на основе процентиля ошибок

Я новичок в Keras и нейронных сетях в целом. Я пытаюсь реализовать настраиваемую функцию потерь на основе среднеквадратичной ошибки для многослойного автокодировщика, который будет использоваться при обнаружении аномалий. В основном подход, к которому я стремлюсь, отсюда https://www.jstage.jst.go.jp/article/ipsjjip/27/0/27_335/_pdf

К сожалению, у меня нет репутации для публикации изображений, так как я тоже новичок в SO, но формула находится на странице 2, раздел 3 как Lprop

Интуиция здесь заключается в том, что я не хочу, чтобы автокодировщик обновлял веса для точек данных, которые возвращают ошибки выше ап-процентиля потерь. Таким образом, он учится восстанавливать выбросы в наборе данных, борясь с выбросами, следовательно, обнаруживая их как аномальные.

Вот код, который я пробовал, и скомпилированная модель

import keras.backend as K
c = 70.0
    def mean_squared_errorx(y_true, y_pred):
        es = K.square(y_pred - y_true)
        const = np.percentile(es, c)
        w = K.cast(K.less(const, K.mean(K.square(y_pred - y_true), axis=-1)), dtype = "float32")
        return w * K.mean(K.square(y_pred - y_true), axis=-1)

    #'mean_squared_error'
    autoencoder.compile(optimizer=adam, loss=mean_squared_errorx)
    autoencoder.fit(train, train,
                    epochs=num_epochs,
                    batch_size=round(len(train)/50),
                    shuffle=True,
                    validation_data=(train, train),
                    verbose = 0)
    encoded_d = encoder.predict(train)
    decoded_pred = decoder.predict(encoded_d)

Идея состоит в том, чтобы заставить K.less возвращать логическое значение для каждой ошибки, а затем преобразовывать его в число с плавающей запятой, которое будет использоваться в качестве веса в операторе возврата. Я знаю, что часть np.percentile, вероятно, не будет работать с Tensor, но не знаю, как еще выполнить процентильное ранжирование.

С этим кодом я получаю это сообщение об ошибке

InvalidArgumentError: Incompatible shapes: [37,21] vs. [37]
     [[{{node loss_25/dense_104_loss/Less}}]]

где в данном случае размер пакета составляет 37, а количество функций - 21. Я ценю любые отзывы об этой или других частях кода - спасибо!


person kidamar    schedule 17.07.2019    source источник


Ответы (1)


Найден потенциальный обходной путь, если кто-то работает над чем-то похожим

import keras.backend as K
    def mean_squared_error_w(y_true, y_pred):
        mses = K.mean(K.square(y_pred - y_true), axis = -1)
        std_of_mses = K.std(mses)
        const = K.mean(mses, axis = -1) + (std_of_mses * 0.5)
        mask = K.cast(K.less(K.mean(K.square(y_pred - y_true), axis=-1), const), dtype = "float32")
        return mask * K.mean(K.square(y_pred - y_true), axis=-1)

Я считаю, что это создаст тензор bools для всех значений, где ошибка больше порогового значения, определяемого средним значением MSE пакета плюс половина стандартного отклонения (если ошибки были нормально распределены, это должно соответствовать примерно 70-й процентиль данных в качестве порогового значения). Он преобразует булевые значения в веса 0 или 1 в качестве маски, которая затем применяется к выходным потерям MSE.

person kidamar    schedule 18.07.2019