VGG_net

本文详细介绍了卷积层和池化层的参数设置,探讨了在PyTorch中如何使用嵌套循环创建灵活的模型结构,以及如何在nn.Module中利用__call__方法进行模型调用。重点讲解了VGG网络的实现,包括输入张量x在前向传播中的作用和处理过程。
摘要由CSDN通过智能技术生成

这篇文章详细给出了卷积层和池化层的各种参数,包含padding和stride,不需要手动计算。

这次不像LeNet那么直白的按顺序写层和结构了,这次是以嵌套循环的方式重复生成卷积层和池化层,这样的写法更聪明。

值得注意的是,pytoon中的新变量声明是弱声明,只要写出变量名= 变量内容即可。

另:

问题一:model没有显示有参数,为何后面使用的时候是model(x):

在这段代码中,虽然在创建model对象时没有显式地调用__call__方法(即没有使用括号传递参数),但是在PyTorch中,nn.Module对象是可调用的(callable),这意味着可以像调用函数一样来使用它们。

当你调用model(x)时,实际上是在调用model对象的__call__方法,这个方法会自动调用forward方法。在nn.Module的子类中,需要实现forward方法来定义模型的前向传播逻辑。因此,通过调用model(x),PyTorch会自动调用model对象的forward方法,并将输入x传递给这个方法来执行前向传播计算。

所以,虽然你没有显式地使用括号传递参数给model对象,但是在PyTorch中,可以通过model(x)这样的形式来调用模型的前向传播操作。这种设计使得模型的使用更加简洁和直观。

具体代码实现如下:

#Imports
import torch
import torch.nn as nn # All neural network modules,nn.Linear,nn.Conv2d,BatchNorm,Loss functions
import torch.optim as optim # For all optimization algorithms,SGD,Adam,etc.
import torch.nn.functional as F # All functions that don't have any parameters
from torch.utils.data import DataLoader # Gives easier dataset managment and creates mini batches
import torchvision.datasets as datasets # Has standard datasets we can import in a nice way
import torchvision.transforms as transforms # Transformations we can perform on our dataset

VGG_types = {
'VGG11': [64,'M',128,'M',256,256,'M',512,512,'M',512,512,'M'],
'VGG13': [64,64,'M',128,128,'M',256,256,'M',512,512,'M',512,512,'M'],
'VGG16': [64,64, 'M', 128,128,'M',256,256,256,'M',512,512,512,'M',512,512,512,'M'],
'VGG19': [64,64, 'M', 128,128, 'M',256,256,256,256,'M',512,512,512,512,'M',512,512,512,512,'M']
}
#Then flatten and 4096x4096x10000 Linear Layers

#VGG16 = [64,64,'M',128,128,'M',256,256,256,'M',512,512,512,'M', 512,512,512,'M']
##Then flatten and 4096x4096x10000 Linear Layers

class VGG_net(nn.Module):
    def __init__(self,in_channels = 3,num_classes = 1000):
        super(VGG_net,self).__init__()
        # self.relu = nn.ReLU()
        # self.pool = nn.AvgPool2d(kernel_size=(2,2),stride=(2,2))
        # self.conv1 = nn.Conv2d(in_channels=1,out_channels=6,kernel_size=(5,5),stride=(1,1),padding=(0,0))
        # self.conv2 = nn.Conv2d(in_channels=6,out_channels=16,kernel_size=(5,5),stride=(1,1),padding=(0,0))
        # self.linear1 = nn.Linear(120,84)        #基本上定义了所有需要用到的层操作,包括不限于激活函数、卷积操作、池化操作、线性操作即全连接层
        
        #上面是之前的做法,这次采用更灵活更聪明的做法
        self.in_channels = in_channels
        self.conv_layers = self.create_conv_layers(VGG_types['VGG16'])
        
        self.fcs = nn.Sequential(   #当一个模型较简单的时候,我们可以使用torch.nn.Sequential类来实现简单的顺序连接模型
            nn.Linear(512*7*7,4096),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(4096,4096),
            nn.ReLU(),
            nn.Dropout(p=0.5),
            nn.Linear(4096,num_classes)
        )

    def forward(self,x):
        x = self.conv_layers(x)
        x = x.reshape(x.shape[0],-1)
        x = self.fcs(x)
        return x

    def create_conv_layers(self,architecture):
        layers = []
        in_channels = self.in_channels

        for x in architecture :
            if type(x) == int :
                out_channels = x
                layers += [nn.Conv2d(in_channels=in_channels,out_channels=out_channels,kernel_size=(3,3),stride=(1,1),padding=(1,1)),
                           nn.BatchNorm2d(x),
                           nn.ReLU()]
                in_channels = x
            elif x == 'M':
                layers += [nn.MaxPool2d(kernel_size=(2,2),stride=(2,2))]
        
        return nn.Sequential(*layers)

device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = VGG_net(in_channels=3,num_classes=1000).to(device)
x = torch.randn(1,3,224,224)
x = x.cuda()#没有这一行会报错:
#错误内容就在类型不匹配,根据报错内容可以看出Input type为torch.FloatTensor(CPU数据类型),而weight type(即网络权重参数这些)为torch.cuda.FloatTensor(GPU数据类型)。
#加了这一行
#inputs = inputs.to(device)        	# 方法一:将input这个tensor转换成了CUDA 类型
#inputs = inputs.cuda()				# 方法二:将input这个tensor转换成了CUDA 类型
print(model(x).shape)

问题二:x的具体含义

在这段代码中,x代表输入的张量,它是一个4维张量,形状为(1, 3, 224, 224)。具体来说,它表示了一个大小为1的batch中包含了一个RGB图像,图像大小为224x224像素。

在模型的前向传播过程中,x会经过一系列的卷积、池化、激活函数等操作,最终被展平并输入到全连接层中进行分类。在forward方法中,x会依次经过self.conv_layersself.fcs两个部分的处理。

  1. x = self.conv_layers(x): 这一步中,输入x会经过VGG网络的卷积层部分,self.conv_layers是一个包含了多个卷积层和激活函数的序列。这些卷积层会提取输入图像的特征。

  2. x = x.reshape(x.shape[0], -1): 在卷积层后,将特征张量展平成一维向量,以便输入到全连接层中。

  3. x = self.fcs(x): 最后,展平后的特征向量经过全连接层部分self.fcs,包含了多个线性层和激活函数,最终输出预测结果。

所以,x在这段代码中代表输入张量,经过模型的前向传播操作后,会得到模型对输入图像的分类结果。

问题三:for x in architecture 里的x和前面说的张量x,是同一个变量吗,还是两个?

在代码中,for x in architecture中的x和我之前提到的张量x是两个不同的变量。让我们来解释一下:

  1. for x in architecture: 这里的x是一个迭代变量,用于遍历architecture列表中的元素。在这个上下文中,x只是一个占位符,用来表示architecture列表中的每个元素。

  2. x张量:在上面的代码中,x张量是一个具体的输入张量,表示一个4维的图像张量。这个张量在模型的前向传播过程中被用作输入数据,经过模型的各个层处理后得到输出结果。

因此,for x in architecture中的x只是一个迭代变量,用于遍历列表中的元素;而x张量是一个具体的输入数据张量,用于模型的前向传播计算。这两个x是不同的变量,代表不同的含义。

问题四:所以python语法里不在乎变量的同名吗?

是的,Python语法允许在不同的作用域中使用同名的变量,因为Python是一种动态类型语言,变量的作用域和类型是在运行时确定的。在不同的作用域中可以使用相同的变量名,但它们实际上是不同的变量。

在代码中,变量的作用域由变量所在的代码块决定。在for x in architecture循环中,x是一个循环变量,它只在循环体内部有效,循环结束后就会被销毁。而在模型前向传播的过程中,x是一个张量变量,它代表输入数据张量,用于模型计算。

因此,尽管这两个变量名字相同,但它们处于不同的作用域,因此不会发生冲突。这种灵活性使得Python代码更容易编写和理解。

  • 36
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值