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

news2024/11/15 19:48:29

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.data
    
    output = 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.data
    
    output = 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,H

maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)    # kernel_size被设成2,那么stride会默认为2

output = 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)))     # 先做卷积,再做池化,最后ReLU
        x = F.relu(self.pooling(self.conv2(x)))     # 第二次
        x = x.view(batch_size, -1)                  # 用view将x转成全连接网络所需要的输入形式
        x = self.fc(x)
        return x

model = Net()

完整的代码:

import torch

# 构造Dataloader
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         # 构造优化器
import matplotlib.pyplot as plt


batch_size = 64

# 存储训练轮数以及对应的accuracy用于绘图
epoch_list = []
acc_list = []

# Compose的实例化
transform = transforms.Compose([
    transforms.ToTensor(),  # 将PIL图像转成Tensor
    transforms.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)))     # 先做卷积,再做池化,最后ReLU
        x = F.relu(self.pooling(self.conv2(x)))     # 第二次
        x = x.view(batch_size, -1)                  # 用view将x转成全连接网络所需要的输入形式
        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  # inputs输入x,target输出y
        optimizer.zero_grad()

        # forward + backward + update
        outputs = 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 = 0
    total = 0
    with torch.no_grad():   # 让后续的代码不计算梯度
        for data in test_loader:
            images, labels = data
            outputs = 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.coloradmin.cn/o/709941.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自然语言处理从入门到应用——预训练模型总览:两大任务类型

分类目录:《自然语言处理从入门到应用》总目录 从大量无标注数据中进行预训练使许多自然语言处理任务获得显著的性能提升。总的来看,预训练模型的优势包括: 在庞大的无标注数据上进行预训练可以获取更通用的语言表示,并有利于下游…

python语法(高阶)-多线程编程

""" 演示多线程编程的使用 """ import time import threadingdef sing(msg):while True:print(msg)time.sleep(1)return Nonedef dance(msg):while True:print(msg)time.sleep(1)return Noneif __name__ __main__:# 创建一个唱歌的线程&#xf…

后台管理系统的权限(vue如何实现后台管理系统的权限,react如何实现后台管理系统的权限)

一、权限的解释 一般来说,在后台管理系统里肯定会使用到权限,权限一般分为功能级权限和数据级权限 1、功能级权限 1)、页面级权限(菜单): 不同的用户(角色)登录到管理系统后&#…

mysql load data infile 报错 1290 处理方法

mysql load data infile 命令导入数据报错"16:06:13 load data infile “/var/lib/mysql/test/employee.csv” into table emp fields terminated by ‘,’ ignore 1 lines Error Code: 1290. The MySQL server is running with the --secure-file-priv option so it cann…

Linux应用层开发--多线程进程编程

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言一、linux开发的方向二、Linux环境特点介绍Linux环境基本构成 三、进程与线程1、进程的概念2、进程的状态3、线程的概念4、线…

leetcode 559. N 叉树的最大深度

2023.7.2 这道题还是使用层序遍历&#xff0c;在N叉树的层序遍历的基础上增加一个求深度的操作即可。下面上代码&#xff1a; class Solution { public:int maxDepth(Node* root) {int depth 0;queue<Node*> que;if(root nullptr) return 0;que.push(root);while(!que…

json 压缩算法详解

概要 无论使用何种编程语言&#xff0c;json格式的数据已被广泛应用&#xff0c;不论是数据的传输还是存储&#xff0c;在很多应用场景下&#xff0c;你可能想进一步地压缩JSON字符串的长度&#xff0c;以提升传输效率&#xff0c;如果你使用的是nosql数据库&#xff0c;你可能…

2012年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&…

记一次tomcat版本升级导致的现网问题

前言 最近公司项目做安全漏洞审查&#xff0c;把一批服务的fastjson,tomcat,log4j版本做升级&#xff0c;那天上线了50个服务&#xff0c;所有服务上线之后&#xff0c;现网有客服反馈录音笔下单异常。查询了现网日志&#xff0c;发现适配服务有异常信息&#xff0c;报错信息如…

闲人闲谈PS之四十二——顾问的“禁忌之地”—制造能力计划

惯例闲话&#xff1a;上个月有幸成为乐老师乐谈IT系列培训课程的讲师&#xff0c;分享主题是&#xff0c;PS在装备制造和工程行业的应用。虽然培训规模不是很大&#xff0c;但是闲人很有信心&#xff0c;至少在小范围之内&#xff0c;参与培训的听友人来说&#xff0c;PS一直以…

什么条件下会出现死锁,如何避免?

文章目录 一、什么是死锁二、产生死锁的原因&#xff1a;三、如何避免死锁&#xff1a; 一、什么是死锁 死锁&#xff0c;简单来说就是两个或者两个以上的线程在执行过程中&#xff0c;去争夺同一个共享资源导致相互等待的现象。如果没有外部干预&#xff0c;线程会一直处于阻塞…

图像的算术操作

1.图像的加法 用途&#xff1a;图像的合成 Rain图片View图片 合成代码&#xff1a; import numpy as np import cv2 as cv import matplotlib.pyplot as pltrain cv.imread(rain.png) plt.imshow(rain[:, :, ::-1]) plt.show()view cv.imread(view.png) plt.imshow(view…

773. 滑动谜题

链接&#xff1a;773. 滑动谜题 题解&#xff1a;https://blog.csdn.net/INGNIGHT/article/details/131350054 滑动拼图 II class Solution { public:int slidingPuzzle(vector<vector<int>>& board) {// 异常判断if (board.size() < 0 || board[0].size…

怎么管理好一个团队?

一个成功的企业需要一个高效、有能力、积极的团队来支持其业务运营。管理一个团队需要领导者具备一定的技能和知识&#xff0c;怎么管理好一个团队对于许多企业领导者而言也是一项不小的挑战。对此&#xff0c;我想首先推荐一本非常优秀的团队书籍——《经理人参阅&#xff1a;…

js vuejs dagre-d3绘制流程图实用指南 有向图可视化

写在前面 之前有小伙伴问我如何使用 D3 在前端绘制流程图,今天在这里给安排上,与大家分享。 明确一点,只要你的数据计算能力足够强,使用原生D3绘制流程图绝对可以的,但是,为了让大家更容易上手,避免重复造轮子,给大家推荐一个专门绘制流程图的 D3 插件 dagre-d3。 首…

idea tomcat js 汉字乱码

Run/Debug Configuiations->VM options:-Dfile.encodingUTF-8

服务 第七章

目录 1.tomcat 核心组件 2.处理请求&#xff0c;内部数据流向 3.请求处理过程 4.主要目录说明 5.tomcat 优化 6.总结 1.tomcat 核心组件 2.处理请求&#xff0c;内部数据流向 3.请求处理过程 4.主要目录说明 5.tomcat 优化 6.总结 tomcat 属于轻量级应用服务器&#xf…

基于Tars高并发IM系统的设计与实现-基础篇1

基于Tars高并发IM系统的设计与实现–基础篇1 作者简介 兰怀玉 毕业于中央民族大学计算机专业 先后供职国内外多家公司软件研发设计岗位&#xff0c;有丰富的软件研发经验。 从事IM领域设计研发十余年&#xff0c;先后领衔多个IM通讯系统设计与研发发&#xff0c;拥有丰富的IM…

裂墙推荐!阿里大牛新产Java面试速成指南,主打就是躺着拿Ofeer

很多粉丝后台留言&#xff0c;Java程序员面临的竞争太激烈了…… 我自己也有实感&#xff0c;多年身处一线互联网公司&#xff0c;虽没有直面过求职跳槽的残酷&#xff0c;但经常担任技术面试考官&#xff0c;对程序员招聘市场的现状很清楚。导致现在激烈竞争的原因不外乎三方面…

移动端数据可视化设计

在做APP设计的时候&#xff0c;难免会遇到一些需要展示数据的场景。使用传统的表格和文档展示数据不仅难看&#xff0c;也影响用户理解数据的含义。而数据可视化设计能将数据以更加直观的方式展现出来&#xff0c;使数据更加客观、更有说服力。 在移动应用中&#xff0c;数据可…