特点 H(x) = F(x) + x
在layer1,layer2,layer3,layer4中,使用残差连接,即输入+原输出 作为新的输出, 即 out += identity
第一层:nn.Conv2d
import torch.nn as nn
# 第一个,输入通道3,输出通道64
# 如果输入图片大小为3*224*224,则输入为长宽为(224+3*2-7)/2+1=112,形状为64*112*112
# 参数量为3*7*7*64
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, bias=False)
# 参数量为64 * 2 = 128 (每个通道的均值和方差)
nn.BatchNorm2d(64)
nn.ReLU(inplace=True)
#64*112*112 输入,输入为64*56*56
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
layer1 *2
网络层2层运行2遍,所以包含四层网络。通道数64
in_channels=64
out_channels=64
#参数量 = (3 kernel * 3 kernel * 64 in_channels) * 64 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=2, padding=1, bias=False)
in_channels=out_channels
nn.BatchNorm2d(out_channels)
nn.ReLU(inplace=True)
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
nn.BatchNorm2d(out_channels)
# 残差连接,将第二个3x3卷积层的输出与输入(即第一个3x3卷积层之前的特征图)直接相加
# 输入输出通道数相同,所以直接使用输入的x
identity=x
out += identity
nn.ReLU(inplace=True)
layer2 *2
网络层2层运行2遍,所以包含四层网络。通道数从64变成128
#第二遍的时候in_channels=128
in_channels=64
out_channels=128
# 输入输入通道数不一样,先用1x1卷积核变化下通道数,然后再残差连接
#参数量 = (1 kernel * 1 kernel * 64 in_channels) * 128 out_channels
identity=nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False)(x)
#参数量 = (3 kernel * 3 kernel * 64 in_channels) * 128 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=2, padding=1, bias=False)
in_channels=out_channels
nn.BatchNorm2d(out_channels)
nn.ReLU(inplace=True)
#参数量 = (3 kernel * 3 kernel * 128 in_channels) * 128 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
nn.BatchNorm2d(out_channels)
# 残差连接,将第二个3x3卷积层的输出与输入(即第一个3x3卷积层之前的特征图)直接相加
out += identity
nn.ReLU(inplace=True)
layer3 *2
网络层2层运行2遍,所以包含四层网络。通道数从128变成256
#第二遍的时候in_channels=256
in_channels=128
out_channels=256
# 输入输入通道数不一样,先用1x1卷积核变化下通道数,然后再残差连接
#参数量 = (1 kernel * 1 kernel * 64 in_channels) * 128 out_channels
identity=nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False)(x)
#参数量 = (3 kernel * 3 kernel * 128 in_channels) * 256 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=2, padding=1, bias=False)
in_channels=out_channels
nn.BatchNorm2d(out_channels)
nn.ReLU(inplace=True)
#参数量 = (3 kernel * 3 kernel * 256 in_channels) * 256 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
nn.BatchNorm2d(out_channels)
# 残差连接,将第二个3x3卷积层的输出与输入(即第一个3x3卷积层之前的特征图)直接相加
out += identity
nn.ReLU(inplace=True)
layer4 *2
网络层2层运行2遍,所以包含四层网络。通道数从256变成512
#第二遍的时候in_channels=512
in_channels=256
out_channels=512
#参数量 = (3 kernel * 3 kernel * 256 in_channels) * 512 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=2, padding=1, bias=False)
in_channels=out_channels
nn.BatchNorm2d(out_channels)
nn.ReLU(inplace=True)
#参数量 = (3 kernel * 3 kernel * 512 in_channels) * 512 out_channels
nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
nn.BatchNorm2d(out_channels)
# 残差连接,将第二个3x3卷积层的输出与输入(即第一个3x3卷积层之前的特征图)直接相加
# 输入输入通道数不一样,先用1x1卷积核变化下通道数,然后再残差连接
identity=nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False)(x)
out += identity
nn.ReLU(inplace=True)
最后一层:全连接层
#自适应平均池化层,用于将输入的二维特征图池化成单个点
nn.AdaptiveAvgPool2d((1, 1))
torch.flatten(x, 1)
# 全连接层
# 参数量 = (输出通道数最后一层 * 通道数) * 分类数 = 512 * 1000 = 512,000
nn.Linear(512, 1000)