卷积神经网络(四)Resnet网络pytorch实现

1.Resnet 主要结构图

在这里插入图片描述

2.VGG与resnet34比较

注意虚线和实线的区别:

2.1不需要下采样,直接相加

在这里插入图片描述
3.1需要下采样,下采样之后再相加
在这里插入图片描述

在这里插入图片描述

3.resnet参数结构

在这里插入图片描述

4.具有代表性的残差块

前面是34-的,后面是50+的
在这里插入图片描述

5.具体代码实现

5.1先定义适合Resnet34的基础卷积块

#18,34

class BasicBlock(nn.Module):
    #因为第一个卷积和第二个卷积的通道数一样,所以这个设置为1
    expansion = 1

    def __init__(self, in_channel, out_channel, stride=1, downsample=None):
        super(BasicBlock, self).__init__()
        #Conv(3x3,64)  stride=1
        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,
                               kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channel)
        self.relu = nn.ReLU()
        #Conv(3x3,64)   stride=1
        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,
                               kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channel)
        #残差边
        self.downsample = downsample
    def forward(self, x):
        #
        identity = x
        #判断是否需要下采样   
        if self.downsample is not None:
            #若需要
            identity = self.downsample(x)
        #第一次卷积
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        #第二次卷积
        out = self.conv2(out)
        out = self.bn2(out)
        #相加之后传入给激活函数
        out += identity
        out = self.relu(out)
      
        return out

5.2Resnet50基础卷积块

#50,101,152
class Bottleneck(nn.Module):
    #第三个卷积块的通道数是第一个的四倍(64->256) ,前面定义方便后面运算
    expansion = 4

    def __init__(self, in_channel, out_channel, stride=1, downsample=None):
        super(Bottleneck, self).__init__()

        #Conv(1x1,64)  stride=1 

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,
                               kernel_size=1, stride=1, bias=False)  # squeeze channels
        self.bn1 = nn.BatchNorm2d(out_channel)

        # Conv(3x3,64)   第一个的时候stride=2 其他就是=1

        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,
                               kernel_size=3, stride=stride, bias=False, padding=1)   #stride=2,stride=1
        self.bn2 = nn.BatchNorm2d(out_channel)

        #Conv(1x1,256)  stride=1

        self.conv3 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel*self.expansion,
                               kernel_size=1, stride=1, bias=False)  # unsqueeze channels
        self.bn3 = nn.BatchNorm2d(out_channel*self.expansion)

        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample



    def forward(self, x):
        identity = 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)
        #是否要进行下采样
        if self.downsample is not None:
            identity = self.downsample(x)
        #相加之后再使用激活函数
        out += identity
        out = self.relu(out)

        return out

6.模型整体代码:

import torch.nn as nn
import torch

#18,34

class BasicBlock(nn.Module):
    #因为第一个卷积块和第二个卷积块的通道数一样,所以这个设置为1
    expansion = 1

    def __init__(self, in_channel, out_channel, stride=1, downsample=None):
        super(BasicBlock, self).__init__()
        #Conv(3x3,64)  stride 要自己定义,因为如果为大卷积块的第一个残差网络,这儿的步长就是2
        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,
                               kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channel)
        self.relu = nn.ReLU()
        #Conv(3x3,64)   stride=1
        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,
                               kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channel)
        #残差边
        self.downsample = downsample
    def forward(self, x):
        #
        identity = x
        #判断是否需要下采样   
        if self.downsample is not None:
            #若需要
            identity = self.downsample(x)
        #第一次卷积
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        #第二次卷积
        out = self.conv2(out)
        out = self.bn2(out)
        #相加之后传入给激活函数
        out += identity
        out = self.relu(out)
      
        return out

#50,101,152
class Bottleneck(nn.Module):
    #第三个卷积块的通道数是第一个的四倍(64->256) ,前面定义方便后面运算
    expansion = 4

    def __init__(self, in_channel, out_channel, stride=1, downsample=None):
        super(Bottleneck, self).__init__()

        #Conv(1x1,64)  stride=1 

        self.conv1 = nn.Conv2d(in_channels=in_channel, out_channels=out_channel,
                               kernel_size=1, stride=1, bias=False)  # squeeze channels
        self.bn1 = nn.BatchNorm2d(out_channel)

        # Conv(3x3,64)   第一个的时候stride=2 其他就是=1

        self.conv2 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel,
                               kernel_size=3, stride=stride, bias=False, padding=1)   #stride=2,stride=1
        self.bn2 = nn.BatchNorm2d(out_channel)

        #Conv(1x1,256)  stride=1

        self.conv3 = nn.Conv2d(in_channels=out_channel, out_channels=out_channel*self.expansion,
                               kernel_size=1, stride=1, bias=False)  # unsqueeze channels
        self.bn3 = nn.BatchNorm2d(out_channel*self.expansion)

        self.relu = nn.ReLU(inplace=True)
        self.downsample = downsample



    def forward(self, x):
        identity = 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)
        #是否要进行下采样
        if self.downsample is not None:
            identity = self.downsample(x)
        #相加之后再使用激活函数
        out += identity
        out = self.relu(out)

        return out


class ResNet(nn.Module):
    #block       :BasicBlock    Bottleneck
    #blocks_num  :[3, 4, 6, 3], [3, 4, 23, 3]
    #num_classes=1000

    def __init__(self, block, blocks_num, num_classes=1000, include_top=True):
        super(ResNet, self).__init__()

        self.include_top = include_top  #看是否有后面的全连接
        #定义初始通道数=64
        self.in_channel = 64

        #第一个卷积层(7x7,64)  stride=2
        self.conv1 = nn.Conv2d(3, self.in_channel, kernel_size=7, stride=2,
                               padding=3, bias=False)
        self.bn1 = nn.BatchNorm2d(self.in_channel)
        self.relu = nn.ReLU(inplace=True)

        #(3x3,2)  stride=2
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        #第一个卷积层结束
        #Bottleneck ,64,3
        #
        #
        #

        self.layer1 = self._make_layer(block, 64, blocks_num[0])
        #

        self.layer2 = self._make_layer(block, 128, blocks_num[1], stride=2)


        self.layer3 = self._make_layer(block, 256, blocks_num[2], stride=2)


        self.layer4 = self._make_layer(block, 512, blocks_num[3], stride=2)


        if self.include_top:
            self.avgpool = nn.AdaptiveAvgPool2d((1, 1))  # output size = (1, 1)
            self.fc = nn.Linear(512 * block.expansion, num_classes)

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
        #Bottleneck ,64,3
        #Bottleneck ,128,4
        #Bottleneck ,256,6
        #Bottleneck ,512,3


    def _make_layer(self, block, channel, block_num, stride=1):
        #下采样初始定义为:None
        downsample = None

        """
        下采样部分

        """
        
        #当步长不等于1,或者输入通道不等于 4xchannel的时候要进行下采样

        #stride=2,这个数值要自己传入的,channel,这个数值也是要自己传入的

        #只有这种情况才执行下采样:3个大块,第一个小块开始的时候才执行这个下采样,为了特征图大小维度一致
        #                      : 4个大块。。。。。。。。。。
        #                      :6个大块。。。。。。。。。。
        #                      :3个大块。。。。。。。。。。

        if stride != 1 or self.in_channel != channel * block.expansion:   #当步长不等于一,In_channel不等于四倍的block.expension
        #把特征的维度,宽高都要和前面的搞一致,这样就可以相加了

            downsample = nn.Sequential(
                nn.Conv2d(self.in_channel, channel * block.expansion, kernel_size=1, stride=stride, bias=False),  #stride=2
                nn.BatchNorm2d(channel * block.expansion))


        #定义一个列表 
        layers = []
        #
        #64,64,None,1
        #把第一个卷积层传入到列表中   第一个含有下采样,其他的没有
        #注意这个block()代表的是所要传入的参数,
        layers.append(block(self.in_channel, channel, downsample=downsample, stride=stride)) #stride=2(50) #stride=1(34)
        #256
        #重新定义4倍
        self.in_channel = channel * block.expansion   #256,512,1024,2048
        #(1,3)

        for i in range(1, block_num):    #(1到block_num) 不包括block_num  (0,block_num)0,       #1,2
            #block()->Bottleneck()
            layers.append(block(self.in_channel, channel))     #256, 64 
        #256
        """0
        inchannel=256,这个就是下采样的那个残差网络块,产生的,因为他是一个块一个块的,用block(self.in_channel=256,channel=64)
        #对于这个channel=64这个,self._make_layer(block, 64, blocks_num[0]),这个参数一定要对应,channel里面是64,调用make_layer()的时候
        要注意前面传入的block,后面传入的是channel,block里面的参数就是残差网络块的了
        终于0明0白
        """
        return nn.Sequential(*layers)
        #注意参数的对应,

    def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)

        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)

        if self.include_top:
            x = self.avgpool(x)
            x = torch.flatten(x, 1)
            x = self.fc(x)

        return x


def resnet34(num_classes=1000, include_top=True):
    return ResNet(BasicBlock, [3, 4, 6, 3], num_classes=num_classes, include_top=include_top)



def resnet101(num_classes=1000, include_top=True):
    return ResNet(Bottleneck, [3, 4, 23, 3], num_classes=num_classes, include_top=include_top)

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 卷积神经网络(CNN)是一种深度学习算法,通常用于解决计算机视觉问题。在人脸识别领域,CNN非常适合提取人脸图像的特征,因为它可以自动学习并提取最有意义的特征。 PyTorch是一种基于Python的深度学习框架,可以帮助开发人员快速设计、构建和训练深度学习模型。在人脸识别领域,PyTorch已被广泛使用。 基于卷积神经网络的人脸识别模型通常由卷积层、池化层、全连接层和分类器组成。 卷积层主要用于提取人脸图像的特征,而池化层则用于减少模型的参数数量和计算量。 全连接层是用于该模型的分类器,通常用于将卷积层和池化层中提取的特征将其转换为可供分类器识别的形式。 在使用PyTorch进行人脸识别时,通常需要遵循以下步骤: 1. 收集和准备人脸数据集。 2. 构建卷积神经网络。 3. 通过将数据集分割成训练集和测试集来训练模型。 4. 评估模型的准确性以及确定任何需要进行调整的部分。 5. 使用模型进行实际的人脸识别任务。 基于卷积神经网络的人脸识别模型具有许多优势,包括高准确度、高效、可伸缩性和应用范围广,已经被广泛应用于面部识别,安全和监控系统等领域。 ### 回答2: 基于卷积神经网络的人脸识别是目前人工智能领域的热门应用之一,其中pytorch是当前广泛应用于该领域的深度学习框架之一。卷积神经网络是一种特殊类型的神经网络,具有良好的特征提取和分类能力,适合用于人脸识别领域。 在pytorch中,可以通过搭建卷积神经网络来进行人脸识别。首先,需要准备一组训练数据集和测试数据集,可以采用公开的人脸数据集,如LFW数据集。接着,可以使用pytorch的卷积层、池化层、全连接层等组件搭建卷积神经网络模型,可以采用经典的卷积神经网络结构,如AlexNet、VGG或ResNet等。 然后,需要对训练数据集进行数据增强、归一化等预处理操作,并使用损失函数来进行模型的训练和优化。同时,为了避免过拟合,可以采用一些正则化方法,如dropout、L1/L2正则化等。 最后,在测试阶段,可以将测试数据集输入训练好的人脸识别模型中,通过计算模型的预测结果(如softmax概率分布)来进行人脸识别判别。 总的来说,基于卷积神经网络的人脸识别pytorch实现较为简单易懂,具有很高的精度和效率,有着广泛的应用前景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值