Взвешивание выборки не помогло в обучении несбалансированных данных
Я тренирую двухслойную сеть 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
в подходящей функции.