马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、ResNet-50 是什么
ResNet-50 是基于残差网络(ResNet)架构的深度卷积神经网络,核心创新是引入残差块(Residual Block)与跳跃连接(Skip Connection)。它解决了深度网络中的梯度消失与退化问题,使网络可以堆叠到更深的层次而不出现过拟合或梯度问题。
二、结构组成
- 输入层:通常为 224×224 像素的 RGB 图像,3 个通道。
- 初始卷积层:7×7 卷积核、64 个滤波器、步幅 2 做特征提取;随后批归一化(BatchNorm)、ReLU 与 3×3 最大池化(步幅 2)。
- 残差块:由 1×1、3×3、1×1 三种卷积构成(Bottleneck 结构),跳跃连接把块输入直接加到块输出上,保证梯度在反向传播中可流通。
- 四个阶段:阶段一 3 个残差块(64 滤波器);阶段二 4 个(128);阶段三 6 个(256);阶段四 3 个(512)。
- 全局平均池化 + 全连接 + Softmax:将特征图压缩为向量并映射到类别数。
三、网络细节
- Bottleneck:每个残差块由三个卷积层组成,1×1 降维、3×3 提取主特征、1×1 恢复维度;部分块用步幅 2 的卷积缩小特征图。
- 参数量:ResNet-50 约有 2.56×10⁷(约 2560 万)个参数。
四、优势与应用
优势在于能有效训练极深网络、在 ImageNet 等视觉任务上表现良好、残差连接缓解梯度消失。常见应用包括图像分类、目标检测(作为 backbone)与图像分割(作为特征提取器)。
五、PyTorch 代码实现
下面给出一个最小化的 ResNet-50 骨架(BasicBlock 版本),以及直接使用 torchvision 预训练模型的写法。
import torch
import torch.nn as nn
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, in_channels, out_channels, stride=1, downsample=None):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
self.downsample = downsample
self.stride = stride
def forward(self, x):
identity = x
if self.downsample is not None:
identity = self.downsample(x)
out = self.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += identity
return self.relu(out)
class ResNet(nn.Module):
def __init__(self, block, layers, num_classes=1000):
super(ResNet, self).__init__()
self.in_channels = 64
self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
self.bn1 = nn.BatchNorm2d(64)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2)
self.layer3 = self._make_layer(block, 256, layers[2], stride=2)
self.layer4 = self._make_layer(block, 512, layers[3], stride=2)
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(512 * block.expansion, num_classes)
def _make_layer(self, block, out_channels, blocks, stride=1):
downsample = None
if stride != 1 or self.in_channels != out_channels * block.expansion:
downsample = nn.Sequential(
nn.Conv2d(self.in_channels, out_channels * block.expansion, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(out_channels * block.expansion))
layers = [block(self.in_channels, out_channels, stride, downsample)]
self.in_channels = out_channels * block.expansion
for _ in range(1, blocks):
layers.append(block(self.in_channels, out_channels))
return nn.Sequential(*layers)
def forward(self, x):
x = self.maxpool(self.relu(self.bn1(self.conv1(x))))
x = self.layer4(self.layer3(self.layer2(self.layer1(x))))
x = torch.flatten(self.avgpool(x), 1)
return self.fc(x)
def resnet50(num_classes=1000):
return ResNet(BasicBlock, [3, 4, 6, 3], num_classes)
model = resnet50(num_classes=10) # 改成你自己的类别数量
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
print(model)
也可直接加载官方预训练模型并替换最后一层:
import torch
import torchvision.models as models
model = models.resnet50(pretrained=True)
num_classes = 10 # 改成你自己的类别数量
model.fc = torch.nn.Linear(model.fc.in_features, num_classes)
model.to(device)
print(model)
qidao123.com企服评测-应用市场 编辑提示:实际工程中更常用 torchvision 提供的 resnet50(pretrained=True),并在自己的数据集上微调最后一层;替换 fc 后再训练可显著缩短收敛时间。
|