Есть ли в керасе оптимизатор, основанный на точности или отзыве вместо потери? - PullRequest
0 голосов
/ 27 августа 2018

Я разрабатываю нейронную сеть сегментации только с двумя классами, 0 и 1 (0 - это фон, а 1 - объект, который я хочу найти на изображении). На каждом изображении присутствует около 80% от 1 и 20% от 0. Как видите, набор данных не сбалансирован, и это приводит к неверным результатам. Моя точность составляет 85%, и моя потеря низка, но это только потому, что моя модель хороша в поиске фона!

Я хотел бы основать оптимизатор на другом показателе, таком как точность или отзыв, который в этом случае более полезен.

Кто-нибудь знает, как это реализовать?

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

поскольку наш комментарий был недостаточно ясен, позвольте мне дать вам код, чтобы отслеживать то, что вам нужно. Вы не используете точность или отзыв, чтобы оптимизировать. Вы просто отслеживаете их как действительные оценки, чтобы получить лучшие веса. Не смешивайте потери, оптимизаторы, метрики и прочее. Они не предназначены для одного и того же.

def precision(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
    beta = 1

    # just in case of hipster activation at the final layer
    y_pred = K.clip(y_pred, 0, 1)

    # shifting the prediction threshold from .5 if needed
    y_pred_bin = K.round(y_pred + threshold_shift)

    tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
    fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
    fn = K.sum(K.round(K.clip(y_true - y_pred, 0, 1)))

    precision = tp / (tp + fp)
    return precision


def recall(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
    beta = 1

    # just in case of hipster activation at the final layer
    y_pred = K.clip(y_pred, 0, 1)

    # shifting the prediction threshold from .5 if needed
    y_pred_bin = K.round(y_pred + threshold_shift)

    tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
    fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
    fn = K.sum(K.round(K.clip(y_true - y_pred_bin, 0, 1)))

    recall = tp / (tp + fn)
    return recall


def fbeta(y_true, y_pred, threshold_shift=0.5-THRESHOLD):
    beta = 2

    # just in case of hipster activation at the final layer
    y_pred = K.clip(y_pred, 0, 1)

    # shifting the prediction threshold from .5 if needed
    y_pred_bin = K.round(y_pred + threshold_shift)

    tp = K.sum(K.round(y_true * y_pred_bin)) + K.epsilon()
    fp = K.sum(K.round(K.clip(y_pred_bin - y_true, 0, 1)))
    fn = K.sum(K.round(K.clip(y_true - y_pred, 0, 1)))

    precision = tp / (tp + fp)
    recall = tp / (tp + fn)

    beta_squared = beta ** 2
    return (beta_squared + 1) * (precision * recall) / (beta_squared * precision + recall) 


def model_fit(X,y,X_test,y_test):
    class_weight={
    1: 1/(np.sum(y) / len(y)),
    0:1}
    np.random.seed(47)
    model = Sequential()
    model.add(Dense(1000, input_shape=(X.shape[1],)))
    model.add(Activation('relu'))
    model.add(Dropout(0.35))
    model.add(Dense(500))
    model.add(Activation('relu'))
    model.add(Dropout(0.35))
    model.add(Dense(250))
    model.add(Activation('relu'))
    model.add(Dropout(0.35))
    model.add(Dense(1))
    model.add(Activation('sigmoid'))

    model.compile(loss='binary_crossentropy', optimizer='adamax',metrics=[fbeta,precision,recall])
    model.fit(X, y,validation_data=(X_test,y_test), epochs=200, batch_size=50, verbose=2,class_weight = class_weight)
    return model
0 голосов
/ 27 августа 2018

Нет. Чтобы сделать «градиентный спуск», вам нужно вычислить градиент. Для этого функция должна быть как-то плавной. Точность / отзыв или точность не является гладкой функцией, она имеет только острые края, на которых градиент равен бесконечности, и ровные места, на которых градиент равен нулю. Следовательно, вы не можете использовать какой-либо численный метод, чтобы найти минимум такой функции - вам придется использовать какую-то комбинаторную оптимизацию, и это будет NP-сложным.

...