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

在PyTorch中实现Word Dropout:为UNK Token嵌入训练扩充样本

没问题,我来帮你把Word Dropout整合到你的CNN分类器里——这确实是训练UNK token嵌入的标准操作,能让模型更好地处理未见过的词汇。下面是完整的实现,默认UNK索引为0、Padding索引为1,如果你需要互换两者,只需要调整参数即可。

带Word Dropout的CNN分类器实现

我会基于你给出的Classifier类框架,补充完整的Word Dropout逻辑和CNN核心代码:

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

class Classifier(nn.Module):
    def __init__(self, params):
        super(Classifier, self).__init__()
        # 从参数字典中提取必要配置
        self.vocab_size = params['vocab_size']
        self.embedding_dim = params['embedding_dim']
        self.num_filters = params['num_filters']
        self.filter_sizes = params['filter_sizes']
        self.num_classes = params['num_classes']
        
        # Word Dropout相关配置(可通过params灵活调整)
        self.word_dropout_prob = params.get('word_dropout_prob', 0.1)  # 默认dropout概率设为0.1
        self.unk_idx = params.get('unk_idx', 0)
        self.pad_idx = params.get('pad_idx', 1)
        
        # 嵌入层:指定padding_idx,让padding的嵌入固定为0(默认行为)
        self.embedding = nn.Embedding(self.vocab_size, self.embedding_dim, padding_idx=self.pad_idx)
        
        # 多尺寸卷积核的CNN层
        self.convs = nn.ModuleList([
            nn.Conv2d(1, self.num_filters, (fs, self.embedding_dim)) 
            for fs in self.filter_sizes
        ])
        
        # 最终分类全连接层
        self.fc = nn.Linear(len(self.filter_sizes)*self.num_filters, self.num_classes)
        
    def word_dropout(self, input_ids):
        """
        核心Word Dropout逻辑:仅在训练模式下,随机将非Padding的token替换为UNK
        input_ids: 输入序列张量,形状为 [batch_size, seq_len]
        """
        # 非训练模式或dropout概率为0时,直接返回原输入
        if not self.training or self.word_dropout_prob == 0.0:
            return input_ids
        
        # 生成掩码:标记出非Padding的位置(这些位置才可能被替换)
        non_pad_mask = (input_ids != self.pad_idx)
        # 生成随机dropout掩码:按指定概率选中要替换的位置
        dropout_mask = torch.rand(input_ids.shape, device=input_ids.device) < self.word_dropout_prob
        # 合并掩码:只有非Padding且被选中的位置才会被替换为UNK
        replace_mask = non_pad_mask & dropout_mask
        
        # 复制原输入并替换目标位置
        output_ids = input_ids.clone()
        output_ids[replace_mask] = self.unk_idx
        
        return output_ids
    
    def forward(self, input_ids):
        # 第一步:应用Word Dropout(仅训练时生效)
        input_ids = self.word_dropout(input_ids)
        
        # 嵌入层转换:[batch_size, seq_len] -> [batch_size, seq_len, embedding_dim]
        embeds = self.embedding(input_ids)
        # 调整维度适配CNN输入:增加通道维度(CNN要求输入为[batch, channels, height, width])
        embeds = embeds.unsqueeze(1)
        
        # 卷积+全局最大池化
        conv_results = []
        for conv in self.convs:
            # 卷积操作:输出形状为 [batch_size, num_filters, seq_len - filter_size + 1, 1]
            conv_out = F.relu(conv(embeds))
            # 最大池化:对序列维度做池化,得到每个滤波器的全局最大值
            pooled_out = F.max_pool2d(conv_out, (conv_out.shape[2], 1)).squeeze()
            conv_results.append(pooled_out)
        
        # 拼接所有尺寸滤波器的输出
        concat_features = torch.cat(conv_results, dim=1)
        # 分类预测
        logits = self.fc(concat_features)
        
        return logits

关键细节说明

  • Word Dropout的边界控制:特意通过non_pad_mask确保不会替换Padding token,因为Padding本身是填充的无意义符号,替换它对训练UNK嵌入没有帮助,还会干扰序列长度的一致性。
  • 训练/推理模式适配:只有在model.train()模式下才会启用Word Dropout,调用model.eval()时会自动跳过,保证推理时输入的稳定性。
  • 参数灵活性:如果你需要互换UNK和Padding的索引,只需要在传入params时修改unk_idx和pad_idx的值即可,比如params={'unk_idx':1, 'pad_idx':0, ...}。

实用建议

  • 推荐把word_dropout_prob设置在0.1~0.2之间,这个范围既能提供足够的UNK训练样本,又不会过度破坏输入的语义信息。
  • 预处理数据集时,记得把低频词汇提前替换为UNK,结合Word Dropout能让模型对未见过的词汇具备更好的泛化能力。
  • 训练时务必记得调用model.train(),验证/测试时调用model.eval(),否则Word Dropout会在推理阶段错误生效。

内容的提问来源于stack exchange,提问作者Chum-Chum Scarecrows

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:07:10