Взвешивание выборки не помогло в обучении несбалансированных данных

Я тренирую двухслойную сеть LSTM с 16-32 ячейками в каждом слое и имел довольно несбалансированный набор данных для обучения. Основываясь на моих семи частотах классов, веса выборки, вычисленные по простой формуле total_samples/class_frequency, равны [3,7, 5,6, 26,4, 3,2, 191,6, 8,4, 13,2], и я добавляю этот вес для каждой выборки в кортеж (data, метка) вывод моего генератора набора данных для запуска моих Kerasmodel.fit()функция. Код обучения был:

model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
mc = ModelCheckpoint(model_file, monitor='val_acc', mode='max', verbose=1, save_best_only=True)
es = EarlyStopping(monitor='val_acc', mode='max', verbose=1, patience=50)
history = model.fit(train_data, epochs=epochs, steps_per_epoch = train_steps, validation_data=val_data,
                            validation_steps = val_steps, verbose=verbose, callbacks=[es, mc])

Затем я использовал лучшую сохраненную модель, чтобы оценить ее и вычислить статистику производительности с помощью этого кода (мои данные находятся в наборах данных tensorflow):

saved_model = load_model(model_file)
iterator = test_data.make_one_shot_iterator()
next_element = iterator.get_next()
y_test = y_pred = np.empty(0)
for i in range(test_steps):
    batch = sess.run(next_element)
    x_test_batch = batch[0]
    y_test_batch = batch[1]
    y_pred_batch = saved_model.predict_on_batch(x_test_batch)
    y_test = np.append(y_test, np.argmax(y_test_batch, axis=1))
    y_pred = np.append(y_pred, np.argmax(y_pred_batch, axis=1))
print('\nTest data classification report:\n{}\n'.format(classification_report(y_test, y_pred)))

Но что я вижу в выходной статистике, так это то, что взвешенная статистика в целом хуже, чем невзвешенная (установка всех весов равными 1), даже для редких классов (самые высокие веса). Вот статистика:

Для утяжеленного бега:

     class     prec.     recall    f1       support
     0.0       1.00      0.97      0.98     79785
     1.0       0.89      0.88      0.88     52614
     2.0       0.61      0.76      0.68     11090
     3.0       0.96      0.93      0.95     91160
     4.0       0.59      0.92      0.72      1530
     5.0       0.89      0.90      0.89     34746
     6.0       0.81      0.87      0.84     22289

accuracy                           0.92    293214
macro avg      0.82      0.89      0.85    293214

Для невзвешенного пробега:

     class     prec.     recall    f1       support
     0.0       0.99      0.98      0.99     79785
     1.0       0.89      0.90      0.90     52614
     2.0       0.79      0.66      0.72     11090
     3.0       0.95      0.96      0.95     91160
     4.0       0.85      0.82      0.83      1530
     5.0       0.89      0.92      0.90     34746
     6.0       0.88      0.86      0.87     22289

accuracy                           0.93    293214
macro avg      0.89      0.87      0.88    293214

что здесь не так?

1 ответ

Вы должны использовать class_weight в fit функция или fit_generator применять веса к вашим классам.

Сначала вам нужно создать словарь с label:weight формат:

class_weight = {0: 3.7,
            1: 5.6,
            2: 2.64,...}

Затем примените его к своей функции соответствия:

history = model.fit(train_data, epochs=epochs, steps_per_epoch = train_steps, validation_data=val_data, 
                        class_weight=class_weight, validation_steps = val_steps, verbose=verbose, callbacks=[es, mc])

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

Другие вопросы по тегам