【AI 进阶笔记】 DetNet 知识点学习
1. DetNet 是啥?
在目标检测领域,主流的方法一般都是基于 CNN(卷积神经网络)的,比如 Faster R-CNN、YOLO、SSD 这些大佬。但这些传统方法有个痛点:网络越深,感受野越大,但特征图越来越小,导致目标检测特别是小目标检测的效果不太行。
DetNet 论文的核心目的,就是解决深层网络导致的分辨率下降问题,让目标检测能在不牺牲高层语义信息的情况下,保留较高的分辨率,从而提升检测效果,特别是小目标的检测能力。
简单来说,DetNet 就是个 更适合目标检测的 CNN 结构,它的主要思路是:
- 保持特征图的较高分辨率(不让它变得太小)
- 扩大感受野(让网络能“看”得更远)
- 增强检测能力(小目标也能发现)
2. DetNet 的核心思想?
DetNet 论文的核心贡献在于设计了一种新型的 Backbone(骨干网络)结构,让检测任务的特征图在深层网络里依然能保持较大尺寸。
传统的 CNN,比如 ResNet,层数越深,特征图缩小得越厉害。比如,一张 512x512 的图片经过 ResNet 的卷积后,到了深层可能只剩下 16x16 的特征图,这对于目标检测尤其是小目标检测是个噩梦!
DetNet 通过以下几个设计巧妙地避免了这个问题:
- 引入扩张卷积(Dilated Convolution) 来扩大感受野,同时保持特征图的分辨率。
- 去掉 ResNet 里最后的降采样(Stride=2 的池化/卷积),让特征图不变小。
- 重新设计 Bottleneck 结构,适配检测任务。
简单来说,DetNet 就是 ResNet 的改进版,专门为目标检测优化,让检测头能获取更多有用的信息。
3. DetNet 关键技术解析
在 PyTorch 代码实现之前,我们先搞清楚 DetNet 的几个核心设计点:
3.1 扩张卷积(Dilated Convolution)
DetNet 里最关键的技术之一就是 扩张卷积(又叫空洞卷积),这个东西的作用是 增大感受野,同时不降低分辨率。
传统卷积 VS 扩张卷积:
- 传统卷积:3×3 的卷积核,只能看 3×3 的局部区域。
- 扩张卷积:3×3 的卷积核,但可以通过 跳跃 采样,比如膨胀系数=2 时,它其实是 5×5 的感受野,但计算量仍然是 3×3 的水平。
这样一来,我们就可以用小小的计算量,获得更大的感受野,而不会让特征图变得太小。
3.2 不降采样(保持高分辨率)
在传统的 ResNet 里,到达 Stage 5(最后几个残差块)时,特征图已经变得很小(1/32 原图尺寸)。而 DetNet 直接干掉了最后的降采样,让特征图保持在 1/16 甚至 1/8 原图尺寸,这样目标检测头就能用到更清晰的特征图。
3.3 重新设计的 Bottleneck 结构
DetNet 里用了一种特殊的 残差块(Bottleneck),这个块里面的 3x3 卷积被替换成了 扩张卷积,这样可以同时 保留特征图的大小,又能获取更大感受野。
4. PyTorch 实现 DetNet
理解了 DetNet 的核心思想后,我们来用 PyTorch 实现一个 DetNet 的 Backbone(骨干网络),然后让它跑起来!
4.1 先定义 DetNet 的 Bottleneck 结构
代码语言:python代码运行次数:0运行复制import torch
import torch.nn as nn
class DetBottleneck(nn.Module):
def __init__(self, in_channels, out_channels, dilation):
super(DetBottleneck, self).__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3,
padding=dilation, dilation=dilation, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
self.conv3 = nn.Conv2d(out_channels, out_channels, kernel_size=1, bias=False)
self.bn3 = nn.BatchNorm2d(out_channels)
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
return self.relu(out)
这个结构就是 DetNet 里用的特制残差块,里面的 conv2
是扩张卷积。
4.2 组装 DetNet Backbone
代码语言:python代码运行次数:0运行复制class DetNet(nn.Module):
def __init__(self, num_classes=20):
super(DetNet, self).__init__()
self.layer1 = DetBottleneck(64, 128, dilation=1)
self.layer2 = DetBottleneck(128, 256, dilation=2)
self.layer3 = DetBottleneck(256, 512, dilation=4)
self.classifier = nn.Conv2d(512, num_classes, kernel_size=1)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.classifier(x)
return x
这个 DetNet
类就是一个完整的骨干网络结构,最后接了个 1x1
的卷积层,用于分类。
4.3 试运行
代码语言:python代码运行次数:0运行复制model = DetNet(num_classes=20)
x = torch.randn(1, 64, 128, 128) # 假设输入是一张 128x128 的图片
output = model(x)
print(output.shape)
输出的 shape
应该是 (1, 20, 128, 128)
,证明 DetNet 确实保留了高分辨率的特征图!