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

在PyTorch实现的ResNet模型中如何放置Dropout层?

在3D ResNet中添加Dropout正则化的合理位置

针对你提供的3D ResNet PyTorch实现,Dropout的放置需要兼顾正则化效果和残差结构的特性,以下是几个经过验证的合理位置,附代码修改示例:


1. 全局平均池化后、全连接层前(最安全的入门方案)

这个位置对模型结构改动最小,仅对最终的全局特征向量做正则化,不会干扰卷积层的特征提取逻辑,适合初步尝试缓解过拟合。

修改ResNet类:

在__init__中添加Dropout层:

def __init__(self, ...):
    # 原有代码保持不变
    self.avgpool = nn.AdaptiveAvgPool3d((1, 1, 1))
    self.dropout = nn.Dropout(p=0.5)  # 新增Dropout,概率可调整为0.2-0.5
    self.fc = nn.Linear(block_inplanes[3] * block.expansion, n_classes)
    # 初始化代码保持不变

在forward方法中插入Dropout:

def forward(self, x):
    # 原有卷积、池化、残差层代码保持不变
    x = self.avgpool(x)
    x = x.view(x.size(0), -1)
    x = self.dropout(x)  # 插入Dropout
    x = self.fc(x)
    return x

2. 残差块内部的激活函数后(更强的正则化)

如果模型过拟合严重,可以在每个残差块的主路径中,卷积+BN+ReLU之后插入Dropout,对中间特征做正则化。注意不要破坏残差连接的恒等映射逻辑,不要在残差相加后直接加Dropout。

修改BasicBlock类:

class BasicBlock(nn.Module):
    expansion = 1

    def __init__(self, in_planes, planes, stride=1, downsample=None, dropout_p=0.3):
        super().__init__()
        self.conv1 = conv3x3x3(in_planes, planes, stride)
        self.bn1 = nn.BatchNorm3d(planes)
        self.relu = nn.ReLU(inplace=True)
        self.dropout = nn.Dropout(p=dropout_p)  # 新增Dropout
        self.conv2 = conv3x3x3(planes, planes)
        self.bn2 = nn.BatchNorm3d(planes)
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        residual = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.dropout(out)  # 插入Dropout

        out = self.conv2(out)
        out = self.bn2(out)

        if self.downsample is not None:
            residual = self.downsample(x)

        out += residual
        out = self.relu(out)

        return out

修改Bottleneck类:

针对瓶颈结构,可以在每个卷积段后都加Dropout,增强正则化:

class Bottleneck(nn.Module):
    expansion = 4

    def __init__(self, in_planes, planes, stride=1, downsample=None, dropout_p=0.3):
        super().__init__()
        self.conv1 = conv1x1x1(in_planes, planes)
        self.bn1 = nn.BatchNorm3d(planes)
        self.conv2 = conv3x3x3(planes, planes, stride)
        self.bn2 = nn.BatchNorm3d(planes)
        self.conv3 = conv1x1x1(planes, planes * self.expansion)
        self.bn3 = nn.BatchNorm3d(planes * self.expansion)
        self.relu = nn.ReLU(inplace=True)
        self.dropout1 = nn.Dropout(p=dropout_p)  # 第一个Dropout
        self.dropout2 = nn.Dropout(p=dropout_p)  # 第二个Dropout
        self.downsample = downsample
        self.stride = stride

    def forward(self, x):
        residual = x

        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.dropout1(out)  # 插入第一个Dropout

        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
        out = self.dropout2(out)  # 插入第二个Dropout

        out = self.conv3(out)
        out = self.bn3(out)

        if self.downsample is not None:
            residual = self.downsample(x)

        out += residual
        out = self.relu(out)

        return out

同时需要修改_make_layer方法,传递dropout参数:

def _make_layer(self, block, planes, blocks, shortcut_type, stride=1):
    downsample = None
    if stride != 1 or self.in_planes != planes * block.expansion:
        if shortcut_type == 'A':
            downsample = partial(self._downsample_basic_block,
                                 planes=planes * block.expansion,
                                 stride=stride)
        else:
            downsample = nn.Sequential(
                conv1x1x1(self.in_planes, planes * block.expansion, stride),
                nn.BatchNorm3d(planes * block.expansion))

    layers = []
    # 传递dropout_p参数
    layers.append(
        block(in_planes=self.in_planes,
              planes=planes,
              stride=stride,
              downsample=downsample,
              dropout_p=0.3))
    self.in_planes = planes * block.expansion
    for i in range(1, blocks):
        layers.append(block(self.in_planes, planes, dropout_p=0.3))

    return nn.Sequential(*layers)

注意事项

  • Dropout概率建议设置在0.2-0.5之间,过高可能导致模型欠拟合。
  • 由于ResNet本身使用了Batch Normalization,Dropout和BN结合时可能会有轻微的训练波动,可适当降低学习率或增加训练轮数。
  • 不要在残差相加与最终ReLU之间插入Dropout,这会破坏残差学习的核心逻辑,导致模型性能下降。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 13:10:58