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

为什么我实现的Transformer在序列标注任务上效果不如BiLSTM?

问题背景

我目前在处理序列标注任务,采用单个Transformer Encoder来获取序列每个元素的logits。在对Transformer和BiLSTM进行实验后,发现在我的场景下BiLSTM表现更优,因此想确认是否是我的Transformer实现存在问题,以下是相关实现代码:

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

def create_mask(src, lengths):
    """Create a mask hiding future tokens
    Parameters:
        src (tensor): the source tensor having shape [batch_size, number_of_steps, features_dimensions]
        length (list): a list of integers representing the length (i.e. number_of_steps) of each sample in the batch."""
    mask = []
    max_len = src.shape[1]
    for index, i in enumerate(src):
        # The mask consists in tensors having false at the step number that doesn't need to be hidden and true otherwise
        mask.append([False if (i+1)>lengths[index] else True for i in range(max_len)])
    return torch.tensor(mask)

class PositionalEncoding(nn.Module):

    def __init__(self, d_model, dropout=0.1, max_len=5000, device = 'cpu'):
        super().__init__()
        self.dropout = nn.Dropout(p=dropout)
        self.device = device
        position = torch.arange(max_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2) * (-math.log(10000.0) / d_model)
        pe = torch.zeros(1, max_len, d_model)
        pe[0, :, 0::2] = torch.sin(position * div_term)
        pe[0, :, 1::2] = torch.cos(position * div_term)
        self.register_buffer('pe', pe)
    
    def forward(self, x):
        x = x + self.pe[:, :x.size(1), :].to(self.device)
        return self.dropout(x)

class Transformer(nn.Module):
    """Class implementing transformer ecnoder, partially based on
    pytorch official transformer tutorial"""
    def __init__(self, in_dim, h_dim, n_heads, n_layers, dropout=0.2, drop_out = 0.0, batch_first = True, device = 'cpu', positional_encoding = True):
        super(Transformer, self).__init__()
        self.model_type = 'Transformer'
        self.pos_encoder = PositionalEncoding(in_dim, dropout, device = device)
        encoder_layers = nn.TransformerEncoderLayer(in_dim, n_heads, h_dim, dropout)
        self.transformer_encoder = nn.TransformerEncoder(encoder_layers, n_layers, norm=nn.LayerNorm(in_dim))
        self.in_dim = in_dim
        self.drop_out = drop_out
        self.positional_encoding = positional_encoding
    
        
    def forward(self, src, mask = None, line_len=None):
        src = src * math.sqrt(self.in_dim)
        if self.positional_encoding:
            src = self.pos_encoder(src)
        if line_len is not None and mask is None:
            mask = create_mask(src, line_len)
        else:
            mask = None
        output = self.transformer_encoder(src, src_key_padding_mask = mask)
        if self.drop_out:
            output = F.dropout(output, p = self.drop_out)
        return src, output

上述代码运行后,输出隐层状态会传入额外的线性层,采用二分类CrossEntropy损失和Adam优化器进行训练。已经尝试了多组超参数组合,但BiLSTM表现仍然更优。

实现问题排查

你的Transformer实现存在多个明显错误,是导致效果不如BiLSTM的核心原因:

  • Padding mask逻辑完全写反:PyTorch的src_key_padding_mask要求被mask的padding位置为True,有效位置为False。你现有create_mask的逻辑是将有效位置设为True、padding位置设为False,等于直接把所有有效输入都屏蔽了,注意力计算完全失效。同时函数注释写的是“隐藏未来token”,这是Decoder端用的序列掩码,Encoder端的padding mask不需要隐藏未来token,注释也存在误导。
  • 未传入batch_first参数:你自定义的Transformer类设了batch_first=True,但初始化nn.TransformerEncoderLayer时没有传入batch_first=True,该层默认输入形状是[序列长度, 批次大小, 特征维度],和你传入的[批次大小, 序列长度, 特征维度]不匹配,注意力计算逻辑完全错误。
  • mask赋值逻辑错误:forward方法中的逻辑是只要外部传入了mask,或者line_len为空,就会直接把mask设为None,等于你手动传入的mask永远不会生效,padding位置没有被正确屏蔽。
  • 位置编码设备处理冗余:你已经用register_buffer注册了位置编码pe,它会自动跟随模型移动到对应设备,不需要手动调用to(self.device),如果模型移到GPU但初始化时device参数还是默认的cpu,反而会出现设备不匹配的报错。
修复实现后效果仍不如BiLSTM的可能原因

如果修复上述错误后效果还是没有超过BiLSTM,属于正常情况,和任务、数据特性相关:

  • 数据集规模较小:Transformer的拟合能力强但需要更多数据支撑,小数据集下BiLSTM自带的序列局部依赖归纳偏置更有优势,更容易收敛到更好的效果。
  • 序列长度偏短:短序列场景下Transformer的全局注意力优势无法体现,BiLSTM对局部相邻特征的建模效率更高,同等参数量下效果更好。
  • 超参数适配不足:Transformer对学习率更敏感,通常需要比LSTM更小的学习率,搭配学习率warmup策略才能稳定收敛,直接使用Adam默认学习率很容易出现训崩的情况。
  • 任务特性更适配BiLSTM:如果你的序列标注任务强依赖相邻token的局部特征,比如分词、简单实体识别等,BiLSTM的序列建模特性本身就比Transformer更贴合这类任务的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 12:18:01