使用自定义损失函数处理多类分类中的类不平衡

问题描述 投票:0回答:1

我正在使用先进的机器学习技术来解决 Python 中的多类分类问题。我正在处理的数据集存在严重的类别不平衡问题,其中某些类别与其他类别相比代表性不足。这种不平衡对我的模型的性能产生了不利影响,特别是对于少数群体。

为了解决这个问题,我正在考虑实现一个自定义损失函数,它可以更好地处理类不平衡问题。我正在使用 TensorFlow/Keras 进行模型开发。我当前的模型结构如下:

import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

# Example model architecture
model = Sequential([
    Dense(128, activation='relu', input_shape=(input_shape,)),
    Dense(64, activation='relu'),
    Dense(num_classes, activation='softmax')
])

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

这里,num_classes 表示数据集中的类数,input_shape 是输入特征的形状。问题在于损失函数“categorical_crossentropy”,它没有考虑类别不平衡。

我正在寻找一种创建自定义损失函数的方法,该函数可以将类别权重集成到计算中,从而在训练期间更加重视少数类别。这是我的具体问题:

如何在 TensorFlow/Keras 中开发自定义损失函数,其中包含多类分类问题的类权重? 确保此自定义损失函数计算效率高且不会对训练时间产生显着负面影响的最佳实践是什么? 在实现自定义损失函数来处理类别不平衡时,我应该注意哪些潜在的陷阱或常见错误?

python tensorflow machine-learning keras loss-function
1个回答
0
投票

幸运的是,

keras
具有内置功能,可以在计算
loss
时对数据进行加权,因此不需要自定义函数。

由于您尚未粘贴任何有关输入数据的代码,我假设您正在使用

tf.data.Dataset
,因为这是加载数据的推荐方法。根据这篇SO post,我们可以简单地使用
tf.data.Dataset
返回第三个值,该值将用作样本权重。您可以在下面找到一个使用您的模型定义的完全可重现的示例。要查看
weight
的效果,只需在
comment/uncomment
line 44
即可。

PS:如果您想了解有关

downsampling
/
upsampling
以及如何权衡数据的更多信息,请参阅 Google 提供的一些有用的 文档

import random

import pandas as pd
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

#fix seeds
tf.keras.utils.set_random_seed(
    42
)
random.seed(42)

# column definitions
LABEL_COLUMN = 'label'
WEIGHT_COLUMN = 'weight'
NUMERIC_COLS = ['col_1', 'col_2']
LABELS = [0, 1, 2]

# generate some example data
col_1 = [i for i in range(1,101)]
col_2 = [i for i in range(1,101)]
col_3 = [random.choice([0, 1, 2]) for i in range(1, 101)]
col_4 = [random.choice([1, 3, 1]) for i in range(1, 101)]

data = {
    'col_1': col_1,
    'col_2': col_2,
    'label': col_3,
    'weight': col_4
}

df = pd.DataFrame(data)

# create tf.data.Dataset
def prep_data(row_data):

    _label = row_data.pop(LABEL_COLUMN)
    weight = row_data.pop(WEIGHT_COLUMN)

    label = tf.one_hot(_label, len(LABELS))

    # return row_data.values(), label, weight
    return row_data.values(), label


ds = tf.data.Dataset.from_tensor_slices(dict(df))
ds = ds.map(map_func=prep_data)
ds = ds.batch(16)

# create model
# Example model architecture
model = Sequential([
    Dense(128, activation='relu', input_shape=(len(NUMERIC_COLS),)),
    Dense(64, activation='relu'),
    Dense(len(LABELS), activation='softmax')
])

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# fit model
model.fit(
    ds, epochs=1, verbose=1
)

# using weight
# 7/7 [==============================] - 4s 6ms/step - loss: 4.6744 - accuracy: 0.3500
# weight commented out
# 7/7 [==============================] - 1s 5ms/step - loss: 2.7758 - accuracy: 0.3300
© www.soinside.com 2019 - 2024. All rights reserved.