流程
分阶段指定β值
# 根据当前epoch计算使用的beta值
idx = epoch // 160 # 每160轮epoch切换一次加权系数
betas = [0, 0.9999] # 两个beta值
beta = betas[idx] # 根据idx选择beta值
计算有效样本的权重
对权重进行归一化
(每类权重值 / 权重总和)* 样本数量
# 将权重进行归一化
per_cls_weights = per_cls_weights / np.sum(per_cls_weights) * len(cls_num_list)
print(f"Class weights after normalization: {per_cls_weights}")
代码
import numpy as np
import torch
def calculate_per_cls_weights(cls_num_list, epoch, device):
# 训练采样器设为空
train_sampler = None
print(f"Train sampler: {train_sampler}")
# 根据当前epoch计算使用的beta值
idx = epoch // 160 # 每160轮epoch切换一次加权系数
print(f"Epoch: {epoch}, Beta index (idx): {idx}")
betas = [0, 0.9999] # 两个beta值
beta = betas[idx] # 根据idx选择beta值
print(f"Selected beta value: {beta}")
# 计算每个类别的有效样本数 effective_num
effective_num = 1.0 - np.power(beta, cls_num_list)
print(f"Effective number (for each class): {effective_num}")
# 计算每个类别的权重 per_cls_weights
per_cls_weights = (1.0 - beta) / effective_num
print(f"Class weights before normalization: {per_cls_weights}")
# 将权重进行归一化
per_cls_weights = per_cls_weights / np.sum(per_cls_weights) * len(cls_num_list)
print(f"Class weights after normalization: {per_cls_weights}")
# 将权重转为张量并移动到指定设备上
per_cls_weights = torch.FloatTensor(per_cls_weights).to(device)
print(f"Final weights as a tensor on device ({device}): {per_cls_weights}")
return per_cls_weights
# 示例
cls_num_list = [100, 50, 10, 5] # 假设数据集中有4个类别,样本数分别为100、50、10、5
epoch = 200 # 当前训练轮次
device = 'cuda' if torch.cuda.is_available() else 'cpu' # 选择设备
# 计算类别权重
per_cls_weights = calculate_per_cls_weights(cls_num_list, epoch, device)
print("Per class weights:", per_cls_weights)
解析
前面部分所有类别权重相等。
在你的 Acne04 数据集上,BKD 在第 77 个 epoch 时测试集准确率达到最大值,并且此时并没有使用有效样本的计算,而是直接按照类平衡去计算就取得了最大的效果。出现这种现象的原因可能包括以下几点:
-
类平衡策略的优势:BKD 的类平衡蒸馏策略通过对尾部类别施加更高的权重来使得模型在尾部类别上获得更好的表现。即使没有用到有效样本的计算,类平衡蒸馏本身已经纠正了模型对频繁类别的偏向,从而大幅提升了尾部类别的表现。这种简单的类平衡策略可能已经足够有效,以至于能够在较早的 epoch 中达到最佳的分类效果。
-
数据集规模和分布的影响:Acne04 数据集的规模较小,类别不平衡的情况可能并没有特别严重,因此即使没有采用更复杂的有效样本计算,类平衡蒸馏就能够取得显著的性能提升。对于这种中等规模或类别分布不那么极端的数据集,较为简单的类平衡方法往往足够有效。
-
训练的早期收敛:在第 77 个 epoch 时,模型可能已经充分学习到了数据中的特征,尤其是在使用 BKD 的情况下,模型不仅能够学到头部类别的泛化特征,还能够有效提升尾部类别的表现。这表明 BKD 提供的类平衡机制已经足以解决该数据集上的类不平衡问题,而不需要依赖更复杂的有效样本策略。
-
蒸馏温度和超参数的影响:BKD 蒸馏过程中使用的温度参数 TTT 可能在此时已经使得教师模型的软标签足够平滑,进一步帮助学生模型更好地学习尾部类别的特征,而无需通过有效样本策略来调整每类的权重分布。
因此,在 Acne04 数据集上,BKD 的类平衡机制已经足够有效,使得模型在第 77 个 epoch 时就达到了测试集准确率的最大值,即使没有使用更加复杂的有效样本策略(Balanced Knowledge Dist…)
程度没有那么严重的不平衡数据集,是不是就用类平衡策略就可以了,比其他的平衡策略更好使一点?
是的,对于不平衡程度没有那么严重的数据集,使用类平衡策略(如 BKD 中的类平衡蒸馏)通常已经足够有效,且可能比其他复杂的平衡策略表现得更好。原因如下:
-
简单有效:类平衡策略通过调整不同类别的权重,让模型在学习时关注那些少数类。这种方法的简单性意味着它能够快速适应不太严重的类不平衡数据集,而不需要像更复杂的重采样或有效样本计算那样复杂的机制。
-
避免过度调整:在不太严重的不平衡数据集中,过度使用复杂的平衡策略(如重采样或有效样本计算)可能会导致对尾部类别的过度关注,反而损害头部类别的表现。类平衡策略通过温和的权重调整,更好地维持了头部和尾部类别之间的平衡,不会过度影响整体模型的泛化能力。
-
计算效率:类平衡策略相对简单,计算开销较低,不需要频繁调整采样或计算每个类别的有效样本数,因此训练过程更加高效。对于不太严重的类不平衡问题,这种高效的解决方案通常已经足够有效。
-
蒸馏的优势:BKD 的类平衡蒸馏策略在学习时不仅关注少数类,还能通过蒸馏从教师模型中学习整体数据的分布。因此,它能够在提升尾部类别性能的同时保持对头部类别的良好表现,这对于不太严重的不平衡问题尤为重要。
因此,对于不平衡程度较低的数据集,类平衡策略通常能提供足够的性能提升,同时避免了更复杂策略可能带来的负面影响,如过度拟合少数类或损害模型的整体性能(Balanced Knowledge Dist…)。