Вопрос или проблема
Я новичок в этой области и учусь, решая небольшие задачи. Я работаю с нейронной сетью на несбалансированном наборе данных, но застрял на AUC 0.85, и, похоже, это не улучшается. На аналогичном наборе данных с lgbm я получаю 0.97. Также за 100 испытаний optuna AUC составляет около 0.84-0.85. Не знаю… это кажется странным. Является ли хорошим вариантом использовать “сбалансированный” как вес класса для несбалансированного набора данных?
def objective_nn(trial, X_train_tuning, y_train_tuning, class_weight_dict):
num_layers = trial.suggest_int('num_layers', 2, 5)
units = trial.suggest_int('units', 128, 512)
dropout_rate_input = trial.suggest_float('dropout_rate_input', 0.1, 0.3)
dropout_rate_hidden = trial.suggest_float('dropout_rate_hidden', 0.1, 0.3)
learning_rate = trial.suggest_float('learning_rate', 1e-4, 1e-3, log=True)
activation = trial.suggest_categorical('activation', ['relu', 'swish'])
optimizer_name = trial.suggest_categorical('optimizer', ['adam', 'adamw'])
l2_reg = trial.suggest_float('l2_reg', 1e-4, 1e-2, log=True)
batch_size = trial.suggest_categorical('batch_size', [16, 32])
skf = StratifiedKFold(n_splits=3, shuffle=True, random_state=RANDOM_STATE)
validation_aucs = []
for fold_index, (train_index, valid_index) in enumerate(skf.split(X_train_tuning, y_train_tuning)):
X_train_fold, X_valid_fold = X_train_tuning.iloc[train_index].reset_index(drop=True), X_train_tuning.iloc[valid_index].reset_index(drop=True)
y_train_fold, y_valid_fold = y_train_tuning.iloc[train_index].reset_index(drop=True), y_train_tuning.iloc[valid_index].reset_index(drop=True)
model = models.Sequential()
model.add(layers.Input(shape=(X_train_fold.shape[1],)))
model.add(layers.Dense(units, activation=activation, kernel_regularizer=regularizers.l2(l2_reg)))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(dropout_rate_input))
for _ in range(num_layers - 1):
model.add(layers.Dense(units, activation=activation, kernel_regularizer=regularizers.l2(l2_reg)))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(dropout_rate_hidden))
model.add(layers.Dense(1, activation='sigmoid'))
if optimizer_name == 'adam':
optimizer = optimizers.Adam(learning_rate=learning_rate)
elif optimizer_name == 'adamw':
optimizer = optimizers.AdamW(learning_rate=learning_rate)
model.compile(optimizer=optimizer, loss="binary_crossentropy", metrics=[tf.keras.metrics.AUC(name="auc")])
# Коллбеки
early_stopping = callbacks.EarlyStopping(monitor="val_auc", mode="max", patience=5, restore_best_weights=True)
reduce_lr = callbacks.ReduceLROnPlateau(monitor="val_loss", mode="min", factor=0.5, patience=3, verbose=0)
history = model.fit(
X_train_fold, y_train_fold,
validation_data=(X_valid_fold, y_valid_fold),
epochs=50,
batch_size=batch_size,
class_weight=class_weight_dict,
callbacks=[early_stopping, reduce_lr],
verbose=0
)
val_auc = max(history.history['val_auc'])
validation_aucs.append(val_auc)
return np.mean(validation_aucs)
train_df = pd.read_csv(DATA_PATH, encoding='utf-8')
train_df.columns = train_df.columns.str.lower()
X = train_df.drop(columns=['isfraud'])
y = train_df['isfraud']
plot_dir="/content/plots"
os.makedirs(plot_dir, exist_ok=True)
X = preprocess_data(X, MODE, DIR, SEED, plot_dir)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE, stratify=y)
tuning_subset_size = 0.2
X_train_tuning, _, y_train_tuning, _ = train_test_split(X_train, y_train, test_size=(1-tuning_subset_size), random_state=RANDOM_STATE, stratify=y_train)
class_weights = compute_class_weight(class_weight="balanced", classes=np.unique(y), y=y)
class_weight_dict = dict(enumerate(class_weights))
study = optuna.create_study(direction='maximize', study_name="maximize_auc")
study.optimize(lambda trial: objective_nn(trial, X_train_tuning, y_train_tuning, class_weight_dict), n_trials=N_TRIALS, n_jobs=40)
Ответ или решение
Выбор подхода для повышения AUC нейронной сети в условиях несбалансированных данных
В данной статье мы рассмотрим проблемы, связанные с застреванием на уровне AUC 0.85 при обучении нейронной сети на несбалансированном наборе данных, и предложим возможные пути их решения. Также мы проанализируем, почему результаты, полученные с помощью LightGBM, достигают AUC 0.97, и что можно сделать для улучшения модели нейронной сети.
1. Оценка текущего состояния модели
На первом этапе необходимо внимательно проанализировать структуру нейронной сети и ее гиперпараметры. Ваш подход в использовании Optuna для оптимизации гиперпараметров весьма уместен. Однако, очень важно понимать, что нейронные сети могут требовать значительных настроек, особенно при работе с несбалансированными наборами данных.
Ключевые моменты для анализа:
-
Гиперпараметры сети: Возможно, вам следует попробовать увеличивать или уменьшать количество единиц в слоях, а также количество слоев до тех пор, пока не появятся улучшения в AUC. Это также касается dropout rate и регуляризации L2. Некоторые комбинации могут быть слишком агрессивными или неэффективными.
-
Функции активации и оптимизаторы: Экспериментируйте с другими комбинациями активаций и оптимизаторов. Например, попробуйте использовать
LeakyReLU
илиELU
в качестве альтернативыReLU
, поскольку они легче справляются с затухающим градиентом. -
Классовые веса: Использование сбалансированных весов классов может оказаться полезным. Однако, стоит помнить, что проблема дисбаланса классов требует индивидуального подхода, и иногда применение сбалансированных весов может ухудшить общий результат.
2. Работа с несбалансированными данными
Несбалансированные данные могут серьезно влиять на эффективность модели. Если в вашем наборе данных количество объектов одного класса значительно превышает количество объектов другого, это может привести к недостаточной обучаемости для второго класса.
Рекомендации:
-
Переобучение или недообучение: Проверьте, не происходит ли переобучение модели. Так как AUC 0.85 дает представление о том, что модель, возможно, недостаточно сложна или переобучена. Следует проанализировать кривые обучения и в случае необходимости использовать более сложные архитектуры.
-
Аугментация данных: Попробуйте применять методы аугментации данных для увеличения представительства меньшинственного класса. Это поможет нейронной сети лучше учить различия между классами.
-
Смещение и подвыборка: Рассмотрите использование методов SMOTE или NearMiss для создания синтетических образцов меньшего класса или отбора образцов большего класса.
3. Перекрестная проверка и обучение
При настройке модели, вы используете StratifiedKFold
для оценки AUC. Это хороший подход, однако важно убедиться, что каждая выборка на этапе кросс-валидации адекватно отражает распределение классов.
Рекомендации:
-
Увеличение количества фолдов: Попробуйте увеличить количество фолдов в кросс-валидации для более надежной оценки.
-
Ошибка обучения: Проверьте значения потери и AUC на этапе обучения и валидации. Если вы видите значительное расхождение, это может свидетельствовать о проблемах в обучении.
4. Применение альтернативных моделей
Использование LightGBM дает более высокие AUC-значения. Это не случайно. LightGBM широко используется для работы с несбалансированными данными благодаря встроенным методам. Возможно, стоит провести дополнительный анализ того, почему именно этот алгоритм обеспечивает лучшие результаты и взять это в расчет при доработке нейронной сети.
Заключение
Ваш процесс обучения нейронной сети на несбалансированных данных требует тщательного анализа и экспериментов. Улучшение AUC от 0.85 до более высоких значений возможно, но потребует времени и ресурсов. Рассматривайте различные варианты улучшения архитектуры, подходы к обработке данных и методы оценки, чтобы стремиться к более высокому уровню предсказуемости. Не стесняйтесь использовать и комбинировать различные инструменты и шаблоны, чтобы находить оптимальные решения.