PyTorch中Dropout无法降低损失但Keras中正常的问题排查
问题
在TensorFlow/Keras与PyTorch框架下,基于Keras的IMDB数据集,对有无Dropout的简单MLP模型损失情况做对比测试。结果显示Keras中带Dropout的模型表现正常,但PyTorch中带Dropout的模型未达到预期的损失下降效果,与Keras表现不一致。相关实现代码及结果如下:
Keras实现代码
# Keras - IMDB Dataset model = Sequential() model.add(Dense(16, activation = "relu", input_shape= (10000,))) model.add(Dropout(0.5)) # comment out this line for no dropout model model.add(Dense(16, activation = "relu")) model.add(Dropout(0.5)) # comment out this line for no dropout model model.add(Dense(1, activation = "sigmoid")) model.compile( optimizer = "rmsprop", loss = "binary_crossentropy", metrics = ["accuracy"] ) history = model.fit( X_train, y_train, epochs = 20, batch_size = 512, validation_data = (X_val, y_val) )
Keras测试结果:左图为无Dropout模型,右图为带Dropout模型
PyTorch实现代码
# Pytorch - same IMDB dataset from keras class MLP(nn.Module): def __init__(self, in_dims, l1, l2, out_dims): super(MLP, self).__init__() self.fc1 = nn.Linear(in_dims, l1) self.fc2 = nn.Linear(l1, l2) self.fc3 = nn.Linear(l2, out_dims) self.dropout = nn.Dropout(p=0.5) def forward(self, X): out = F.relu(self.fc1(X)) out = self.dropout(out) # comment out this line for no dropout model out = F.relu(self.fc2(out)) out = self.dropout(out) # comment out this line for no dropout model out = F.sigmoid(self.fc3(out)) return out model = MLP(10000, 16, 16, 1) optimizer = optim.RMSprop(model.parameters(), lr = 0.001) criterion = nn.BCELoss() min_val_loss = np.inf losses = [] val_losses = [] accuracy = [] val_accuracy = [] for e in range(0,20): running_loss = 0 for i,(X_train, y_train) in enumerate(train_loader): yhat = model.forward(X_train) loss = criterion(yhat.flatten(), y_train) running_loss += loss.item() optimizer.zero_grad() loss.backward() optimizer.step() losses.append(running_loss / (i+1)) #note its i+1 since i starts from 0 model.eval() with torch.no_grad(): running_val_loss = 0 for i,(X_val, y_val) in enumerate(val_loader): yhat_val = model.forward(X_val) val_loss = criterion(yhat_val.flatten(), y_val) running_val_loss += val_loss.item() val_losses.append(running_val_loss / (i + 1)) if val_loss < min_val_loss: best_params = model.state_dict() min_val_loss = val_loss print(f"epochs : {e}, train_loss : {loss}, val_loss : {val_loss}")
PyTorch测试结果:左图为无Dropout模型(与Keras结果相近),但带Dropout的模型表现不符合预期
问题排查与解决
以下是PyTorch实现中可能存在的关键问题及修复方案:
1. 训练模式未重置
PyTorch中调用model.eval()会将Dropout切换到评估模式(关闭随机失活),但你在每个epoch的验证环节结束后,没有将模型切回训练模式model.train()。这会导致后续训练阶段Dropout仍处于关闭状态,相当于全程没启用Dropout,自然无法达到预期效果。
修复代码:在验证环节结束后添加:
model.train()
2. RMSprop优化器参数不匹配
Keras与PyTorch的RMSprop默认参数存在差异:
- Keras默认
rho=0.9、epsilon=1e-7; - PyTorch默认
rho=0.99、epsilon=1e-8。
这些差异会直接影响优化器的更新节奏,导致模型收敛效果不一致。
修复代码:对齐Keras的默认参数:
optimizer = optim.RMSprop(model.parameters(), lr=0.001, rho=0.9, eps=1e-7)
3. 损失日志显示逻辑错误
你当前打印的train_loss和val_loss是每个epoch最后一个batch的损失值,而非整个epoch的平均损失,这会干扰对模型收敛情况的判断。
修复代码:修改打印语句使用平均损失:
print(f"epochs : {e}, train_loss : {losses[-1]}, val_loss : {val_losses[-1]}")
4. 数据预处理一致性问题
需确保PyTorch使用的IMDB数据集与Keras的预处理逻辑完全一致:
- 确认词汇表大小限制为10000(与Keras输入维度匹配);
- 确认输入向量化方式相同(如是否为one-hot编码);
- 确认标签 dtype 与模型输出匹配(BCELoss要求输入和标签均为float类型,若标签是整数需转换:
y_train = y_train.float())。
内容的提问来源于stack exchange,提问作者imantha
相关产品推荐
相关产品推荐

