深度学习之torchvision、多层感知器与激活函数


学习笔记

1 torchvision库与加载内置图片数据集

torchvision库是PyTorch中用来处理图像和视频的一个辅助库,提供了一些常用的数据集、模型、转换函数等。

torchvision库提供的内置数据集可用于测试、学习和创建基准模型,为了统一数据加载和处理代码,PyTorch提供了两个类用以处理数据加载,它们分别是torch.utils.data.Dataset类和torch.utils.data.DataLoader类,通过这两个类可使数据集加载和预处理代码与模型训练代码脱钩,从而获得更好的代码模块化和代码可读性。

torchvision加载的内置图片数据集均继承自torch.utils.data.Dataset类,因此可直接使用加载的内置数据集创建DataLoader。

PyTorch的内置图片数据集均在torchvision.datasets模块下,包含Caltech、CelebA、CIFAR、Cityscapes、COCO、Fashion-MNIST、ImageNet、MNIST等很多著名的数据集。其中MNIST数据集是手写数字数据集,这是一个很适合入门者学习使用的小型计算机视觉数据集,它包含0~9的手写数字图片和每一张图片对应的标签。

下面以此数据集为例学习如何加载使用内置图片数据集,加载内置图片数据集的代码如下:

import torchvision
from torchvision.transforms import ToTensor


train_ds = torchvision.datasets.MNIST('data/', train=True, transform=ToTensor(), download=True)
test_ds = torchvision.datasets.MNIST('data/', train=False, transform=ToTensor(), download=True)

上述代码中,首先导入了torchvision库,并从torchvision.transforms模块下导入ToTensor类。

torchvision.transforms模块包含了转换函数,使用它可以很方便地对加载的图像做各种变换。

在这里我们用到了ToTensor类,该类的主要作用有以下3点。

  • (1) 将输入转换为张量。

  • (2) 将读取图片的格式规范为(channel,height,width),这与我们以前经常遇到的图片格式可能有些区别,PyTorch中的图片格式一般是通道数(channel)在前,然后是高度(height)和宽度(width)。

  • (3) 将图片像素的取值范围归一化,规范为0~1。

上述加载代码中,通过torchvision.datasets.MNIST方法加载MNIST数据集,
方法中的第一个参数data/表示下载数据集存放的位置,这里放在了当前程序目录下的data文件夹中;

参数train表示是否是训练数据,若为True,则加载训练数据集,若为False,则加载测试数据集;

使用参数transform表示对加载数据的预处理,参数值为ToTensor();

最后一个参数download=True表示将下载此数据集,一旦下载完成后,下一次执行此代码时,将优先从本地文件夹直接加载。

现在我们得到了两个数据集,分别是训练数据集和测试数据集,PyTorch还提供了torch.utils.data.DataLoader类用以对数据集做进一步的处理,DataLoader接收数据集,并执行复杂的操作,如小批次处理、多线程、随机打乱等,以便从数据集中获取数据。它接收来自用户的Dataset实例,并使用采样器策略将数据采样为小批次。

DataLoader主要有以下4个目的。

  • (1)使用shuffle参数对数据集做乱序的操作

​ 一般情况下,需要对训练数据集进行乱序的操作。因为原始的数据在样本均衡的情况下可能是按照某种顺序进行排列的,如数据集的前半部分为某一类别的数据,后半部分为另一类别的数据。但经过打乱顺序之后,数据的排列就会拥有一定的随机性,在顺序读取的情况下,读取一次得到的样本为任何一种类型数据的可能性相同。这样可避免出现模型反复依次序学习数据的特征或者学习到的只是数据的次序特征的情况。

  • (2)将数据采样为小批次,可用batch_size参数指定批次大小

​ 若同时对输入和标签迭代送入模型进行训练,这样单个样本训练有一个很大的缺点,就是损失和梯度会受到单个样本的影响,如果样本分布不均匀,或者有错误标注样本,则会引起梯度的巨大震荡,从而导致模型训练效果很差。为了解决此问题,可考虑使用批量数据训练(也叫作批量梯度下降算法),通过遍历全部数据集算一次损失函数,然后计算损失对各个参数的梯度,并更新参数。这种训练方式每更新一次,参数都要把数据集里的所有样本都看一遍,不仅计算开销大,而且计算速度慢。

​ 为了克服上述两种方法的缺点,一般采用的是一种折中手段进行损失函数计算:即把数据分为若干个小的批次(batch),按批次来更新参数,这样,一个批次中的一组数据共同决定了本次梯度的方向,大大降低了参数更新时的梯度方差,下降起来更加稳定,减少了随机性。与单样本训练相比,小批次训练可利用矩阵操作进行有效的梯度计算,计算量也不是很大,对计算机内存的要求也不高。

  • (3)可以充分利用多个子进程加速数据预处理, num_workers参数可以指定子进程的数量

  • (4)可通过collate_fn参数传递批次数据的处理函数,实现在DataLoader中对批次数据做转换处理

train_dl = torch.utils.data.DataLoader(train_ds, batch_size=64,shuffle=True)
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=46)

上述代码中分别创建了训练数据和测试数据的DataLoader,并设置它们的批次大小为64,对训练数据设置了shuffle为True;

对测试数据,由于仅仅作为测试,没必要做乱序。

DataLoader是可迭代对象,我们观察它返回的数据集的形状,以方便对DataLoader和MNIST数据集有一个直观的印象,代码如下:

imgs,labels = next(iter(train_dl))# 创建生成器,并用next方法返回一个批次数据
print(imgs.shape)  # 输出torch.Size([64, 1, 28, 28])
print(labels.shape) # 输出torch.Size([64])

上述代码中使用iter方法将DataLoader对象创建为生成器,并使用next方法返回了一个批次的图像(imgs)和对应的一个批次的标签(labels),imgs.shape为torch.Size([64,1, 28, 28]),如何理解这个shape呢?

很显然,这里的64是批次,我们可以认为这代表64张形状为(1, 28, 28)的图片,其中1为通道数,28和28分别表示高和宽;既然这里有64张图片,对应的也应该有64个标签,也就是labels.shape所显示的torch.Size([64])。

下面通过绘图来看一下MNIST数据集中的这些图片是什么样子的。使用Matplotlib库绘图,绘制imgs中的前10张图片,代码如下:

在这里插入图片描述

2 多层感知器

单个的神经元所完成的任务就是对所有输入的特征乘以权重(w)、加上偏置(b)。

例如,输入有3个特征,分别为x1、x2、x3,那么线性回归模型所做的就是对这些输入特征乘以权重(w)、加上偏置(b),使用激活函数(Activation)激活后,得到输出(Prediction),公式如下:
P r e d i c t i o n = A c t i v a t i o n ( w 1 × x 1 + w 2 × x 2 + w 3 × x 3 + b ) Prediction=Activation(w1×x1+w2×x2+w3×x3+b) Prediction=Activation(w1×x1+w2×x2+w3×x3+b)
当然,在回归问题上并不需要激活函数,或Activation相当于将计算结果直接传递输出。
上面这个公式可看作一个多变量的线性回归模型,一旦通过训练得到了模型的参数值(也就是w1、w2、w3和b的值),就可以使用这个模型做多变量的预测,只需要将参数代入上面的公式即可。

总结单个神经元的一般结构如图所示:
在这里插入图片描述

这里神经元是单层的,也就是说,只有一层计算就输出了结果,没有什么深度。

那什么是深度学习呢?所谓深度学习就是使用更深层的网络来学习,而不是只有一层。
这种只有一层的模型,我们叫作浅层学习,经典机器学习中经常使用这种网络。
浅层学习有一个缺陷,也就是单层神经元的一个缺陷,它无法拟合异或运算,异或运算看上去非常简单,相同为0相异为1。

但是看似简单,使用单个的神经元的缺陷却没有办法解决。单个神经元要求数据必须是线性可分的,异或问题无法找到一条直线分割这两个类,这个问题使得神经网络的发展停滞了很多年。当然,对于无法线性可分的问题,在经典机器学习中可以通过将特征映射到高维空间来实现线性可分。

为了解决此问题,人们提出了使用多层神经元创建模型。多层神经元互相连接,使得模型的深度大大增加,这也是深度学习这个名字的由来。多层神经元互相连接一般称为多层感知器或者神经网络。那为什么叫它神经网络呢?人们解决拟合异或问题,其实受到了生物神经元的启发。生物大脑中的神经元是互相连接的,构成的神经网络彼此连接变得非常的深,当一个信号传递到某一个神经元,如果信号达到了一定的强度,此神经元会被激活,将信号往下传递;如果传递过来的信号没有激活此神经元,这个信号就不再往下传递。这便是大脑中神经元大致的工作原理,它有以下两个特点:

(1)互相连接,网络非常深。

(2)对信号有一个判断或激活。

深度学习或神经网络的工作方式与生物大脑神经元的这种传递的特点类似,为了继续使用神经网络拟合异或问题或者解决各种不具备线性可分的问题,人们想出了一个方法,就是在神经网络的输入和输出之间插入更多的神经元。如下图所示为多层感知器的图示:

在这里插入图片描述

输入层(input)和输出层(output)之间插入了一个隐藏层(hidden),这样使得网络层数变深,我们称它为多层感知器。在多层感知器这个网络结构中,每一层之间的所有单元均互相连接,每一个单元均与前一层所有单元连接,所以我们也称这样的网络为全连接网络。多层感知器的显著特点是包含多层神经元,上图中只有一个隐藏层,实际上可以添加更多的层,层越多,模型的拟合能力会越大。

3 激活函数

​ 首先,为什么要激活?激活也是模拟了上面提到的生物大脑中神经元的工作原理,大脑中神经元会对接收到的信号进行考察,如果此信号满足一定条件,神经元才会将信号往下输出,反之就不往下传递了。激活函数的作用也类似,激活会为网络带来非线性,使得网络可以拟合非线性问题等更多复杂问题,大大增强网络的拟合能力。假如没有激活函数,无论输入与输出之间插入多少层,整个网络仍然是一个线性网络,它还是只能拟合线性问题。

总结起来,激活函数为网络带来了非线性,使得网络可以拟合各种各样复杂的问题。神经网络中常见的激活函数有ReLU、Sigmoid、Tanh、LeakyReLU等,激活函数也可以自定义,只要一个函数是线性可导的,就可以拿来作为激活函数。下面介绍几个常见的。

3.1 ReLU激活函数

​ ReLU也叫修正线性单元,是目前应用最多的一个激活函数,在当前大部分模型中,都使用ReLU函数作为激活函数,其公式如下:
f ( x ) = m a x ( x , 0 ) f(x)=max(x,0) f(x)=max(x,0)
ReLU激活函数图像如下图所示:

在这里插入图片描述

ReLU激活函数的特点是,如果一个输入是大于0的,将其往后传递,反之则输出0,ReLU激活函数在实际应用中几乎是当前最受欢迎的激活函数,它是大多数神经网络的默认选择。在PyTorch中有内置的torch.relu()方法用来实现ReLU激活,代码如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NWfJDFK-1682583811608)(pytorch深度学习.assets/image-20230427120744784.png)]

代码中可以看到如果输入中有小于0的元素,输出会被置为0。

3.2 Sigmoid激活函数

​ Sigmoid激活函数是神经网络早期最常用的激活函数,其公式如下:
S i g m o i d ( x ) = 1 / ( 1 + e − x ) Sigmoid(x)=1/(1+e-x) Sigmoid(x)=1/(1+ex)
Sigmoid激活函数图像如下图所示:

在这里插入图片描述

从上图中可以看到,Sigmoid函数的输出为0~1,其在输入0附近的曲线斜率比较大,在远离0的部分的曲线斜率接近于0。

Sigmoid函数也常作为逻辑回归问题的输出函数,这时Sigmoid的输出可以认为是一个是或否的概率值,常用来解决二分类问题。如果对经典机器学习中的逻辑回归有所了解的话,就会发现,逻辑回归模型的输出层就使用了Sigmoid函数。

Sigmoid函数在深度学习的早期是最常用的中间层激活函数,但是后来逐渐被ReLU函数所取代,这是因为Sigmoid函数在远离0这个中心点的区域几乎接近于水平线,会导致梯度的大大衰减,甚至发生梯度消失,使得模型不容易训练。

在PyTorch中有内置的torch.sigmoid()方法用来实现Sigmoid激活,代码如下:

input = torch.randn(2)
output = torch.sigmoid(input) #使用Sigmoid函数激活,输出为(0,1)
print(output)  # 类似 tensor([0.4569, 0.5355])

3.3 Tanh激活函数

​ Tanh激活函数,又叫作双曲正切激活函数,其公式如下:
T a n h ( x ) = ( e x + e − x ) / ( e x − e − x ) Tanh(x)=(ex+e-x)/(ex-e-x) Tanh(x)=(ex+ex)/(exex)
Tanh激活函数的图像如下图所示:

在这里插入图片描述

在形状上,Tanh激活函数类似Sigmoid激活函数,但是它的中心位置是0,其输出为(−1, 1)。

Tanh激活函数的一个常见的使用场景是对生成模型的输出做激活,从而使得输出规范为(−1, 1)。

PyTorch的内置函数torch.tanh()用来实现双曲正切激活函数。

input = torch.randn(2)
output = torch.tanh(input)   # 对输入使用Tanh函数激活,输出为(-1, 1)
print(output)  # 输出类似tensor([ 0.5529, -0.9574])

3.4 LeakyReLU激活函数

LeakyReLU激活函数(带泄漏单元的ReLU)的数学表达式如下:
y = m a x ( 0 , x ) + l e a k × m i n ( 0 , x ) y=max(0,x)+leak×min(0,x) y=max(0,x)+leak×min(0,x)
LeakyReLU激活函数的图像如下图所示:

在这里插入图片描述

ReLU激活函数将所有的负值都设为零不同,LeakyReLU激活函数给所有负值赋予一个小的非零斜率leak,这样保留了一些负轴的值,使得负轴的信息不会全部丢失。

实际中,LeakyReLU激活函数中的leak取值一般比较小,使用LeakyReLU函数激活后,在反向传播过程中,LeakyReLU激活函数输入小于零的部分,也可以计算得到梯度,这有利于一些情况下的模型训练,例如生成器模型。

PyTorch中有内置的LeakyReLU实现,代码如下:

#初始化 LeakyReLU,参数表示负轴部分的斜率
m = nn.LeakyReLU(0.1)
input = torch.randn(2)
output = m(input)#使用LeakyReLU函数对输入激活
print(m)
print(input)
print(output)

'''
LeakyReLU(negative_slope=0.1)
tensor([-0.0633,  0.7387])
tensor([-0.0063,  0.7387])
'''

Leaky ReLU函数(ReLU的改进)

1、与ReLU函数相比,把x的非常小的线性分量给予负输入(0.01x)来调整负值的零梯度问题;有助于扩大 ReLU 函数的范围,通常𝜆λ的值为 0.01 左右;函数范围是负无穷到正无穷。

2、LeakyRelu激活函数通过在负半轴添加一个小的正斜率(使得负轴的信息不会全部丢失)来解决ReLU激活函数的“死区”问题,该斜率参数𝜆λ是手动设置的超参数,一般设置为0.01。通过这种方式,LeakyRelu激活函数可以确保模型训练过程中神经元的权重在输入小于0的情况下依然会得到更新。

3、不会出现 Dead ReLu 问题,但是关于输入函数f(x) 的部分容易出现梯度爆炸的情况是一样的,所以必要时也可以搭配 sigmoid 或 tanh 使用。

Leaky ReLU不足

1、经典(以及广泛使用的)ReLU 激活函数的变体,带泄露修正线性单元(Leaky ReLU)的输出对负值输入有很小的坡度。由于导数总是不为零,这能减少静默神经元的出现,允许基于梯度的学习(虽然会很慢)。

2、从理论上讲,Leaky ReLU 具有 ReLU 的所有优点,而且 Dead ReLU 不会有任何问题,但在实际操作中,尚未完全证明 Leaky ReLU 总是比 ReLU 更好。

还有很多比较著名的激活函数,如ELU、ReLU6、PReLU、SELU等。

关于激活函数可参考链接自行了解:常用的激活函数合集
pytorch学习推荐日月光华老师的pytorch免费课程:pytorch深度学习与简明教程

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
torchvision是一个用于构建计算机视觉模型的图形库,它是PyTorch深度学习框架的一部分。torchvision包含了几个重要的模块,包括加载数据的函数和常用的数据集接口(torchvision.datasets)、常用的模型结构(torchvision.models,包含了许多预训练模型,如AlexNet、VGG、ResNet等)、常用的图片变换方法(torchvision.transforms,如裁剪、旋转等)以及其他有用的方法(torchvision.utils)。torchvision通常与PyTorch一起安装,安装命令如下:pip install torchvision。安装时建议使用清华镜像以提高下载速度:pip install torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple/。可以通过导入torchtorchvision模块来验证安装是否成功:import torch,import torchvision。如果没有报错,则表示安装成功。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [torchvision详细介绍](https://blog.csdn.net/frighting_ing/article/details/121863387)[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^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [torchvision-0.9.0](https://download.csdn.net/download/weixin_45235219/87401907)[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^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [pytorchtorchvision安装](https://blog.csdn.net/u013230291/article/details/108487877)[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^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰履踏青云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值