PyTorch深度学习实践(十)卷积神经网络基础篇

介绍

全连接网络:指的是网络里面用的都是线性层,如果一个网络全都由线性层串行连接起来,就叫做全连接网络
在这里插入图片描述在线性层里面输入和每一个输出值之间都存在权重,即每一个输入节点都要参与到下一层输出节点的计算上,这样的线性层也叫全连接层 Fully Connected
在这里插入图片描述
卷积神经网络把图像按照原始的空间结构保存,能保留原始的空间信息
在这里插入图片描述经过一个卷积层把12828的图像变成42424
使用下采样(subsampling)时,通道数不会改变,图像的宽度和高度会改变,下采样的目的是减少数据的数据量,减少特征图(Feature map)的元素数量,目的是降低运算需求,因为是做分类,最终的目的是通过不断的卷积运算输出一个概率向量
现在输入的维度比较高,需要不断地进行维度(可以先升高后降低)和大小上的变化,最终把图像由12828的张量变成概率向量
在这里插入图片描述如上图,又经过了卷积和下采样,针对MNIST数据集,最注重输出的是图像对应所属10个分类的概率,所以最后要把844的三阶张量展开成一个一维的向量,可以用上一讲里面的view来实现,8个通道,每个通道有4*4个元素,按照某种顺序,把它展开成一维向量 ,如下图
在这里插入图片描述展开之后就得到了线性的只有向量的输入,再用全连接层最终把这个向量映射到10维的输出,然后接上交叉熵损失利用softmax计算概率分布,解决分类问题
在这里插入图片描述所以构建神经网络的时候,首先要明确你的输入张量的维度,输出张量的维度,要让网络正常工作,要用各种层进行维度或者每个维度上大小的变化,最终映射到我们想要的输出空间
所以实际上卷积和全连接都是在做这样一种空间变换
神经网络里面,卷积和下采样叫做特征提取器,能通过卷积运算,找到某种特征
在这里插入图片描述分类器:经过特征提取之后把它变成向量,然后把这个向量连接全连接网络做分类
在这里插入图片描述

问题:卷积核怎么寻找特征?

待解答

图像到底是什么?

一般是用RGB三个通道表示的,如下图,每一个图像可以划分成很多个格子,给每一个格子填上颜色值就构成一个图像,叫做栅格图像,基本上从自然界获取图像都是采用这样的方式
图像如果放大就是一个一个的格子
在这里插入图片描述 相机拍照时,是通过传感器获得像素值,有红绿蓝三种颜色的传感器,传感器上有光敏电阻,电阻值与RGB值有对应关系,最终获得图像
在这里插入图片描述用这个卷积块把图像遍历一遍,然后对每一个块做卷积运算,得到卷积输出结果,最后把输出结果拼到一起,这就是卷积

单通道图像卷积

在这里插入图片描述在这里插入图片描述
如上图,输入是155的图像,卷积核是33,步长为1,经过卷积核在输入矩阵上运算(计算方式如上图)得到了13*3的输出,以上是一个通道的卷积运算方法

多通道卷积

比如输入图像是3个通道,到神经网络中间的时候输入通道不一定是3个,几百个通道都有可能,以3通道为例,每一个通道都要配一个核,输入通道的数量与核的数量是一样的
如下图,三个通道分别和卷积核做卷积,得到3个矩阵,然后相加
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

为什么输出的宽度和高度是3呢?

我们看每一次卷积的中心
在这里插入图片描述
如果是3*3的卷积核,宽高是会减2的,上下左右各减一个

在这里插入图片描述如果想要输出是m个通道怎么办呢?
那就准备m个卷积核,每一个卷积核对原始输入卷积完之后通道数都是1,然后把这些通道拼接起来
每一个卷积核通道数量要求和输入通道一样
卷积核的数量和输出通道数是一样的
卷积核的大小自己定,与图像大小无关
共享权重机制:对每一个图像块操作用的是相同的卷积核
在这里插入图片描述
可以把m个卷积核拼成4维张量 m(卷积核个数)*n(通道数)widthheight,我们构建卷积层,它的权重就是这样的一个维度
在这里插入图片描述#卷积层并不在于输入的张量的宽度和高度,因为我们是复用的权重,只是把图像遍历一遍,图像大输出就打,图像小,输出就小
#所以卷积层对输入图像的宽度和高度没有要求,只对输入通道数有要求
#定义一个卷积层,需要确定输入通道,输出通道,卷积核的大小

import torch
in_channels,out_channels=5,10#n,m
width,height=100,100#图像的大小
kernel_size=3#卷积核的大小3*3
batch_size=1#pytorch里面所有输入的数据必须是小批量的数据
input=torch.randn(batch_size,
                  in_channels,
                  width,
                  height)#batch_size表示小批量的第几个
#torch.randn 生成输入数据的时候取的随机数,服从正态分布采样的随机数
conv_layer=torch.nn.Conv2d(in_channels,
                           out_channels,
                           kernel_size=kernel_size)
#Conv2d,卷积核也可以用长方形的,kernel_size=(5,3)
output=conv_layer(input)#把输入传进卷积层,得到输出
print(input.shape)#[1,5,100,100]
print(output.shape)#[1,10,98,98]
print(conv_layer.weight.shape)#卷积层权重的形状[10,5,3,3],10是输出通道的数量,5是输入通道的数量,3,3是卷积核的大小
#卷积层并不在于输入的张量的宽度和高度,因为我们是复用的权重,只是把图像遍历一遍,图像大输出就打,图像小,输出就小
#所以卷积层对输入图像的宽度和高度没有要求,只对输入通道数有要求
#定义一个卷积层,需要确定输入通道,输出通道,卷积核的大小

结果

torch.Size([1, 5, 100, 100])
torch.Size([1, 10, 98, 98])
torch.Size([10, 5, 3, 3])

怎么保证卷积之后图像宽高不变?

在这里插入图片描述这是有规律可循的
如果卷积核是33,3/2=1----->在原矩阵外补1圈0 padding=1
如果卷积核是5
5,5/2=2----->在原矩阵外补2圈0 padding=2

import torch
input=[3,4,6,5,7,
       2,4,6,8,2,
       1,6,7,8,4,
       9,7,4,6,2,
       3,7,5,4,1]
input=torch.Tensor(input).view(1,1,5,5)#把输入变成(batch_size,channel,width,height)
conv_layer=torch.nn.Conv2d(1,1,kernel_size=3,padding=1,bias=False)
#构建卷积层,输入是1个通道,输出是一个通道,卷积核3*3,如果bias=True,卷积完之后会给每一个通道加上一个偏置量
#不需要加偏置量就bias=False,padding=1是当卷积核为3*3时,保证输出还是5*5
kernel=torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1,1,3,3)#构建卷积核(输出通道数,输入通道数,宽度,高度)
conv_layer.weight.data=kernel.data#把做出来的张量赋值给卷积层的权重.data,把卷积层的权重初始化
output=conv_layer(input)
print(output)

结果

tensor([[[[ 91., 168., 224., 215., 127.],
          [114., 211., 295., 262., 149.],
          [192., 259., 282., 214., 122.],
          [194., 251., 253., 169.,  86.],
          [ 96., 112., 110.,  68.,  31.]]]],

当步长stride=2

在这里插入图片描述

下采样

下采样用的比较多的是MaxPooling(最大池化层)
最大池化层是没有权重的
22的maxpooling默认stride=2
就是把图像分成2
2的一个组,在每个组里面找最大值
所以做maxpooling的时候只能把一个通道拿出来做maxpooling,通道之间不会去找最大值,所以在做最大池化(maxpooling)的时候,通道数量不会发生改变,但是如果用2*2的maxpooling,图像大小会缩成原来的一半
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200902170558863.png?x-oss-process=image/watermark,type_ZmFuZ3poZW代码实现

import torch
input=[3,4,5,6,
       2,4,6,8,
       1,6,7,8,
       9,7,4,6]
input=torch.Tensor(input).view(1,1,4,4)
maxpooling_layer=torch.nn.MaxPool2d(kernel_size=2)
#当kernel_size=2,maxpooling默认的步长也会是2
output=maxpooling_layer(input)
print(output)

结果

tensor([[[[4., 8.],
          [9., 8.]]]])

卷积神经网络实现MNIST

图中filter就是卷积核
在这里插入图片描述第一个最大池化做一个就行了,因为它没有权重,跟sigmoid和relu一样,是没有权重的,但是有权重的必须每一个层单独做一个实例

在这里插入图片描述代码(与上一讲的代码只是网络模型不一样)

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F  # 用Relu函数
import torch.optim as optim  # 优化器优化

batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
# transform:把图像转化成图像张量
train_dataset = datasets.MNIST(root='../data',
                               train=True,
                               download=True,
                               transform=transform)  # 训练数据集
train_loader = DataLoader(train_dataset,
                          shuffle=True,
                          batch_size=batch_size)
test_dataset = datasets.MNIST(root='../data',
                              train=False,
                              download=True,
                              transform=transform)
test_loader = DataLoader(test_dataset,
                         shuffle=False,
                         batch_size=batch_size)
#import torch
#import torch.nn.functional as F
class Net(torch.nn.Module):
    def __init__(self):
        super(Net,self).__init__()
        self.conv1=torch.nn.Conv2d(1,10,kernel_size=5)
        self.conv2=torch.nn.Conv2d(10,20,kernel_size=5)
        self.pooling=torch.nn.MaxPool2d(2)
        self.fc=torch.nn.Linear(320,10)
        
    def forward(self,x):
        #Flatten data from (n,1,28,28) to (n,784)
        batch_size=x.size(0)
        x=F.relu(self.pooling(self.conv1(x)))#先把输入做卷积,然后做池化,然后做relu
        x=F.relu(self.pooling(self.conv2(x)))
        x=x.view(batch_size,-1)#Flatten,变成想要的全连接网络需要的输入
        x=self.fc(x)#用全连接层做变换
        return x#因为要做交叉熵损失,最后一层不做激活
model=Net()
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
 

def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        optimizer.zero_grad()  # 优化器,输入之前清零
        # forward + backward + updat
        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        if batch_idx % 300 == 299:  # 每300轮输出一次
            print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0


def test():
    correct = 0  # 正确多少
    total = 0  # 总数多少
    with torch.no_grad():  # 测试不用算梯度
        for data in test_loader:  # 从test_loader拿数据
            images, labels = data
            outputs = model(images)  # 拿完数据做预测
            _, predicted = torch.max(outputs.data, dim=1)  # 沿着第一个维度找最大值的下标,返回值有两个,因为是10列嘛,返回值
            # 返回值一个是每一行的最大值,另一个是最大值的下标(每一个样本就是一行,每一行有10个量)(行是第0个维度,列是第1个维度)
            total += labels.size(0)  # 取size元组的第0个元素(N,1),
            correct += (predicted == labels).sum().item()  # 推测出来的分类与label是否相等,真就是1,假就是0,求完和之后把标量拿出来
    print('Accuracy on test set:%d %%' % (100 * correct / total))


# 训练
if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test() #训练一轮,测试一轮 

结果展示

Reloaded modules: __mp_main__
[1,  300] loss:0.606
[1,  600] loss:0.199
[1,  900] loss:0.145
Accuracy on test set:96 %
[2,  300] loss:0.111
[2,  600] loss:0.102
[2,  900] loss:0.089
Accuracy on test set:97 %
[3,  300] loss:0.077
[3,  600] loss:0.072
[3,  900] loss:0.074
Accuracy on test set:98 %
[4,  300] loss:0.064
[4,  600] loss:0.063
[4,  900] loss:0.063
Accuracy on test set:98 %
[5,  300] loss:0.057
[5,  600] loss:0.057
[5,  900] loss:0.051
Accuracy on test set:98 %
[6,  300] loss:0.048
[6,  600] loss:0.050
[6,  900] loss:0.054
Accuracy on test set:98 %
[7,  300] loss:0.044
[7,  600] loss:0.045
[7,  900] loss:0.046
Accuracy on test set:98 %
[8,  300] loss:0.044
[8,  600] loss:0.040
[8,  900] loss:0.043
Accuracy on test set:98 %
[9,  300] loss:0.039
[9,  600] loss:0.039
[9,  900] loss:0.039
Accuracy on test set:98 %
[10,  300] loss:0.037
[10,  600] loss:0.034
[10,  900] loss:0.037
Accuracy on test set:98 %

不难看出,相比PyTorch深度学习实践(九)多分类问题-MNIST数据集中全连接网络97%的准确率,卷积神经网络的准确率为98%,看似只上升了一个百分点,但是错误率由3%降到了2%,错误率降低了30%呀,可以对模型进行改造,追求更好的准确率

如果有GPU,怎么用显卡来计算

①把模型迁移到GPU

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 
model.to(device)

如果装的是支持cuda版本的pyTorch,available就是True,默认是cuda 0,只有cpu就是false
如果有多个显卡,不同的任务可以使用不同的显卡
model.to(device)把整个模型的参数,缓存,所有的模块都放到cuda里面,转成cuda tensor
在这里插入图片描述计算的时候要把用来计算的张量也迁移到GPU,主要是输入和对应的输出,把inputs和target都迁移到device上,注意迁移的device和模型的device要在同一块显卡上,比如把模型放在第0块显卡,数据放在第一块显卡,是没法工作的

inputs, target = inputs.to(device), target.to(device) 

在这里插入图片描述
测试也把输入输出放到显卡上
在这里插入图片描述

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyTorch深度学习实战中,可以使用卷神经网络来进行图像分类任务。在实战中,可以使用经典的卷神经网络模型,如VGG、ResNet、Inception和DenseNet等。这些模型都是在深度学习的发展过程中出现的经典模型,对深度学习的学术研究和工业生产都起到了巨大的促进作用。初学者可以通过阅读论文和实现代码来全面了解这些模型。例如,可以使用PyTorch中的torchvision.models模块来加载预训练的卷神经网络模型,如VGG-16、VGG-19和ResNet等\[1\]。其中,VGG-16和VGG-19是由卷层、池化层和全连接层等不同组合构成的经典卷神经网络模型\[1\]。而ResNet是一种使用残差单元连接而成的卷神经网络模型,通过跨层的短接来突出微小的变化,使得网络对误差更加敏感,并解决了网络退化现象,具有良好的学习效果\[2\]\[3\]。因此,在PyTorch深度学习实战中,可以选择合适的卷神经网络模型来进行图像分类任务。 #### 引用[.reference_title] - *1* *2* *3* [PyTorch深度学习实战 | 典型卷神经网络](https://blog.csdn.net/qq_41640218/article/details/129832298)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值