ResNet模型——pytorch实现

class BasicBlock(nn.Module):  # 定义残差块,resnet18、resnet34使用此残差块
    expansion = 1  # 残差操作维度变化倍数

    def __init__(self, in_channel, out_channel, stride=1, downsample=None):  # 初始化方法
        super(BasicBlock, self).__init__()  # 继承初始化方法

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel, kernel_size=3, stride=stride,
                               padding=1, bias=False)  # conv操作
        self.bn1 = nn.BatchNorm2d(num_features=out_channel)  # bn操作
        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel, kernel_size=3, stride=1, padding=1,
                               bias=False)  # conv操作
        self.bn2 = nn.BatchNorm2d(num_features=out_channel)  # bn操作
        self.relu = nn.ReLU(inplace=True)  # relu激活函数
        self.downsample = downsample  # 是否对原始x操作

    def forward(self, x):  # 前传函数
        identity = x  # 原始x
        if self.downsample:  # 如果对原始x操作
            identity = self.downsample(x)  # 对原始x进行操作,x-->x'

        x = self.conv1(x)  # conv操作
        x = self.bn1(x)  # bn操作
        x = self.relu(x)  # relu激活函数
        x = self.conv2(x)  # conv操作
        x = self.bn2(x)  # bn操作

        x += identity  # F(x)+x/x'
        x = self.relu(x)  # relu激活函数

        return x


class Bottleneck(nn.Module):  # 定义残差块,renet50、resnet101、resnet152使用此残差块
    expansion = 4  # 残差操作维度变化倍数

    def __init__(self, in_channel, out_channel, stride=1, downsample=None, groups=1, base_width=64):  # 初始化方法
        super(Bottleneck, self).__init__()  # 继承初始化方法
        width = int(in_channel * (base_width / 64.0)) * groups  # F(x)第二个卷积的通道数
        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=width, kernel_size=1, stride=1,
                               bias=False)  # conv操作
        self.bn1 = nn.BatchNorm2d(num_features=width)  # bn操作
        self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, groups=groups, kernel_size=3, stride=stride,
                               padding=1, bias=False)  # conv操作
        self.bn2 = nn.BatchNorm2d(num_features=width)  # bn操作
        self.conv3 = nn.Conv2d(in_channels=width, out_channels=out_channel * self.expansion, kernel_size=1, stride=1,
                               bias=False)  # conv操作
        self.bn3 = nn.BatchNorm2d(num_features=out_channel * self.expansion)  # bn操作

        self.relu = nn.ReLU(inplace=True)  # relu激活函数
        self.downsample = downsample  # 是否对原始x操作

    def forward(self, x):  # 前传函数
        identity = x  # 原始x
        if self.downsample:  # 如果对原始x操作
            identity = self.downsample(x)  # 对原始x进行操作,x-->x'

        x = self.conv1(x)  # conv操作
        x = self.bn1(x)  # bn操作
        x = self.relu(x)  # relu激活函数

        x = self.conv2(x)  # conv操作
        x = self.bn2(x)  # bn操作
        x = self.relu(x)  # relu激活函数

        x = self.conv3(x)  # conv操作
        x = self.bn3(x)  # bn操作

        x += identity  # F(x)+x/x'
        x = self.relu(x)  # relu激活函数

        return x


class ResNet(nn.Module):  # 定义resnet模型
    def __init__(self, block, layers, num_classes, in_channel=3, channel=64, groups=1, base_width=64):  # 初始化方法
        super(ResNet, self).__init__()  # 继承初始化方法
        self.in_channel = in_channel  # 输入通道数,应为图片通道数
        self.channel = channel  # 第一次conv输出通道数
        self.groups = groups  # 分组卷积组数
        self.base_width = base_width  # 每组通道数

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=channel, kernel_size=7, stride=2, padding=3,
                               bias=False)  # conv操作
        self.bn1 = nn.BatchNorm2d(self.channel)  # bn操作

        self.relu = nn.ReLU(inplace=True)  # relu激活函数
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)  # maxpool操作

        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(output_size=(1, 1))  # avgpool操作
        self.fc = nn.Linear(512 * block.expansion, num_classes)  # linear映射

        for m in self.modules():  # 遍历模型结构
            if isinstance(m, nn.Conv2d):  # 如果当前结构是卷积操作
                nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity="relu")  # 使用kaiming初始化方法

    def _make_layer(self, block, channel, blocks, stride=1):  # 定义函数,用于生成模型结构
        downsample = None  # 默认不对原始x进行操作

        if stride != 1 or self.channel != channel * block.expansion:  # 如果卷积步长不为1或卷积前后通道数不一致,则需要对原始x进行操作
            downsample = nn.Sequential(
                nn.Conv2d(in_channels=self.channel, out_channels=channel * block.expansion, kernel_size=1,  # conv操作
                          stride=stride, bias=False),
                nn.BatchNorm2d(num_features=channel * block.expansion)  # bn操作
            )
        layers = []  # 列表用于存放模型结构

        layers.append(block(self.channel, channel, downsample=downsample, stride=stride, groups=self.groups,
                            base_width=self.base_width))  # 模型追加block结构
        self.channel = channel * block.expansion  # 通道数转换为卷积后输出通道数
        for _ in range(1, blocks):  # 进行blocks次循环
            layers.append(block(self.channel, channel, groups=self.groups, base_width=self.base_width))  # 模型追加block结构

        return nn.Sequential(*layers)  # 返回模型结构

    def forward(self, x):  # 前传函数
        x = self.conv1(x)  # conv操作
        x = self.bn1(x)  # bn操作
        x = self.relu(x)  # relu激活函数
        x = self.maxpool(x)  # maxpool激活函数

        x = self.layer1(x)  # 第一块残差集合
        x = self.layer2(x)  # 第二块残差集合
        x = self.layer3(x)  # 第三块残差集合
        x = self.layer4(x)  # 第四块残差集合

        x = self.avgpool(x)  # avgpool操作
        x = torch.flatten(x, 1)  # 将多维特征映射成一维特征向量
        x = self.fc(x)  # linear映射

        return x


def resnet18(num_classes=2):  # 定义函数,生成resnet18模型
    return ResNet(BasicBlock, [2, 2, 2, 2], num_classes=num_classes)  # resnet18使用BasicBlock基础残差块,四块残差集合使用的残差块数量为2,2,2,2


def resnet34(num_classes=2):  # 定义函数,生成resnet34模型
    return ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes)  # resnet18使用BasicBlock基础残差块,四块残差集合使用的残差块数量为3,4,6,3


def resnet50(num_classes=2):  # 定义函数,生成resnet50模型
    return ResNet(Bottleneck, [3, 4, 6, 3], num_classes=num_classes)  # resnet18使用Bottleneck基础残差块,四块残差集合使用的残差块数量为3,4,6,3


def resnet101(num_classes=2):  # 定义函数,生成resnet101模型
    return ResNet(Bottleneck, [3, 4, 23, 3],
                  num_classes=num_classes)  # resnet18使用Bottleneck基础残差块,四块残差集合使用的残差块数量为3, 4, 23, 3


def resnet152(num_classes=2):  # 定义函数,生成resnet152模型
    return ResNet(Bottleneck, [3, 8, 36, 3],
                  num_classes=num_classes)  # resnet18使用Bottleneck基础残差块,四块残差集合使用的残差块数量为3, 8, 36, 3

你可能感兴趣的:(pytorch,深度学习,人工智能)