【第十五周】PyTorch深度学习实践2

news2024/11/26 18:49:12

目录

  • 摘要
  • Abstract
  • 1.多分类问题
    • 1.1.Softmax
    • 1.2.维度问题
    • 1.3.NLLLoss v.s. CrossEntropy
    • 1.4.代码实践
      • 1.4.1.导入相应的包
      • 1.4.2.准备数据集
      • 1.4.3.模型设计
      • 1.4.4.构造损失和优化器
      • 1.4.5.模型训练
  • 2.卷积神经网络基础篇
    • 2.1.代码实践
      • 2.1.1.导入相应的包:
      • 2.1.2.准备数据集:
      • 2.1.3.模型设计
      • 2.1.4.构造损失和优化器
      • 2.1.5.模型训练
  • 总结

摘要

本周继续对 PyTorch 进行进一步学习,重点理解了张量的维度变化,在上一周的基础上更加深入地学习了 PyTorch 中各个模块的作用,加深了对神经网络构造流程的印象。同时对比了 NLLLoss 和 CrossEntropy 的作用,理解了为什么神经网络使用 CrossEntropy 作为损失函数时在网络的最后一层不做激活。对于卷积神经网络,深刻理解了经过卷积、池化、全连接之后各个张量的维度变化。

Abstract

This week, I continued to further study PyTorch, focusing on understanding the changes in tensor dimensions. Building upon last week’s foundation, I delved deeper into the roles of various modules in PyTorch, reinforcing my understanding of the neural network construction process. Additionally, I compared the functions of NLLLoss and CrossEntropy, and understood why neural networks use CrossEntropy as the loss function without applying an activation function in the final layer. For convolutional neural networks, I gained a deep understanding of the changes in tensor dimensions after convolution, pooling, and fully connected layers.

1.多分类问题

在这里插入图片描述

MNIST 数据集是一个非常著名且广泛使用的数据集,主要用于训练各种机器学习模型,尤其是在手写数字识别任务上。MNIST 数据集包含 70,000 张 28x28 像素的灰度图像,这些图像是手写的数字 0 到 9。数据集被划分为两部分:一个包含 60,000张图像的训练集,用于训练模型;另一个包含 10,000 张图像的测试集,用于评估模型的性能。

在这里插入图片描述

以手写数字识别为例,多分类问题中输出的应该是一个概率分布

在这里插入图片描述

输出每一个类别都需要满足概率值大于等于0,并且所有输出概率之和应为1。为了满足这个要求,我们最后一层应该要经过一个 softmax 函数处理。

1.1.Softmax

在这里插入图片描述

在这里插入图片描述

注意:
(1)PyTorch 中提供的交叉熵损失函数已经包括了 Softmax 函数,所以我们在神经网络最后一层不会再加入 Softmax 函数。
(2)torch.LongTensor 在 PyTorch 1.6 版本之后被弃用,推荐使用 torch.tensor 并指定 dtype=torch.long 来创建相同类型的张量。

代码测试

import torch
criterion = torch.nn.CrossEntropyLoss()
Y = torch.tensor([2, 0, 1])
Y_pred1 = torch.tensor([[0.1, 0.2, 0.9],
                        [1.1, 0.1, 0.2],
                        [0.2, 2.1, 0.1]])
Y_pred2 = torch.tensor([[0.8, 0.2, 0.3],
                        [0.2, 0.3, 0.5],
                        [0.2, 0.2, 0.5]])

l1 = criterion(Y_pred1, Y) # 括号内参数不可颠倒,否则维度对应不上。
l2 = criterion(Y_pred2, Y)
print(l1)
print(l2)

结果如下:

在这里插入图片描述

单从预测出来的数据上看也能发现 Y_pred1 更加接近 label 。

1.2.维度问题

Y = torch.tensor([2, 0, 1])

对于给定的目标张量的维度代表着 batch_size 的大小,也就是一个批次包含的样本数量。如上说明一个 batch 接受三个样本。因此输入张量的第一个维度要于 batch_size 相等。

Y_pred1 = torch.tensor([[0.1, 0.2, 0.9],
                        [1.1, 0.1, 0.2],
                        [0.2, 2.1, 0.1]])

对于输入张量,第一个维度代表着 batch_size,第二个维度就代表着分类的类别数量。

我们可以拓展到多标签分类任务。在多标签分类任务中,每个样本可以属于多个类别。

假设目标张量如下:

Y = torch.tensor([[1, 0, 2, 2, 0],
                  [1, 1, 0, 1, 2],
                  [1, 1, 0, 0, 2]])

第一个维度代表 batch_size,说明一个批次有三个样本。第二个维度代表这标签长度,即一个样本有多少个标签。

假设输入张量如下:

X = tensor([[[ 1.2481,  0.3071,  0.5614,  0.5019,  0.3484],
             [-0.0334, -0.7007, -0.8127, -0.5478,  0.7969],
             [-0.6703,  1.0289, -0.3442, -0.1401, -1.1288]],

            [[ 0.1026,  1.8155, -1.1236, -0.3992,  0.0606],
             [-2.4911, -0.4922,  1.3564,  0.8053, -0.6478],
             [-1.7029, -0.2763, -0.2075, -0.1883, -1.3610]],

            [[ 0.8464,  0.0158, -0.4769,  1.3246,  1.9271],
             [ 0.3562,  0.3566,  0.8755, -2.8509, -0.4352],
             [-0.4055,  0.5393, -1.1080, -0.7616,  0.4028]]])

第一个维度代表 batch_size,第二个维度代表分类类别,第三个维度代表标签长度。

请添加图片描述
红框内为第一个样本的数据,对输入张量进行 softmax 处理时,我们会以绿框(一列)为一个整体来处理,也就是说通过 softmax 处理产生相对应的概率值后会使得输入张量的每一列相加都为1(而不是每一行)。注意体会这个例子中各个维度的关系。

具体可以参考这个:详解pytorch中nn.CrossEntropyloss函数计算过程

1.3.NLLLoss v.s. CrossEntropy

PyTorch 中还提供了另一个用于分类任务的损失函数 NLLLoss,那么这个损失函数跟 CrossEntropy 又有什么不同呢?

在这里插入图片描述
综上可知,CrossEntropy 等价于 log_softmax + NLLLoss。

参考来源:NLLLoss的具体计算

1.4.代码实践

1.4.1.导入相应的包

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

1.4.2.准备数据集

# prepare dataset
batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(), 
    transforms.Normalize((0.1307,), (0.3081,))
    ])  # 归一化,均值和方差

train_dataset = datasets.MNIST(root='../dataset/mnist/', 
                               train=True, 
                               download=True, 
                               transform=transform)
                               
train_loader = DataLoader(train_dataset, 
                          shuffle=True, 
                          batch_size=batch_size)
                          
test_dataset = datasets.MNIST(root='../dataset/mnist/', 
                              train=False, 
                              download=True, 
                              transform=transform)
                              
test_loader = DataLoader(test_dataset, 
                         shuffle=False, 
                         batch_size=batch_size)

说明:

  1. transforms.Compose() 是 PyTorch提供的一个简单实用的工具。它允许将多个图像变换操作组成一个序列,从而简化图像预处理流水线。transforms.Compose()
    接受一个变换列表,并返回一个新的、组合后的变换。 这特别适合在处理图像时,需要链式应用多个变换操作的场景。
  2. ToTensor() 将 shape 为 (H, W, C) 的 nump.ndarray 或 img 转为 shape 为 (C, H, W) 的 tensor ,其将每一个数值归一化到 [0,1]。
    transforms.Normalize 后面的0.1307和0.3081是对 MINIST 数据集求解出来的均值和方差。

1.4.3.模型设计

在这里插入图片描述

网络结构如上所示,由于线性层的计算需要接受一个向量,所以我们需要把一张图片转换成一个向量进行计算。而对于一个 batch 的多张图片而言,我们可以把这批图片变换成一个二维矩阵,其中二维矩阵的行数代表图片的数量。然后再把这个二维矩阵送入线性层,再利用矩阵乘法 Y = X Y + b Y=XY + b Y=XY+b 便可以一次求得多张图片的线性变换。我们可以使用 x.view(-1, 784) 将维度为 N×1×28×28 的图像转换成 N×784 的二维矩阵。其中,-1表示自动计算行数,784表示一张图片的像素数量。

代码如下:

# design model using class

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.l1 = torch.nn.Linear(784, 512)
        self.l2 = torch.nn.Linear(512, 256)
        self.l3 = torch.nn.Linear(256, 128)
        self.l4 = torch.nn.Linear(128, 64)
        self.l5 = torch.nn.Linear(64, 10)

    def forward(self, x):
        x = x.view(-1, 784)  # -1其实就是自动获取mini_batch
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        x = F.relu(self.l4(x))
        return self.l5(x)  # 最后一层不做激活,不进行非线性变换


model = Net()

1.4.4.构造损失和优化器

criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

1.4.5.模型训练

为了便于灵活地调整,我们将模型的训练封装成一个函数。

def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        # 获得一个批次的数据和标签
        inputs, target = data
        # 优化器在优化前要清0
        optimizer.zero_grad()
        # 获得模型预测结果(64, 10)
        outputs = model(inputs)
        # 交叉熵代价函数outputs(64,10),target(64)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()
        
        # loss 也是一个张量,如果不使用 loss.item() 直接用 loss那么runing_loss也会是一个张量并且保留计算图信息
        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0

说明:

  1. enumerate(train_loader, 0) 会从 train_loader 里返回索引和数据,后面那个 0 代表索引的起始值。
  2. torch.nn.Module 类有一个特殊的方法 _call_, __call__方法内部会调用 forward 方法。
  3. model 是类 Net 的实例化,而 Net 又继承自 torch.nn.Module ,所以 model 是一个可调入对象,可以实现类似函数一样的操作。
  4. 当你在 forward() 方法中执行各种操作时,PyTorch 会自动记录这些操作及其依赖关系,构建一个计算图。一旦计算图构建完成,通过调用 loss.backward(),PyTorch 会沿着计算图从输出节点反向传播,计算每个参数的梯度。
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)  # dim = 1 列是第0个维度,行是第1个维度
            total += labels.size(0)
            correct += (predicted == labels).sum().item()  # 张量之间的比较运算
    print('accuracy on test set: %d %% ' % (100 * correct / total))

说明:

  1. 测试集中不需要求梯度,所以我们可以指定 torch.no_grad()。

  2. torch.max(outputs.data, dim=1) 返回张量第一个维度的最大值以及索引,dim=1 意味着沿着列数的方向检索,而不是沿着某一列。

  3. “_”表示占位符,意思就是我们不需要这部分的信息。

  4. (predicted == labels) 会返回 True 或 False,而(predicted == labels).sum() 会计算布尔张量中 True 的数量,即预测正确的样本数量。

  5. test 是 pytest 测试框架的测试函数标识符前缀,所以 test() 函数有可能会报错,解决办法是将 test() 改名或者在 PyCharm 里将测试框架从 pytest 改为 unittest,具体办法看这个pycharm切换pytest与unittest运行环境。

结果如下:
在这里插入图片描述

2.卷积神经网络基础篇

在这里插入图片描述

在一个卷积神经网络中,前面的部分完成的是特征提取任务,后面部分完成的是分类任务。

在这里插入图片描述

我们观察以上张量的维度,可以发现两个特点:

  1. 输入张量的 channel 大小和卷积核的 channel 大小相等。
  2. 卷积核的数量和输出张量的 channel 大小相等。

在这里插入图片描述
因此,对于确定维度的输入张量和输出张量,卷积核的维度实际上是输出张量的通道数×输入张量的通道数×W×H

在这里插入图片描述

2.1.代码实践

2.1.1.导入相应的包:

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

2.1.2.准备数据集:

# prepare dataset
batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(), 
    transforms.Normalize((0.1307,), (0.3081,))
    ])  # 归一化,均值和方差

train_dataset = datasets.MNIST(root='../dataset/mnist/', 
                               train=True, 
                               download=True, 
                               transform=transform)
                               
train_loader = DataLoader(train_dataset, 
                          shuffle=True, 
                          batch_size=batch_size)
                          
test_dataset = datasets.MNIST(root='../dataset/mnist/', 
                              train=False, 
                              download=True, 
                              transform=transform)
                              
test_loader = DataLoader(test_dataset, 
                         shuffle=False, 
                         batch_size=batch_size)

2.1.3.模型设计

在这里插入图片描述
卷积神经网络中最重要的是搞清楚张量中各种维度的变化。

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)))
        x = F.relu(self.pooling(self.conv2(x)))
        x = x.view(batch_size, -1)  # -1 此处自动算出的是320
        x = self.fc(x)

        return x


model = Net()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 定义设备
model.to(device) # 将在 CPU 上构建的模型迁移到 GPU 上

2.1.4.构造损失和优化器

# construct loss and optimizer
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)

2.1.5.模型训练

def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        inputs, target = inputs.to(device), target.to(device)
        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        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
            images, labels = images.to(device), labels.to(device)
            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))
    return correct / total


if __name__ == '__main__':
    epoch_list = []
    acc_list = []

    for epoch in range(10):
        train(epoch)
        acc = test()
        epoch_list.append(epoch)
        acc_list.append(acc)

结果如下:
在这里插入图片描述

总结

卷积神经网络(Convolutional Neural Network, CNN)是一种深度学习模型,特别擅长处理具有网格状拓扑结构的数据,如图像。这类网络的设计灵感来源于生物视觉皮层的组织方式,尤其是哺乳动物的初级视觉皮层中神经元的感受野特性。CNNs 在计算机视觉任务中表现出色,包括但不限于图像分类、目标检测、语义分割等。学习卷积神经网络最重要的一点在于搞清楚从输入到输出环节的张量维度变化,弄明白了这一点才算真正理解了卷积神经网络的原理。

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

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

相关文章

我谈巴特沃斯滤波器

目录 写在前面的内容我谈巴特沃斯滤波器巴特沃斯滤波器的幅频响应频率变换巴特沃斯各种滤波器例子 写在前面的内容 先看看冈萨雷斯对巴特沃斯滤波器的介绍。 低通 高通 带阻 带通 第一个问题,截止频率处的增益。 0.5的增益是不是陡度小了?巴特沃…

ai智能论文生成系统有用吗?分享5款ai文献综述自动生成器

近年来,人工智能(AI)技术在学术写作领域的应用越来越广泛,尤其是在文献综述的自动生成方面。AI智能论文生成系统通过深度学习和自然语言处理技术,能够帮助研究人员快速生成高质量的文献综述,从而提高写作效…

深度扩展AntSK,让.NET Aspire助力您的AI项目

引言 在现今飞速发展的技术世界中,引用最新的工具和框架来提升项目的性能和可管理性至关重要。作为一名开发者,我最近在自己的AI知识库项目AntSK中集成了.NET Aspire,这为我的项目注入了新的活力。如果你还不清楚什么是.NET Aspire&#xff0…

[单master节点k8s部署]32.ceph分布式存储(三)

基于ceph rbd生成pv 在集群中认证ceph 用下面代码生成ceph的secret .创建 ceph 的 secret,在 k8s 的控制节点操作: 回到 ceph 管理节点创建 pool 池: [rootmaster1-admin ~]# ceph osd pool create k8stest 56 pool k8stest created [rootm…

BERT论文解读及情感分类实战(论文复现)

BERT论文解读及情感分类实战(论文复现) 本文所涉及所有资源均在传知代码平台可获取 文章目录 BERT论文解读及情感分类实战(论文复现)简介BERT文章主要贡献BERT模型架构技术细节任务1 Masked LM(MLM)任务2 N…

【web安全】——常见框架漏洞

1.ThinkPHP框架漏洞 thinkphp是一个国内轻量级的开发框架,采用phpapache,在更新迭代中,thinkphp也经常爆出各种漏洞,thinkphp一般有thinkphp2、thinkphp3、thinkphp5、thinkphp6版本,前两个版本已经停止更新&#xff…

【详细教程】如何使用YOLOv11进行图像与视频的目标检测

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推…

m4a怎么转换成mp3?音频转换MP3只需要这6个小工具!

m4a怎么转换成mp3?M4A和MP3是两种常见的音频格式,M4A通常使用AAC(高级音频编码)进行压缩,提供更高的音质和更小的文件体积,特别适合在Apple设备上使用。而MP3则以其高压缩比和广泛的兼容性著称,…

TM1618数码管控制芯片使用共阳极数码管过程中的问题和解决办法

控制芯片的基本了解 相比于不用控制芯片的电路:这里带2根电源线和3个信号线,共使用了5根线,但可以控制4个8段数码管显示。若是电路直接控制4个8段数码管需要84113个接口,这对于MCU的珍贵引脚简直是浪费。 这里不会出现余晖效应也…

大花蔷薇T2T基因组-60

Multi-omics analyzes of Rosa gigantea illuminate tea scent biosynthesis and release mechanisms 多组学分析揭示了大花蔷薇茶香合成及释放机制 摘要 玫瑰是一种全球广泛栽培的重要观赏作物,用于香水生产。然而,由于缺乏茶玫瑰的参考基因组&#x…

鸿蒙开发(NEXT/API 12)【穿戴设备传感器获取】手机侧应用开发

手机侧应用可以通过Wear Engine获取穿戴设备上的传感器信息,并通过打开、关闭命令控制获取传感器数据。 使用传感器相关接口前,需要向手机侧用户申请获取对应权限的授权 传感器类型申请权限ECG、PPG、HR[HEALTH_SENSOR]人体传感器ACC、GYRO、MAG[MOTIO…

汇编DEBUG程序调用

工具 系统:Windows 11 应用:DOSBox 0.74-3 下载安装教程:本人写的《DOSBox下载安装(Windows系统 DOSBox 0.74-3)》 https://blog.csdn.net/just_do_it_sq/article/details/142715182?spm1001.2014.3001.5501 相关文…

C++ 算法学习——1.3 深度优先搜索

深度优先搜索:简单讲就是搜到某条路尽头,再掉头回溯搜其他的路。此中重点是尽头的判断,和对走过的路进行标记。 一般采用递归的写法,模板大致如下: DFS(node,visited):if node is in visited:returnadd node to visi…

通用mybatis-plus查询封装(QueryGenerator)

结果如下图所示 java类代码分别如下 1 package com.hdx.contractor.util.mybatis;import com.hdx.contractor.common.user.SecurityUser; import com.hdx.contractor.common.user.UserDetail; import com.hdx.contractor.util.query.oConvertUtils; import lombok.extern.slf…

OpenHarmony(鸿蒙南向开发)——轻量系统芯片移植案例(一)

往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~ 持续更新中…… 轻量带屏解决方案之恒玄芯片移植案例 本文章基于恒玄科技BES2600W…

【AI知识点】交叉验证(Cross-Validation)

交叉验证(Cross-Validation) 是机器学习中常用的一种模型评估方法,用于评估模型的性能和泛化能力。它通过在不同的训练集和验证集上多次训练和测试模型,从而有效地评估模型在未见数据上的表现,帮助防止模型的过拟合和欠…

【RTD MCAL 篇2】 K312 UART DMA

【RTD MCAL 篇2】 K312 UART DMA 一,文档简介二, 功能实现2.1 K312 MINIEVB硬件配置2.2 EB 配置2.2.1 Mcl module2.2.2 Mcu module2.2.3 Platform module2.2.4 Port module2.2.5 Uart module2.2.6 Rm module 2.3 main code 三,测试结果 一&am…

Clio——麻省理工学院增强机器人场景理解算法

概述 机器人感知长期以来一直受到现实世界环境复杂性的挑战,通常需要固定设置和预定义对象。麻省理工学院的工程师 已经开发了Clio这项突破性的系统可以让机器人直观地理解并优先考虑周围环境中的相关元素,从而提高其高效执行任务的能力。 了解对更智…

【Python】Marmir 使用指南:Python 驱动的电子表格生成器

Marmir 是一个由 Python 驱动的电子表格生成工具,专门用于将 Python 数据结构(如字典、列表等)转换为电子表格文件(如 Excel)。Marmir 的设计目标是提供比传统电子表格库(如 xlwt)更强大和灵活的…

ctf.bugku-备份是个好习惯

访问页面得到字符串 这串字符串是重复的; d41d8cd98f00b204e9800998ecf8427e 从前端、源码上看,除了这段字符串,没有其他信息;尝试解密,长度32位;各种解密方式试试; MD5免费在线解密破解_MD5在…