问题
SqueezeNet是一款非常经典的CV网络,其设计理念对后续的很多网络都有非常强的指导意义,其核心思想包括:
- 使用1x1卷积核替代3x3,主要原因是3x3的卷积核参数量是1x1的9倍多;
- 降低3x3卷积核的通道数量;
- 网络结构中延迟下采样的时机以获得较大尺寸的激活特征图;
方法
下面介绍PyTorch实现的SqueezeNet网络最核心的Fire模块,如下:
import torch
from torch import nn, Tensor
from typing import Any
class BasicConv2d(nn.Module):
def __init__(self, in_channels: int, out_channels: int, **kwargs: Any) -> None: # 增加in_xxx和out_xxx的好处是,调用的时候可以省略参数名
super().__init__()
self.conv2d = nn.Conv2d(in_channels, out_channels, **kwargs) # **容易漏掉
self.relu = nn.ReLU()
def forward(self, x: Tensor) -> Tensor:
x = self.conv2d(x)
out = self.relu(x)
return out
class Fire(nn.Module):
def __init__(self, in_channels: int, s_1x1: int, e_1x1: int, e_3x3: int) -> None:
super().__init__()
self.squeeze = BasicConv2d(in_channels, s_1x1, kernel_size=1)
self.expand_1x1 = BasicConv2d(s_1x1, e_1x1, kernel_size = 1)
self.expand_3x3 = BasicConv2d(s_1x1, e_3x3, kernel_size = 3, padding = 1) # p=1是为了保持3x3特征图不变
def forward(self, x: Tensor) -> Tensor:
x = self.squeeze(x)
return torch.cat([
self.expand_1x1(x),
self.expand_3x3(x)
], dim=1)
if __name__ == '__main__':
x = torch.rand(size=(1, 3, 224, 224))
conv2d = BasicConv2d(3, 64, kernel_size = 3, padding = 1, stride = 1)
print(conv2d(x).shape) # torch.Size([1, 64, 224, 224])
fire = Fire(3, 32, 32, 48)
print(fire(x).shape) # torch.Size([1, 80, 224, 224])