在改一份代码,网络结构是一个 bert ,一个 dropout 层和最后一个 linear 层
我在把多分类改成多标签分类
就改改数据的输入输出格式,加个 sigmoid 激活函数
但是结果出现了问题,发现 loss 一直在降,但是 acc 缺掉到 0 ,一看才发现,练着练着,最后 linear 层输出是一个特别小的负数,而且越来越小,然后经过 sigmoid 后全部预测为 0 ,所以 loss 算起来还是很低
这种情况可能是出现什么问题呢
1
zhucegeqiu 2021-12-30 09:56:39 +08:00
预测全为 0 为啥 loss 就低,样本不平衡?
|
2
zxCoder OP @zhucegeqiu 比如一共有 1000 个 label ,但是一个样本可能只有一两个 label 是 1 ,其他都是 0 ,直接预测全 0 ,用 BCE 计算 loss 好像就不高
|
3
sss3barry 2021-12-30 10:27:15 +08:00
样本也太不平衡了吧,感觉换 loss 也不一定有用,下采样负例稍微平衡一下?
|
4
ipwx 2021-12-30 10:30:33 +08:00
@zxCoder 你已经说出了原因了。神经网络做的是
1. 最大化 l(x,y) 在训练样本 p(x,y) = p(x)p(y|x) 上的期望。 2. 几乎不可能找到全局最优解,只能找到局部最优解。 在你的例子中,998/1000 以上的训练样本都是 0 。也就是说 p(y=0|x) = 0.998 。如果你是神经网络要学习 y=f(x),那么是不是很容易找到 y=f(x) 恒等于 0 这个局部最优解? |
5
ipwx 2021-12-30 10:31:17 +08:00
p(y=0|x) = 0.998 ,约等于 p(y=0|x) = 1 。如果是后者,显然全局最优解就是 y=f(x) 恒等于 0 。
|
6
jdhao 2021-12-30 10:36:58 +08:00 via Android
使用 weighted cross entropy ,增大类别少的样本权重,或者想办法把各类数据均衡
|
7
ipwx 2021-12-30 10:39:37 +08:00
@jdhao 这个例子里面,imbalance 太严重了。说句难听的,只有 2 个正例,分分钟过拟合。
这种问题建议先 unsupervised training ,用得到的 hidden representation 做更稳的分类器。 |
8
zxCoder OP @ipwx 检查了一下,一共 120 个标签,5 万多个训练样本
标签分布大概是 [656, 122, 380, 217, 2276, 794, 149, 458, 248, 626, 102, 135, 396, 127, 141, 3431, 161, 687, 352, 157, 1322, 1887, 423, 313, 994, 880, 125, 138, 295, 473, 263, 106, 1153, 221, 297, 1643, 150, 3083, 218, 403, 277, 258, 524, 5553, 246, 128, 205, 735, 115, 1089, 159, 201, 438, 1984, 536, 148, 666, 251, 103, 499, 263, 124, 217, 823, 136, 112, 157, 128, 747, 202, 189, 147, 115, 224, 122, 920, 2176, 235, 247, 1861, 110, 124, 1178, 199, 166, 106, 457, 3718, 154, 12597, 641, 182, 354, 164, 277, 230, 232, 106, 3445, 979, 1589, 132, 105, 150, 219, 188, 168, 535, 284, 2137, 1351, 101, 542, 115, 804, 114, 384, 125, 102, 1334] 感觉也还行吧,这算不均衡吗 |
9
zxCoder OP 而且同样的数据,之前在其他基于 bert 的模型上跑也没出现这问题啊
|
10
c0xt30a 2021-12-31 03:39:28 +08:00
这个问题的根源在于, 激活函数是 softmax 的时候,最后一层的输出强制非负并且和为 1;
更换到 sigmoid 之后,输出之和为 1 的限制被解去了。 当有 1000+ 个 label ,而一个样本最多有两个 label 是 1 的时候,网络输出全为 0 明显是一个局部最小,而且基本上不能跳出来的那种。 |
11
c0xt30a 2021-12-31 03:47:48 +08:00
我出个主意:
鉴于最多有两个标签是 1 ,那么可以依旧用 softmax 做激活,用 soft label 处理下数据。 譬如,当某个样本只有 1 个标签的时候,把这个标签设置为 0.5 ,其他的 999 个平分剩下的 0.5 ;当某个样本有两个标签的时候,把这两个标签都设置为 0.5 ,其余的标签设置为 0 。 刚拍脑袋想出来的,不保证靠谱。 |
14
ipwx 2021-12-31 10:39:31 +08:00
哦哦哦 等等,是多标签分类。
那你说不定可以试试在输出层的 loss 上,各维独立添加惩罚系数,就正比于根据你上面那个类别数量的倒数。 不过我觉得你说不定前面的网络哪里有问题。。。 |
15
ipwx 2021-12-31 10:53:14 +08:00
哦又重新看了看你的问题描述。
我懂了,你的问题果然还是各维独立做多标签这里出了问题。 记 C = sum(你上面那个频数列表) np.percentile(C / C.sum(), [1,10,20,50,80,90,99]) => array([0.00119775, 0.0013504 , 0.00157821, 0.00292978, 0.00979803, 0.01954908, 0.06111261]) 这个 imbalance 太严重了。各个维度都输出 0 就是一个非常巨大的局部最小值点。 解决方法 1:在每一维输出的时候,如果是 1 就 loss 添加惩罚系数 C / 类别频率,0 就添加 C / (1 - 类别频率)。这样能把各维二分类各自的 imbalance 问题降下来。 解决方法 2:还是 softmax 做 top-k 分类推荐。额外添加一个分类器预测到底输入有多少个输出类。 |
16
ipwx 2021-12-31 10:55:57 +08:00
@zxCoder 从逻辑回归角度看 0-1 分类会有这样的结论:
对于一个二分类器而言,如果你的类别 A 出现概率是 p ,类别 B 出现概率是 1-p ,并且两类在 loss 上的贡献是等权的,那么最终你的分类器的决策边界大概在 p 附近。 你的所有类别都严重 imbalance ,p 的 99% 分位数都只有 0.06 ,那么你每一类的分类边界,小的大概在 0.001 ,大的也只有 0.06 。但是你在做预测的时候决策边界是 0.5 ,那么当然全部认为是 0 。 我说的那个惩罚系数就是强行把这个决策边界拉回 0.5 附近。 |
17
ipwx 2021-12-31 10:56:32 +08:00
想了想惩罚系数也可以这样
1 => (1 - 类别频率),0 => 类别频率 |
18
zxCoder OP @ipwx 没辙了。。。加了 weight 也不行,把多标签分类改成多分类也不行,总是预测到同一个类别。。。这破论文怎么就还能发呢。。。
|
19
zxCoder OP @ipwx
”1 => (1 - 类别频率),0 => 类别频率“ 老哥能不能说下代码怎么实现这个啊。这个是要自己循环判断每个 label 的预测结果再计算 loss 吗?直接用 weight 好像只能是给每个 label 分配不同的权重 |
20
ipwx 2021-12-31 13:14:52 +08:00 1
@zxCoder 你们用 pytorch 的都没有自己写 train loop 的经历了么啊,只能 model.fit ??
class_prob = C / C.sum() 自己组 loss 不就随便搞了。伪代码: binary_cross_entropy(logits, label) * torch.where(label == 1, 1-C[label], C[label]) 肯定有辙啊 |
21
zxCoder OP @ipwx 还是没啥效果,真是奇怪,同样的数据,在别的模型上就挺正常的,在这个模型上就不行,网络结构都是一个 bert ,一个 dropout 层和最后一个 linear 层
|
22
ipwx 2022-01-01 18:12:24 +08:00
摸不到你的数据所以没法远程给建议了(趴
|