You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AI分类模型不平衡数据集进阶处理方法问询(TensorFlow/PyTorch)

针对高度不平衡数据集的深度学习分类进阶优化方案

我正在处理一个高度不平衡数据集的机器学习分类任务,担心模型性能表现。已经尝试过过采样、欠采样、类别加权等基础方法,现在想了解针对AI分类模型的更高级或高效的不平衡数据集处理方法。

以下是我用TensorFlow编写的Python代码片段:

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

# Load and preprocess the imbalanced dataset
# ...

# Define and compile the model
model = Sequential([
    Dense(64, activation='relu', input_shape=(input_dim,)),
    Dense(32, activation='relu'),
    Dense(num_classes, activation='softmax')
])

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

# Train the model
model.fit(X_train, y_train, epochs=10, batch_size=32, verbose=1)

请问在TensorFlow或PyTorch等深度学习框架中,有哪些可提升模型性能与鲁棒性的针对性技术或进阶方案?


一、自定义损失函数:聚焦难分类样本

基础类别加权交叉熵对所有错误样本权重一致,Focal Loss通过降低易分类样本的权重,让模型优先关注少数类和难分类样本,是不平衡场景的核心优化手段。

TensorFlow实现:

class FocalLoss(tf.keras.losses.Loss):
    def __init__(self, alpha=0.25, gamma=2.0, name='focal_loss'):
        super().__init__(name=name)
        self.alpha = alpha
        self.gamma = gamma

    def call(self, y_true, y_pred):
        y_true = tf.one_hot(tf.cast(y_true, tf.int32), depth=y_pred.shape[-1])
        ce = tf.keras.losses.categorical_crossentropy(y_true, y_pred)
        p = tf.reduce_max(y_pred, axis=-1)
        pt = tf.where(tf.equal(y_true, 1), p, 1 - p)
        loss = self.alpha * tf.pow(1 - pt, self.gamma) * ce
        return tf.reduce_mean(loss)

# 替换原有损失函数
model.compile(optimizer='adam',
              loss=FocalLoss(alpha=0.25, gamma=2.0),
              metrics=['accuracy'])

PyTorch实现:

import torch
import torch.nn as nn

class FocalLoss(nn.Module):
    def __init__(self, alpha=0.25, gamma=2.0, reduction='mean'):
        super().__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.reduction = reduction

    def forward(self, y_pred, y_true):
        ce_loss = nn.CrossEntropyLoss(reduction='none')(y_pred, y_true)
        pt = torch.exp(-ce_loss)
        focal_loss = self.alpha * (1 - pt)**self.gamma * ce_loss
        return torch.mean(focal_loss) if self.reduction == 'mean' else focal_loss

# 初始化损失函数
criterion = FocalLoss(alpha=0.25, gamma=2.0)

二、进阶采样策略:动态调整样本分布

1. 困难负样本挖掘

筛选模型分类错误的难样本(多数类中的难分类样本、所有少数类样本),优先用这些样本更新模型,提升对少数类的识别能力。

TensorFlow实现(结合tf.data):

def hard_negative_mining(dataset, model, batch_size):
    def get_loss(sample):
        x, y = sample
        y_pred = model(x, training=False)
        loss = tf.keras.losses.sparse_categorical_crossentropy(y, y_pred)
        return loss, x, y

    loss_ds = dataset.map(get_loss)
    sorted_ds = loss_ds.shuffle(len(dataset)).sorted(lambda loss, _, __: -loss)
    hard_ds = sorted_ds.map(lambda _, x, y: (x, y)).batch(batch_size)
    return hard_ds

# 使用难样本数据集训练
hard_train_ds = hard_negative_mining(train_ds, model, 32)
model.fit(hard_train_ds, epochs=10)

PyTorch实现(自定义Sampler):

from torch.utils.data import WeightedRandomSampler

def get_hard_sampler(dataloader, model):
    model.eval()
    losses = []
    with torch.no_grad():
        for x, y in dataloader:
            y_pred = model(x)
            loss = nn.CrossEntropyLoss(reduction='none')(y_pred, y)
            losses.extend(loss.tolist())
    weights = torch.tensor(losses)
    sampler = WeightedRandomSampler(weights, num_samples=len(weights), replacement=True)
    return sampler

# 生成难样本采样器并训练
hard_sampler = get_hard_sampler(train_loader, model)
hard_train_loader = torch.utils.data.DataLoader(train_dataset, sampler=hard_sampler, batch_size=32)

for epoch in range(10):
    model.train()
    for x, y in hard_train_loader:
        optimizer.zero_grad()
        y_pred = model(x)
        loss = criterion(y_pred, y)
        loss.backward()
        optimizer.step()

2. 自适应混合采样

训练初期对少数类过采样,后期逐步降低过采样比例;同时对多数类选择性欠采样,仅保留难分类样本,平衡训练过程中的样本分布。

三、模型结构优化:增强少数类特征捕捉

1. 添加注意力机制

让模型自动关注对分类关键的特征,尤其是少数类样本的独特特征。

TensorFlow实现:

class AttentionLayer(tf.keras.layers.Layer):
    def __init__(self, units):
        super().__init__()
        self.W = Dense(units)
        self.V = Dense(1)

    def call(self, inputs):
        inputs = tf.expand_dims(inputs, axis=1)
        score = self.V(tf.nn.tanh(self.W(inputs)))
        attention_weights = tf.nn.softmax(score, axis=1)
        context_vector = attention_weights * inputs
        return tf.reduce_sum(context_vector, axis=1)

# 修改原有模型
model = Sequential([
    Dense(64, activation='relu', input_shape=(input_dim,)),
    AttentionLayer(32),
    Dense(32, activation='relu'),
    Dense(num_classes, activation='softmax')
])

PyTorch实现:

class AttentionLayer(nn.Module):
    def __init__(self, units):
        super().__init__()
        self.W = nn.Linear(units, units)
        self.V = nn.Linear(units, 1)

    def forward(self, x):
        x = x.unsqueeze(1)
        score = torch.tanh(self.W(x))
        attention_weights = torch.softmax(self.V(score), dim=1)
        context_vector = attention_weights * x
        return torch.sum(context_vector, dim=1)

# 修改原有模型
model = nn.Sequential(
    nn.Linear(input_dim, 64),
    nn.ReLU(),
    AttentionLayer(32),
    nn.Linear(32, 32),
    nn.ReLU(),
    nn.Linear(32, num_classes),
    nn.Softmax(dim=1)
)

2. 对比学习预训练

先通过自监督对比学习让模型学习通用特征,再用少量标签数据微调分类器,有效利用未标注数据,提升对少数类的特征提取能力。

TensorFlow实现(简化版):

# 定义对比学习模型
class ContrastiveModel(tf.keras.Model):
    def __init__(self, feature_dim=64):
        super().__init__()
        self.encoder = Sequential([
            Dense(128, activation='relu', input_shape=(input_dim,)),
            Dense(feature_dim, activation='relu')
        ])
        self.projection_head = Sequential([Dense(64, activation='relu'), Dense(32)])

    def call(self, x):
        return self.projection_head(self.encoder(x))

# NT-Xent对比损失
def nt_xent_loss(z1, z2, temperature=0.1):
    z = tf.concat([z1, z2], axis=0)
    cos_sim = tf.matmul(z, tf.transpose(z)) / temperature
    mask = tf.eye(tf.shape(z)[0], dtype=tf.bool)
    cos_sim = tf.where(mask, -1e9 * tf.ones_like(cos_sim), cos_sim)
    labels = tf.concat([tf.range(tf.shape(z1)[0]), tf.range(tf.shape(z1)[0])], axis=0)
    return tf.reduce_mean(tf.keras.losses.sparse_categorical_crossentropy(labels, cos_sim, from_logits=True))

# 预训练对比模型
contrast_model = ContrastiveModel()
optimizer = tf.keras.optimizers.Adam()

@tf.function
def train_step(x1, x2):
    with tf.GradientTape() as tape:
        loss = nt_xent_loss(contrast_model(x1), contrast_model(x2))
    gradients = tape.gradient(loss, contrast_model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, contrast_model.trainable_variables))
    return loss

# x1、x2为同一样本的两种增强版本(如加噪声、裁剪)
for epoch in range(50):
    loss = train_step(x1_augmented, x2_augmented)

# 用预训练编码器初始化分类模型
classifier_model = Sequential([
    contrast_model.encoder,
    Dense(32, activation='relu'),
    Dense(num_classes, activation='softmax')
])
classifier_model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
classifier_model.fit(X_train, y_train, epochs=10)

四、训练策略调整:提升模型鲁棒性

1. 标签平滑

给标签添加小噪声,降低模型对多数类的过度自信,减少过拟合,提升对少数类的泛化能力。

TensorFlow实现:

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(label_smoothing=0.1),
              metrics=['accuracy'])

PyTorch实现:

criterion = nn.CrossEntropyLoss(label_smoothing=0.1)

2. 混合数据增强(MixUp/CutMix)

混合不同样本的特征与标签生成新样本,增加数据多样性,帮助模型学习通用特征,减少对多数类的依赖。

TensorFlow实现(MixUp):

def mixup_data(x, y, alpha=0.2):
    lam = np.random.beta(alpha, alpha)
    batch_size = tf.shape(x)[0]
    index = tf.random.shuffle(tf.range(batch_size))
    mixed_x = lam * x + (1 - lam) * tf.gather(x, index)
    mixed_y = lam * tf.one_hot(y, num_classes) + (1 - lam) * tf.one_hot(tf.gather(y, index), num_classes)
    return mixed_x, mixed_y

@tf.function
def train_step(x, y):
    with tf.GradientTape() as tape:
        x_mixed, y_mixed = mixup_data(x, y)
        y_pred = model(x_mixed, training=True)
        loss = tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_mixed, y_pred))
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    return loss

# 训练循环
for epoch in range(10):
    for x_batch, y_batch in train_ds:
        loss = train_step(x_batch, y_batch)

五、评估指标优化:避免被准确率误导

不平衡数据集下准确率无参考价值,需使用以下指标:

  • 加权F1-Score:综合精确率与召回率
  • Precision-Recall曲线:更适合极不平衡场景
  • 混淆矩阵:直观展示类别分类情况
  • Cohen's Kappa:衡量模型与随机分类的差异

TensorFlow/PyTorch通用指标计算:

from sklearn.metrics import f1_score, confusion_matrix, cohen_kappa_score

# TensorFlow:获取预测结果
y_pred = model.predict(X_test)
y_pred_classes = tf.argmax(y_pred, axis=1).numpy()

# PyTorch:获取预测结果
# model.eval()
# y_pred_classes = []
# with torch.no_grad():
#     for x, y in test_loader:
#         y_pred_classes.extend(torch.argmax(model(x), dim=1).tolist())

# 计算指标
f1 = f1_score(y_test, y_pred_classes, average='weighted')
cm = confusion_matrix(y_test, y_pred_classes)
kappa = cohen_kappa_score(y_test, y_pred_classes)

print(f"Weighted F1-Score: {f1:.4f}")
print(f"Cohen's Kappa: {kappa:.4f}")
print("Confusion Matrix:\n", cm)

内容的提问来源于stack exchange,提问作者Alex Fines

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 18:05:56