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

PyTorch训练RNN实现域名二分类时Loss不随Epoch更新问题咨询

DGA域名二分类RNN模型训练Loss停滞问题排查

问题背景

使用PyTorch训练RNN模型对DGA域名进行二分类,数据集样例如下:

m644136d0.tmodns.ne | 0
dfg.ca.gov | 0
c4w6wpg81xsbopy8a67.ddns.net | 1

其中标签1代表DGA生成域名,采用独热编码做嵌入,但训练50轮后Loss始终维持0.6931(约等于ln2,对应模型随机预测),无任何下降。

问题排查与修复方案

1. 损失函数与输出层的冲突

  • 问题本质:CrossEntropyLoss内部已经整合了LogSoftmax和NLLLoss的计算逻辑,而模型中额外添加了Softmax层,导致输出被两次归一化,最终模型输出趋近于均匀分布(两类概率各0.5),对应Loss固定为ln2≈0.6931。
  • 修复:移除模型中的Softmax层:
    class rnnModel(nn.Module):
        def __init__(self, vocab_size, embedding_dim, num_hid_neurons, num_out, nun_hid_layers=1):
            super(rnnModel, self).__init__()
            
            self.nn = nn.RNN(embedding_dim, num_hid_neurons, nun_hid_layers, batch_first=True)
            self.fc = nn.Linear(num_hid_neurons, 2)
            # 移除self.softmax = nn.Softmax(dim=1)
            self.num_out = num_out
            self.nun_hid_layers = nun_hid_layers
            self.num_hid_neurons = num_hid_neurons
    
        def forward(self, input, hidden):
            if hidden is None :
                batch_size = input.size(0)
                hidden = self.init_hidden(batch_size)
    
            output, hidden = self.nn(input, hidden)
            output = self.fc(output)
            # 移除output = self.softmax(output)
            return output, hidden
    

2. 梯度清零时机错误

  • 问题本质:当前代码将optimizer.zero_grad()放在epoch循环外部,导致每轮所有batch的梯度累加,梯度会出现爆炸或失效,模型无法有效更新参数。
  • 修复:将梯度清零操作移至每个batch循环内部:
    for epoch in range(1, n_epochs + 1):
        total_loss = 0.0
        for input, target in train_data_loader :
            optimizer.zero_grad()  # 每个batch前清零梯度
            batch_size = input.size(0)
            hidden = model.init_hidden(batch_size)
            output, hidden = model(input, hidden)
            output = output[:, -1, :]
            loss = criterion(output, target)
            loss.backward()
            optimizer.step()
            total_loss += loss.item()
        losses.append(total_loss / len(train_data_loader))
        print('Epoch: {}/{}.............'.format(epoch, n_epochs), end=' ')
        print("Loss: {:.4f}".format(total_loss / len(train_data_loader)))
    

3. RNN输入处理与前向传播逻辑错误

  • 问题本质:手动循环输入的每个时间步喂给RNN不仅低效,还导致输入维度冗余(多了一个无用的维度),且没有正确利用整个序列的信息做分类。
  • 修复:
    • 调整domain2tensor,移除冗余维度:
      def domain2tensor(domain):
          tensor = torch.zeros(len(domain), vocab_size)  # 改为(序列长度, 词汇表大小)
          for i, c in enumerate(domain):
              tensor[i, char2token[c]] = 1
          return tensor
      
    • 调整Dataset的pad逻辑:
      def __getitem__(self, index) :
          temp_text = self.Xtr.iloc[index]
          not_padded = domain2tensor(temp_text)
          # 调整pad维度:(seq_len, vocab_size) -> (padded_size, vocab_size)
          padded = F.pad(not_padded, pad=(0,0, self.padded_size - len(not_padded), 0))
          x = self.ytr.iloc[index]
          return padded, torch.tensor(x, dtype=torch.long)  # 标签改为类索引(long类型)
      
    • 训练循环中直接喂入整个序列,并取最后一个时间步的输出做分类:
      for input, target in train_data_loader :
          optimizer.zero_grad()
          batch_size = input.size(0)
          hidden = model.init_hidden(batch_size)
          output, hidden = model(input, hidden)
          # 取RNN最后一个时间步的输出用于分类
          output = output[:, -1, :]
          loss = criterion(output, target)
          loss.backward()
          optimizer.step()
      

4. 标签格式不符合损失函数要求

  • 问题本质:CrossEntropyLoss要求目标是类别的索引值(0或1),但当前代码返回的是one-hot格式的向量,导致损失计算逻辑错误,模型无法学习。
  • 修复:如上述Dataset修改所示,直接返回原始标签的long类型张量即可。

5. 学习率设置过低

  • 问题本质:当前学习率lr=1e-5对于Adam优化器来说过小,参数更新幅度微乎其微,模型无法有效收敛。
  • 修复:将学习率调整至1e-4或1e-3,后续可根据训练曲线再微调:
    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
    

6. 隐藏层初始化的设备不匹配问题

  • 问题本质:如果使用GPU训练,init_hidden生成的隐藏状态张量默认在CPU上,而模型参数在GPU上,会导致设备不匹配报错,或训练无效。
  • 修复:让隐藏状态使用模型所在的设备:
    def init_hidden(self, batch_size):
        hidden = torch.zeros(self.nun_hid_layers, batch_size, self.num_hid_neurons, device=self.nn.weight.device)
        return hidden
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 18:55:02