PyTorch实现论文「并发」Softmax函数遇输出恒值异常问题
并发Softmax实现异常的原因与修正方案
异常根因
你的代码逻辑和对函数的理解存在两处偏差,共同导致了第一个输出恒为0.5的结果:
- 计算循环错误纳入了无需计算的负样本类
- 求和项重复计入了当前类的自身指数值
详细问题拆解
- 固定0.5输出的形成逻辑
以你给出的样例y=[0,1,1]为例,数组中仅类0为负样本,其余两类为正样本。你写的sum_over_j的计算规则是累加所有满足1-y[j]=1的指数化logit值,因此无论i循环到哪个类,sum_over_j的计算结果始终等于exp(vec[0])。
当循环到i=0时,当前类的zi=exp(vec[0]),代入计算公式得到out = exp(vec[0])/(exp(vec[0]) + exp(vec[0])) = 0.5。这就是无论修改vec的第一个元素为任何值,输出都固定为0.5的直接原因。 - 函数设计的认知偏差
你简化后的并发Softmax,核心作用是为每个正样本标签计算独立的归一化得分,不需要对负样本类计算输出。按照你省略rij项后的简化定义,每个正样本类i的输出计算规则为:当前类的指数化logit,除以「当前类的指数化logit + 所有负样本类的指数化logit之和」。负样本类本身不属于需要输出得分的对象,纳入循环计算本身就不符合函数的设计逻辑。
修正后的循环实现
import torch y = [0, 1, 1] vec = torch.tensor([0.2, 0.9, 0.7]) def concurrent_softmax(vec, y): # 提前累加所有负样本类的指数化logit,避免循环内重复计算 neg_logit_sum = sum(torch.exp(vec[j]) for j in range(len(y)) if y[j] == 0) # 仅遍历正样本类计算输出 for i in range(len(vec)): if y[i] == 0: continue current_exp = torch.exp(vec[i]) yield current_exp / (neg_logit_sum + current_exp) for result in concurrent_softmax(vec, y): print(result)
修正后的代码输出会随vec的取值动态变化,不再出现固定值异常,符合函数的预期效果。
内容的提问来源于stack exchange,提问作者Steve Ahlswede
相关产品推荐
相关产品推荐

