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

Transformer多标签分类模型验证测试集输出值异常问题排查

问题:Transformer模型验证/测试集上多次调用同一解码器输出完全一致

我有一个需要输出三个不同标签的Transformer模型,其forward函数代码如下:

def forward(self, src, target):
    src_mask = self.make_src_mask(src)
    target_mask = self.make_target_mask(target)
    enc_src = self.encoder(src, src_mask)
    out_1 = self.decoder(target, enc_src, src_mask, target_mask) # Plain
    out_2 = self.decoder(target, enc_src, src_mask, target_mask) # Mid
    out_3 = self.decoder(target, enc_src, src_mask, target_mask) # Dir
    out_4 = self.relu(out_3) # Dir
    flatten = torch.flatten(out_2, start_dim=1, end_dim=2)
    out_5 = self.fc_out_mid(flatten) # size [num_samples,num_frames]
    out_4 = self.fc_out_direction(out_4)
    out_4 = torch.nn.functional.log_softmax(out_4, dim=2)
    return out_1, out_5, out_4, out_2, out_3

损失函数分别计算out_1、out_5、out_4后合并。我期望out_1、out_2、out_3形状相同但数值不同,训练集上三者数值确实不同,符合预期,但在验证集和测试集上三者数值完全一致。请问这是如何发生的?我哪里操作有误?


核心原因

你三次调用的是同一个解码器实例:

  • 训练时模型处于train()模式,解码器内部的dropout、层归一化等带随机性的组件会生效,每次前向传播的计算会产生微小差异,导致out_1、out_2、out_3数值不同;
  • 验证/测试时模型切换到eval()模式,这些随机性组件被禁用(比如dropout停止随机失活,层归一化固定使用训练阶段统计的均值和方差),同一输入下多次调用解码器的输出自然完全一致。

更关键的是,你的代码逻辑本身存在设计错误:想得到三个针对不同任务的输出,却复用同一个解码器,训练时的差异只是随机性带来的“假差异”,并不是模型学习到了三个独立的任务分支,一旦关掉随机性,输出必然重合。

解决办法

要实现三个独立的任务分支,必须为每个分支创建独立的解码器实例,而非复用同一个:

1. 模型初始化阶段定义三个独立解码器

def __init__(self, decoder_config, ...):
    # 保留原有编码器等组件
    self.encoder = Encoder(...)
    
    # 为三个任务分别创建独立解码器
    self.decoder_plain = Decoder(**decoder_config)  # 对应out_1的解码器
    self.decoder_mid = Decoder(**decoder_config)    # 对应out_2的解码器
    self.decoder_dir = Decoder(**decoder_config)    # 对应out_3的解码器
    
    # 原有全连接层保持不变
    self.fc_out_mid = nn.Linear(...)
    self.fc_out_direction = nn.Linear(...)

2. Forward函数中调用对应解码器

def forward(self, src, target):
    src_mask = self.make_src_mask(src)
    target_mask = self.make_target_mask(target)
    enc_src = self.encoder(src, src_mask)
    
    # 调用不同的解码器得到任务特异性输出
    out_1 = self.decoder_plain(target, enc_src, src_mask, target_mask) # Plain
    out_2 = self.decoder_mid(target, enc_src, src_mask, target_mask) # Mid
    out_3 = self.decoder_dir(target, enc_src, src_mask, target_mask) # Dir
    
    # 后续处理逻辑不变
    out_4 = self.relu(out_3)
    flatten = torch.flatten(out_2, start_dim=1, end_dim=2)
    out_5 = self.fc_out_mid(flatten)
    out_4 = self.fc_out_direction(out_4)
    out_4 = torch.nn.functional.log_softmax(out_4, dim=2)
    
    return out_1, out_5, out_4, out_2, out_3

可选优化方案

如果三个任务存在关联性,不想完全独立训练三个完整解码器,可以考虑:

  • 共享解码器主体,独立任务头部:让三个分支共享解码器的前N层,只在最后几层或输出层使用独立的参数,既复用共享特征,又保留任务特异性;
  • 任务嵌入引导:在解码器输入中加入任务特定的嵌入向量,让同一解码器根据不同嵌入输出对应任务的结果,但这种方式需要修改解码器的前向逻辑,实现复杂度更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:05:34