Как работать с несбалансированными наборами данных при обучении нейронных сетей

#python #tensorflow #keras #imbalanced-data

Вопрос:

Я даже изо всех сил пытаюсь кратко, но ясно объяснить свой вопрос, поэтому я приложу все усилия, чтобы предоставить некоторую справочную информацию, прежде чем перейти непосредственно к вопросу.

Бракграунд

У меня очень несбалансированный набор данных, состоящий из 3 классов, 2 из которых являются классами меньшинств, и мне интересно их классифицировать.

Набор данных состоит из разреженных объектов и выглядит следующим образом:

 RA0 RA1 RA2 RA3 RA4 RA5 RA6 RA7 RA8 RA9 ... RB1 RB2 RB3 RB4 RB5 RB6 RB7 RB8 RB9 label
-------------------------------------------------------------------------------------
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  2
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  1
0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  1
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  1
 

Этот набор данных очень несбалансирован, так как значения для меток следующие:

 df.label.value_counts()/len(df)
>0    0.944352
>1    0.028622
>2    0.027025
 

RAX Объекты соответствуют метке 1, а RBX объекты соответствуют метке 2. Почему эти две метки «смешаны» с этими двумя различными типами функций? Исходные данные представляют собой временные ряды, а метки представляют «состояние» временных рядов.

Итак, я снова и снова пробовал методы выборки, чтобы попытаться «сбалансировать» набор данных, но в данном случае, похоже, лучше работало то, что я пытался найти class_weights метки с помощью поиска по сетке.

Я попытался выполнить поиск по сетке, используя roc_auc оценку, а затем обучение нейронной сети для классификации, но я борюсь с частью показателей. Модель выглядит следующим образом:

  import tensorflow as tf

 def seq_model(n_features=20,init_neurons=170,decay=0.25,layers=3,lr=0.0001,activation1 = 'relu',activation2='relu'):
    model = Sequential()
    model.add(Dense(n_features, input_dim=n_features, activation=activation1))
    actual_neurons = init_neurons
    for i in range(layers):
        actual_neurons = int(actual_neurons*(1-decay*i))
        if actual_neurons <=0:
            break
        model.add(Dense(actual_neurons,activation = activation2))
    model.add(Dense(3,activation = 'softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=[tf.keras.metrics.AUC()])
    return model
 

И после запуска a GridSearch я понял , что лучший вес класса для этого набора данных был {0: 1, 1: 95, 2: 95} . Затем, после выполнения GridSearch я обучил модель, но я заметил, что Keras она больше не поддерживает roc_auc кривую для показателей (например accuracy ), поэтому, прочитав другие вопросы и ответы в SO, я пришел к следующему:

 class RocCallBack(Callback):
    def __init__(self,training_data,validation_data):
        self.x = training_data[0]
        self.y = training_data[1]
        self.x_val = validation_data[0]
        self.y_val = validation_data[1]
        
    def on_train_begin(self,logs={}):
        return
    def on_train_end(self, logs={}):
        return
    
    def on_epoch_begin(self,epoch,logs={}):
        return
    
    def on_epoch_end(self,epoch,logs={}):
        y_pred_train = self.model.predict_proba(self.x)
        roc_train = roc_auc_score(self.y,y_pred_train)
        y_pred_val = self.model.predict_proba(self.x_val)
        roc_val = roc_auc_score(self.y_val,y_pred_val)
        print('rroc-auc_train: %s - roc-auc_val: %s' % (str(round(roc_train,4)),str(round(roc_val,4))),end=100*' ' 'n')
        return
    
    def on_batch_begin(self, batch, logs={}):
        return

    def on_batch_end(self, batch, logs={}):
        return

roc = RocCallBack(training_data=(x_train.values,y_train2),
                 validation_data = (x_test.values,y_test2))

early_stopping = EarlyStopping(patience = 100,verbose = True,monitor='val_auc',restore_best_weights=True)
check_point = ModelCheckpoint('classifier.hdf5',verbose=1,save_best_only=True,monitor = 'val_auc')

y_train2 = to_categorical(y_train)
y_test2 = to_categorical(y_test)

history = model.fit(x_train.values,y_train2, 
                    epochs = 50000,
                    batch_size = 24,
                    validation_data=(x_test.values,y_test2),
                    shuffle = False,
                    class_weight={0: 1, 1: 95, 2: 95},
                   callbacks=[roc,early_stopping,check_point])
 

Вопросы:

а) Во время обучения я заметил, что модель пытается минимизировать val_auc значение, чего я не ожидал, потому что думал, что идея заключалась в том, чтобы максимизировать его. Это нормально или я допустил какую-то ошибку в процессе?

б) Для оптимизации roc_auc (и, следовательно, повышения точности, верно?) правильно ли вводить tf.keras.metrics.AUC() модель в качестве метрики? Если нет, то как это следует сделать, чтобы добиться хорошей производительности?

в) При нахождении оптимальных весов для классов я не должен использовать accuracy их в качестве метрики, верно? Является roc_auc ли лучшая метрика, которую я мог бы использовать для этих случаев?

Мне действительно жаль, если это был длинный пост, но я все еще учусь работать с наборами данных такого типа, и любая помощь будет признательна. Я также могу предоставить любую другую информацию, если это необходимо.

Комментарии:

1. Стандартные способы работы с несбалансированными наборами данных-это подвыборка, передискретизация или синтетические выборки. Для несбалансированных вы правы, точность-это плохо. Используйте другую метрику, учитывающую стоимость

2. @IanQuah Спасибо за ваш ответ. Я пробовал под и над выборкой, но не получил очень хороших результатов. Я действительно попробовал их с точностью в качестве метрики. Или я должен использовать, например, над выборкой вес класса roc auc? Какой еще показатель вы бы мне порекомендовали?

3. Точность — плохой показатель. Если у вас 99% класса А, и вы всегда угадываете «А», ваша точность составляет 99%, но это не очень хороший результат. Я бы просто погуглил несбалансированные потери в классе