李哥考研深度学习项目(四),图片分类理论

一.卷积神经网络

1.手动计算卷积神经网络

(1)现有特征图4*4. 卷积核大小为2, 卷出来的特征图多大。卷积核的参数量多少?

答:即为4*4的矩阵每2*2的矩阵可以乘一次可以得到3*3的矩阵,因此特征图为3*3,卷积核的参数量为2*2=4

(2)现有特征图4*4. 卷积核大小为3, 卷出来的特征图多大。

答:即为4*4的矩阵每3*3的矩阵可以乘一次可以得到2*2的矩阵,因此特征图为2*2

也可以得到一个公式:特征图-卷积核大小+1=特征图大小

(3)现有特征图4*4. 卷积核大小为3,padding 1, 卷出来的特征图多大。

注:Padding(填充)在卷积神经网络(CNN)中是指在输入数据的边缘添加额外的像素(通常是零),以影响卷积操作的输出。即为在矩阵周围添加一圈的0,再参与运算。

答:即可算出特征值为4-3+1+2=4,特征图表示不变,仍为4*4。

(4)特征图100*100,卷积核 7,padding多少,特征图大小不变。

100-7+1=94,若要使特征图大小不变,100-94=6,padding要为3

(5)特征图3*4*4. padding1, 卷积核数量1,卷出来的特征图为1*4*4。这套卷积核多大? 卷积核的参数量多少?

答:厚度为3,padding为1因此4*4的特征图不会变化,卷积的大小为3*3,厚度为3,因此卷积核为3*3*3,卷积核的参数量为1*3*3*3=27

(6)特征图3*4*4. 卷积核3*3*3, padding1, 卷积核数量7,卷出来的特征图多大。

答:因为padding为1,输出空间的尺寸为4*4,输出的通道数是7(即卷积核数量为7),因此特征图大小为7*4*4

(7)特征图3*224*224. 卷积核3*3*3, padding=1,卷积核数量64.卷出来的特征图多大?

答:64*224*224

(8)特征图64*224*224. 卷积核64*3*3, padding=1,卷积核数量128 卷出来特征图多大。这套卷积核的参数量多少?

答:特征图大小:128*224*224,卷积核的参数量可以通过以下公式计算:

卷积核参数量=(卷积核的高度×卷积核的宽度×输入通道数+1)×输出通道数(1为bias,可以省略)

卷积核的高度×卷积核的宽度:3*3

输入通道数与输入特征图的通道数一致,也为64

输出的通道数为128(即卷积核数量为128)

因此卷积核的参数量为(3*3*64)*128

二.AlexNet模型的代码解析

1. 引入库和预训练的AlexNet模型

import torchvision.models as models
import torch.nn as nn
alexnet = models.alexnet()
print(alexnet)

先从torchvision导入alexnet模型,并输出alexnet模型。

2. 定义类

class MyAlexNet(nn.Module):
    def __init__(self):
        super(MyAlexNet, self).__init__()
        self.relu = nn.ReLU()
        self.drop = nn.Dropout(0.5)

在初始化函数中,首先定义了ReLU激活函数和Dropout,其中Dropout为了防止过拟合,每个训练时的神经元有50%被丢弃

3.定义卷积层和池化层

self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=11, stride=4, padding=2)
self.pool1 = nn.MaxPool2d(3, stride=2)
self.conv2 = nn.Conv2d(64, 192, 5, 1, 2)
self.pool2 = nn.MaxPool2d(3, stride=2)

self.conv3 = nn.Conv2d(192, 384, 3, 1, 1)
self.conv4 = nn.Conv2d(384, 256, 3, 1, 1)
self.conv5 = nn.Conv2d(256, 256, 3, 1, 1)

self.pool3 = nn.MaxPool2d(3, stride=2)
self.adapool = nn.AdaptiveAvgPool2d(output_size=6)

conv1:卷积层,输入三通道(RGB图像),输出64通道,使用大小的卷积核kernel_size为11,步长stride为4,padding填充为2

pool1:池化层,为3*3的窗口,步长为2,用于减少空间维度

conv2到conv5的后续卷积层每一层将输入特征图的通道数逐渐改变,卷积核从5变到3,步长和填充保持1,每层卷积后都有ReLU激活函数进行非线性变换

pool2和pool3:池化层用于逐渐降低空间的维度,保留最显著的特征

adapool:自适应平均池化,最终将所有特征图池化为固定的6x6尺寸,无论输入图像的大小如何。

4. 定义全连接层

self.fc1 = nn.Linear(9216, 4096)
self.fc2 = nn.Linear(4096, 4096)
self.fc3 = nn.Linear(4096, 1000)

fc1:全连接层,将输入9216维,映射到4096维

fc2:另一个全连接层,输入4096,映射到4096维

fc3:最终的全连接层,将4096维,映射到1000维

5.forward方法

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

    x = self.conv2(x)
    x = self.relu(x)
    x = self.pool2(x)

    x = self.conv3(x)
    x = self.relu(x)
    print(x.size())  # 打印当前尺寸
    x = self.conv4(x)
    x = self.relu(x)
    print(x.size())
    x = self.conv5(x)
    x = self.relu(x)
    x = self.pool3(x)
    print(x.size())
    x = self.adapool(x)
    x = x.view(x.size()[0], -1)

    x = self.fc1(x)
    x = self.relu(x)
    x = self.fc2(x)
    x = self.relu(x)
    x = self.fc3(x)
    x = self.relu(x)

    return x

卷积操作:数据从conv1开始,通过ReLU和池化层逐渐提取特征

打印尺寸:每一层卷积操作后,打印当前的张量尺寸(通过print(x.size())),帮助调试。随着层加深,图像的空间维度会减小

自适应池化:在最后,通过adapool将图像大小缩放为6*6

展平:x = x.view(x.size()[0], -1)将特征图展平为一维向量,准备用于全连接层

全连接层:数据通过三个全连接层,最终输出1000个类别的概率。

6. 计算模型的参数数量

def get_parameter_number(model):
    total_num = sum(p.numel() for p in model.parameters())
    trainable_num = sum(p.numel() for p in model.parameters() if p.requires_grad)
    return {'Total': total_num, 'Trainable': trainable_num}

print(get_parameter_number(myalexnet))

get_parameter_number计算模型的总参数数(total_num)和可训练参数(trainable_num)用于评估模型的大小。

model.parameters():这是PyTorch中每个模型对象的一个方法,它返回模型中所有参数(包括权重和偏置),这些参数通常是nn.Parameter类型的张量。

p.numel():是PyTorch中的一个函数,用来返回一个张量中元素的总数

7.模拟输入并查看输出

img = torch.zeros((4, 3, 224, 224))
out = myalexnet(img)
print(out.size())

img:我们使用torch.zeros创建了一个大小为(4, 3, 224, 224)的零图像张量,表示4个图像

8.模型源码

import torchvision.models as models
import torch.nn as nn


alexnet = models.alexnet()


print(alexnet)

class MyAlexNet(nn.Module):
    def __init__(self):
        super(MyAlexNet, self).__init__()
        self.relu = nn.ReLU()
        self.drop = nn.Dropout(0.5)

        self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=11, stride=4,padding=2)
        self.pool1 = nn.MaxPool2d(3, stride=2)
        self.conv2 = nn.Conv2d(64,192,5,1,2)
        self.pool2 = nn.MaxPool2d(3, stride=2)

        self.conv3 = nn.Conv2d(192,384,3,1,1)

        self.conv4 = nn.Conv2d(384,256,3,1,1)

        self.conv5 = nn.Conv2d(256, 256, 3, 1, 1)

        self.pool3 = nn.MaxPool2d(3, stride=2)
        self.adapool = nn.AdaptiveAvgPool2d(output_size=6)

        self.fc1 = nn.Linear(9216,4096)

        self.fc2 = nn.Linear(4096,4096)

        self.fc3 = nn.Linear(4096,1000)

    def forward(self,x):

        x = self.conv1(x)
        x = self.relu(x)
        x = self.pool1(x)

        x = self.conv2(x)
        x = self.relu(x)
        x = self.pool2(x)


        x = self.conv3(x)
        x = self.relu(x)
        print(x.size())
        x = self.conv4(x)
        x = self.relu(x)
        print(x.size())
        x = self.conv5(x)
        x = self.relu(x)
        x = self.pool3(x)
        print(x.size())
        x= self.adapool(x)
        x = x.view(x.size()[0], -1)

        x = self.fc1(x)
        x = self.relu(x)

        x = self.fc2(x)
        x = self.relu(x)

        x = self.fc3(x)
        x = self.relu(x)

        return x


import torch

myalexnet = MyAlexNet()

def get_parameter_number(model):
    total_num = sum(p.numel() for p in model.parameters())
    trainable_num = sum(p.numel() for p in model.parameters() if p.requires_grad)
    return {'Total': total_num, 'Trainable': trainable_num}


print(get_parameter_number(myalexnet))

img = torch.zeros((4,3,224,224))

out = myalexnet(img)

print(out.size())

三.ResNet模型的代码解析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值