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

b站刘二大人《PyTorch深度学习实践》课程第十讲卷积神经网络(基础篇)笔记与代码:https://www.bilibili.com/video/BV1Y7411d7Ys?p=10&vd_source=b17f113d28933824d753a0915d5e3a90


上一讲中MNIST数据集的例子采用的是全连接神经网络(Fully Connected Neural Nerwork)

image-20230702145633991
  • 所谓的全连接就是网络中使用的全都是线性层,每一个输入节点都要参与到下一层任意一个输出节点的计算上

Convolutional Neural Network

  • 卷积神经网络可保存图像原本的空间结构,从而保留原始的空间信息

    image-20230702150652516
  • 下采样(Subsampling)操作不改变通道数,宽高会减小

  • 卷积 + 下采样 -> 特征提取;全连接层 -> 分类


image-20230702153933038
  • RGB是三个通道
  • patch取了3个通道
  • 图像原点在左上角
  • 卷积之后通道、宽和高都可变

卷积的运算过程:

  • 例子:输入是一个单通道的1 * 5 * 5的图像,卷积核是 3 * 3的

    • 卷积核现在输入中画出一个3*3的区域,然后做数乘,将结果输出

      image-20230702154325397
    • 然后将块往右移一格,输入与卷积核做数乘求和

      image-20230702154533287 image-20230702154554080 image-20230702154705107
    • 以此往复,直至遍历完整个图像

  • 上述例子是单通道的,但实际中常见到的是多通道的

    • 以3通道为例子,每个通道都要配一个卷积核

      image-20230702155034920
    • 每个通道和一个核做卷积,然后将卷积的结果进行相加

      image-20230702155136540 image-20230702155321775 image-20230702155340907
  • N通道:

    image-20230702155653258
    • N个通道,M个输出:
      • 一个卷积核得到一个通道,那么M个卷积核就能得到M个输出,然后再将M个输出拼接起来
    image-20230702155938637
  • 每一个卷积核的通道数和输入通道数一致,卷积核的总个数和输出通道数一致

    image-20230702160152912

卷积层代码:

image-20230702161029819
import torch
in_channels, out_channels = 5, 10   # 输入通道n,输出通道m
width, height = 100, 100            # 图像的宽和高
kernel_size = 3                     # 卷积核大小
batch_size = 1                      # pytorch中所有的输入数据必须是小批量的# 生成输入数据,这里是随便取一个随机数
input = torch.randn(batch_size,in_channels,width,height)# 创建卷积层
conv_layer = torch.nn.Conv2d(in_channels,out_channels,kernel_size=kernel_size)# 得到卷积输出
output = conv_layer(input)print(input.shape)
print(output.shape)
print(conv_layer.weight.shape)
image-20230702161305065

卷积层中的几个重要参数:

  • 填充padding

    • 想要输出的图像宽高保持不变,那么可以对输入进行填充0

    • 例如padding = 1

      image-20230702162040306 image-20230702162017969
    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,C,W,H# 创建卷积层
    conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False)# 创建卷积核
    # view用来改变形状,四个参数分别对应输出通道数,输入通道数,宽和高
    kernel = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]).view(1, 1, 3, 3)# 将卷积核数据赋给卷积层的权重,对卷积层的权重进行初始化
    conv_layer.weight.data = kernel.dataoutput = conv_layer(input)print(output)
    
    image-20230702163935243 image-20230702163952860
  • 步长stride

    • 遍历步长

      • 例如stride=2,第一次中心在第二行第二列的4,下一次的中心就直接跳到第二行第四列的8
      image-20230702164313997
    • 可以有效降低图像的宽度和高度

      image-20230702164438962
    '''
    和前面padding的代码相比,仅在conv_layer = torch.nn.Conv2d()中将padding换成stride
    '''
    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,C,W,H# 创建卷积层
    conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, stride=2, bias=False)# 创建卷积核
    # view用来改变形状,四个参数分别对应输出通道数,输入通道数,宽和高
    kernel = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]).view(1, 1, 3, 3)# 将卷积核数据赋给卷积层的权重,对卷积层的权重进行初始化
    conv_layer.weight.data = kernel.dataoutput = conv_layer(input)print(output)
    
    image-20230702164726025

下采样 —— 最大池化层(Max Pooling Layer)

image-20230702165319786

例如使用一个2*2的最大池化层,它默认的stride=2,图像是4*4的

这个池化层会将图像按照2*2一组来分,然后将每组中的最大值提取出来拼成一个2*2的输出

操作是在同一个通道内,通道之间不会,因此通道数不会变

import torch# 输入图像
input = [3, 4, 6, 5,2, 4, 6, 8,1, 6, 7, 8,9, 7, 4, 6]
# 将输入转成张量
input = torch.Tensor(input).view(1, 1, 4, 4)    # 四个参数分别对应batch_size,C,W,Hmaxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)    # kernel_size被设成2,那么stride会默认为2output = maxpooling_layer(input)print(output)
image-20230702170115683

实现一个简单的CNN来处理MNIST数据集:

image-20230702171655520
  • 第一个卷积层的卷积核是5*5的,输入通道为1,输出通道为10
    • 由此可知输出的通道为10,图像大小变成24*24
      • 卷积核是5,那么中心就在第三行第三列,这意味着输入图像少了两圈,那就是要减掉4,即24
    • 因此参数为(batch_size,10,24,24)
  • 上一步输出做一个最大池化,池化层为2*2的
    • 最大池化层是2*2的,那么就是对图像按照2*2一组进行划分然后取每组的最大值出来进行拼接
    • 上一步输出的图像是24*24的,因此经过池化后就变成了12*12的
    • 通道数不影响,即保持不变
    • 即(batch_size,10,12,12)
  • 接下去再加第二个卷积层,卷积核是5*5的,输入通道为10(和池化层输出通道保持一样),输出通道为20
    • 同理得(batch_size,20,8,8)
  • 然后再做一个池化层,2*2的
    • (batch_size,20,4,4)
    • 这一步最大池化处理后一共有320个数据(20*4*4)
  • 最后经过一个全连接层将上一步池化层输出的数据映射成一个向量
image-20230702171959946
  • 添加了ReLU做非线性激活
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, 320)batch_size = x.size(0)x = F.relu(self.pooling(self.conv1(x)))     # 先做卷积,再做池化,最后ReLUx = F.relu(self.pooling(self.conv2(x)))     # 第二次x = x.view(batch_size, -1)                  # 用view将x转成全连接网络所需要的输入形式x = self.fc(x)return xmodel = Net()

完整的代码:

import torch# 构造Dataloader
from torchvision import transforms  # 用于对图像进行一些处理
from torchvision import datasets
from torch.utils.data import DataLoaderimport torch.nn.functional as F     # 使用更流行的激活函数Relu
import torch.optim as optim         # 构造优化器
import matplotlib.pyplot as pltbatch_size = 64# 存储训练轮数以及对应的accuracy用于绘图
epoch_list = []
acc_list = []# Compose的实例化
transform = transforms.Compose([transforms.ToTensor(),  # 将PIL图像转成Tensortransforms.Normalize((0.1307, ), (0.3081, ))  # 归一化。0.1307是均值,0.3081是标准差
])# 训练集
train_dataset = datasets.MNIST(root='D:/pycharm_workspace/Liuer_lecturer/dataset/mnist',train=True,download=True,transform=transform)  # 读取到某个数据后就直接进行transform处理
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)
# 测试集
test_dataset = datasets.MNIST(root='D:/pycharm_workspace/Liuer_lecturer/dataset/mnist',train=False,download=True,transform=transform)
test_loader = DataLoader(train_dataset,shuffle=False,batch_size=batch_size)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, 320)batch_size = x.size(0)x = F.relu(self.pooling(self.conv1(x)))     # 先做卷积,再做池化,最后ReLUx = F.relu(self.pooling(self.conv2(x)))     # 第二次x = x.view(batch_size, -1)                  # 用view将x转成全连接网络所需要的输入形式x = self.fc(x)return xmodel = Net()criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)  # 带冲量的梯度下降# 一轮训练
def train(epoch):running_loss = 0.0for batch_idx, data in enumerate(train_loader, 0):inputs, target = data  # inputs输入x,target输出yoptimizer.zero_grad()# forward + backward + updateoutputs = model(inputs)loss = criterion(outputs, target)loss.backward()optimizer.step()running_loss += loss.item()  # loss累加# 每300轮输出一次,减少计算成本if batch_idx % 300 == 299:print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss/300))running_loss = 0.0# 测试函数
def test():correct = 0total = 0with torch.no_grad():   # 让后续的代码不计算梯度for data in test_loader:images, labels = dataoutputs = model(images)_, predicted = torch.max(outputs.data, dim=1)total += labels.size(0)correct += (predicted == labels).sum().item()print('Accuracy on test set: %d %%' % (100 * correct / total))acc_list.append(correct / total)if __name__ == '__main__':for epoch in range(10):train(epoch)test()epoch_list.append(epoch)# loss曲线绘制,x轴是epoch,y轴是loss值
plt.plot(epoch_list, acc_list)
plt.ylabel('Accuracy')
plt.xlabel('epoch')
plt.show()
image-20230702180120452 image-20230702180150297 image-20230702180211252

如何使用GPU进行训练:

  • Move Model to GPU
image-20230702174634740
# “cuda:0”表示使用第一块GPU
# if - else表达式:
# 如果当前的cuda可用那么torch.cuda.is_available()=true,则使用gpu,不可用即false,则使用cpu
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 将模型迁移到GPU上
model.to(device)
  • Move Tensor to GPU

    • 将用于计算的张量迁移到GPU,注意要在同一块显卡

    • 训练的时候:

      image-20230702174820581
    • 测试的时候:

      image-20230702174918888
  • 课程中经过10轮训练后准确率从97%提升到98%,从错误率的角度来看是从3%降到了2%,即降低了三分之一

image-20230702175535563

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/5361.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ModaHub魔搭社区:向量数据库Milvus产品问题(三)

目录 Milvus 的数据落盘逻辑是怎样的? Mishards 推荐的配置是什么? Mishards 支持 RESTful API 吗? 什么是归一化?Milvus 中为什么有时候需要归一化? 为什么欧氏距离和内积在计算向量相似度时的结果不一致&#x…

算法与数据结构(六)

一、图 一、临接表 表示方法如下: 带权值的无向图的构建: #define MaxInt 32767 // 极大值 #define MVNum 100 // 最大定点数 typedef int ArcType; // 边的权值类型 typedef char VerTexType; // 顶点数据类型//弧(边)的结点结构 st…

当金融风控遇上人工智能,众安金融的实时特征平台实践

导读:随着企业数字化转型升级,线上业务呈现多场景、多渠道、多元化的特征。数据要素价值的挖掘可谓分秒必争,业务也对数据的时效性和灵活性提出了更高的要求。在庞大分散、高并发的数据来源背景下,数据的实时处理能力成为企业提升…

Maven中依赖使用范围

IDEA中help中show Log in Explorer可以查看idea日志 依赖使用范围 构建包含的流程:编译 ,测试 ,运行 ,打包 ,安装 ,部署 comile test package install deploy 使用标签 1:compile 缺省值 伴随者…

VRP基础操作

目录 一、华为VRP 1.1、VRP介绍 1.2、设备管理接口 1.3、Console口登录 1.4、参数配置 二、华为VRP命令行基础 2.1、真机设备初始化启动 2.2、命令行视图 2.3、命令行功能 2.4、命令行在线帮助 2.5、配置系统时钟 2.6、配置标题消息 2.7、命令等级 2.8、用户界面…

突破性5G NTN技术,美格智能携手高通发布卫星物联网连接方案

通信技术的快速发展,使得万物互联成为现实,物联网深刻影响我们的生活方式。目前,全球物联网连接主要由WiFi、蓝牙和蜂窝网络等几类技术支撑。数据显示,蜂窝基站的陆地覆盖率约为20%,而海洋覆盖率则不到5%。 这意味着陆…

Docker数据卷与容器的挂载

什么是Docker数据卷: 数据卷(Volumes)是宿主机中的一个目录或文件,当容器目录和数据卷目录绑定后,对方的修改会立即同步。一个数据卷可以被多个容器同时挂载,一个容器也可以被挂载多个数据卷。简单来说数据卷本质其实是…

FPGA的软核、硬核、固核

“核” 现在的FPGA设计,规模巨大而且功能复杂,因此设计的每一个部分都从头开始是不切实际的。一种解决的办法是:对于较为通用的部分可以重用现有的功能模块,而把主要的时间和资源用在设计中的那些全新的、独特的部分。这就像是你在…

20kV高精度可调高压稳压测试电源的学习与使用

一:应用范围 A: 二极管反向耐压测试 B: 二极管反向漏电流测试 C: 高压电容耐压测试 D: 玻璃釉电阻非线性性能测试 E:氙灯击穿电压测试 F: 材料耐压测试 二、特点 高精度恒流恒压高压输出源 它拥有0~20kV的电压输出能力, 0.005%的电压分辨率精度, 0.1uA的电 …

mysql——存储过程

目录 存储过程存储过程的优点创建存储过程调用存储过程查看存储过程查看存储过程的详细信息查看存储过程的属性 存储过程的参数删除存储过程存储过程控制语句 存储过程 存储过程是一组为了完成特定功能的SQL语句集合存储过程在使用过程中是将常用或者复杂的工作预先使用SQL语句…

Android通过连接USB读写SD卡(libaums方案)

Android通过连接USB读写SD卡 最近有一个需求是要求通过Usb扩展读取到SD卡的内容。可以从Usb存储设备拷贝文件到内置卡,也可以从内置卡文件拷贝到Usb存储。 1. 相关的引入包 implementation androidx.core:core-ktx:1.7.0implementation androidx.appcompat:appcompa…

02-基础入门-数据包拓展

基础入门-数据包拓展 基础入门-数据包拓展1、http/https数据包(1)HTTP协议是什么?(2)HTTP原理(3)HTTP特点(4)URI和URL的区别(5)HTTP报文组成&…