pytorch 实现多层神经网络MLP(Pytorch 05)

一 多层感知机

最简单的深度网络称为多层感知机。多层感知机由 多层神经元 组成,每一层与它的上一层相连,从中接收输入;同时每一层也与它的下一层相连,影响当前层的神经元。

softmax 实现了 如何处理数据,如何将 输出转换为有效的概率分布,并应用适当的 损失函数,根据 模型参数最小化损失

线性意味着单调假设:任何特征的增大都会导致模型输出的增大(如果对应的权重为正),或者导致模 型输出的减小(如果对应的权重为负)。

在网络中加入隐藏层,我们可以通过 在网络中加入一个或多个隐藏层来克服线性模型的限制,使其能处理更普遍的函数关系类型。 要做到这一点,最简单的方法是 将许多全连接层堆叠在一起。每一层都输出到上面的层,直到生成最后的输出。我们可以把前L−1层看作表示,把最后一层看作线性预测器。这种架构通常称为多层感知机(multilayer perceptron),通常缩写为 MLP。下面,我们以图的方式描述了多层感知机。

下面是一个单隐藏层的多层感知机,具有5个隐藏单元:

这个多层感知机有4个输入,3个输出,其隐藏层包含5个隐藏单元。输入层不涉及任何计算,因此使用此网络 产生输出 只需要实现隐藏层和输出层的计算。因此,这个多层感知机中的 层数为2。注意,这两个层都是全连 接的。每个输入都会影响隐藏层中的每个神经元,而隐藏层中的每个神经元又会影响输出层中的每个神经元。

线性模型公式:

 不加激活函数,参数可能会组到一起:

加上激活函数 σ 后公式:

为了发挥多层架构的潜力,我们还需要一个额外的关键要素:在仿射变换之后对每个隐藏单元应用非线性的 激活函数(activation function)σ。激活函数的输出(例如,σ(·))被称为活性值(activations)。一般来说, 有了激活函数,就不可能再将我们的多层感知机退化成线性模型
由于X中的每一行对应于小批量中的一个样本,出于记号习惯的考量,我们定义非线性函数σ也以按行的方 式作用于其输入,即一次计算一个样本。

但是 应用于隐藏层的激活函数通常不仅按行操作,也按元素操作。这意味着在计算每一层的线性部分之 后,我们可以 计算每个活性值,而不需要查看其他隐藏单元所取的值。对于大多数激活函数都是这样。 为了构建更通用的多层感知机,我们可以继续堆叠这样的隐藏层,一层叠一层,从而产生更有表达能力的模型。

而且,虽然一个单隐层网络能学习任何函数,但并不意味着我们应该尝试使用单隐藏层网络来解决所有问题。 事实上,通过 使用更深(而不是更广)的网络,我们可以更容易地逼近许多函数

二 激活函数

激活函数(activation function)通过 计算加权和 加上偏置 来确定神经元是否应该被激活,它们将输入信号 转换为输出的可微运算。大多数激活函数都是非线性的

%matplotlib inline
import torch
from d2l import torch as d2l

2.1 ReLU函数

最受欢迎的激活函数是修正线性单元(Rectified linear unit,ReLU),因为它实现简单,同时在各种预测任务 中表现良好。ReLU提供了一种非常简单的非线性变换。给定元素x,ReLU函数被定义为该元素与0的最大值,ReLU函数通过将相应的活性值设为0,仅保留正元素并丢弃所有负元素

        ReLU(x) = max(x, 0)

x = torch.arange(-8.0, 8.0, 1, requires_grad=True)
print(x)
y = torch.relu(x)
d2l.plot(x.detach(), y.detach(), 'x', 'relu(x)', figsize=(5, 2.5))# tensor([-8., -7., -6., -5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.,  5.,
#          6.,  7.], requires_grad=True)

当输入为负时,ReLU函数的导数为0,而当输入为正时,ReLU函数的导数为1。注意,当输入值精确等于0时, ReLU函数不可导。在此时,我们默认使用左侧的导数,即当输入为0时导数为0。

2.1.1 反向传播后查看X的梯度

y.backward(torch.ones_like(x), retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of relu', figsize=(5, 2.5))

 使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过。这使得优化表现得更好,并 且 ReLU 减轻了困扰以往神经网络的梯度消失问题

2.2 sigmoid 函数

对于一个定义域在R中的输入,sigmoid函数将输入变换为区间(0, 1) 上的输出。

sigmoid函数是一个自然的选择,因为它是一个 平滑的、可微 的阈值单元近似。当我们想要将输出视作二元分类问题的概率时,sigmoid仍然被广泛用作 输出单元上的激活函数(sigmoid可以视为softmax的特例)。sigmoid在隐藏层中已经较少使用,它在大部分时候被更简单、 更容易训练的ReLU 所取代。

y = torch.sigmoid(x)
d2l.plot(x.detach(), y.detach(), 'x', 'sigmoid(x)', figsize=(5, 2.5))

sigmoid函数的导数图像如下所示。注意,当输入为0时,sigmoid函数的导数达到最大值0.25;而输入在任一 方向上越远离0点时,导数越接近0

x.grad.data.zero_()
y.backward(torch.ones_like(x), retain_graph=True)
d2l.plot(x.detach(), x.grad, 'x', 'grad of sigmoid', figsize=(5, 2.5))

2.3 tanh函数

与sigmoid函数类似,tanh(双曲正切)函数 也能将其输入压缩转换到区间(‐1, 1)上

下面我们绘制tanh函数。注意,当输入在0附近时,tanh函数接近线性变换。函数的形状类似于sigmoid函数, 不同的是tanh函数 关于 坐标系原点中心对称

y = torch.tanh(x)
d2l.plot(x.detach(), y.detach(), 'x', 'tanh(x)', figsize=(5, 2.5))

tanh函数的导数图像如下所示。当输入接近0时,tanh函数的导数接近最大值1。与我们在sigmoid函数图像 中看到的类似,输入在任一方向上越远离0点,导数越接近0

  • 多层感知机在输出层和输入层之间 增加一个或多个全连接隐藏层,并 通过激活函数转换隐藏层的输出
  • 常用的激活函数包括 ReLU函数sigmoid函数tanh函数

三 多层感知机从零开始实现

3.1 导入数据

Fashion‐MNIST中的每个图像由 28 × 28 = 784个灰度像素值组成。所有图像共分为10个类别

import torch
from torch import nn
from d2l import torch as d2lbatch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
len(train_iter), len(test_iter)# (235, 40)

3.2 初始化模型参数

,Fashion‐MNIST中的每个图像由 28 × 28 = 784个灰度像素值组成。所有图像共分为10个类别。忽 略像素之间的空间结构,我们可以将每个图像视为具有784个输入特征和10个类的简单分类数据集。首先,我 们将实现一个具有单隐藏层的多层感知机,它包含256个隐藏单元。注意,我们可以将这两个变量都视为超参 数。通常,我们选择2的若干次幂作为层的宽度。因为内存在硬件中的分配和寻址方式,这么做往往可以在计 算上更高效。

num_inputs, num_outputs, num_hiddens = 784, 10, 256W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))params = [W1, b1, W2, b2]
params

3.3 激活函数

使用 relu 函数:

def relu(x):a = torch.zeros_like(x)return torch.max(x, a)

3.4 定义模型

因为我们忽略了空间结构,所以我们使用 reshape将每个二维图像转换为一个长度为num_inputs的向量

def net(x):x = x.reshape((-1, num_inputs))h = relu(x@W1 + b1)return (h@W2 + b2)

3.5 定义损失函数

因此在这里我们直接使用高级API中的内置函数来 计 算softmax和交叉熵损失

loss = nn.CrossEntropyLoss(reduction='none')

3.6 执行训练

num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

3.7 执行预测

d2l.predict_ch3(net, test_iter)

 

四 直接调包实现 MLP

与softmax回归的简洁实现 相比,唯一的区别是我们 添加了2个全连接层(之前我们只添加了1个全 连接层)。第一层是隐藏层,它包含128个隐藏单元,并使用了ReLU激活函数。第二层是输出层。  (隐藏层单元个数可以改,保证两个全连接层输出和输入的层数要一致)

net = nn.Sequential(nn.Flatten(),nn.Linear(784, 128),nn.ReLU(),nn.Linear(128, 10))def init_weights(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, std=0.01)
net.apply(init_weights)# Sequential(
#   (0): Flatten(start_dim=1, end_dim=-1)
#   (1): Linear(in_features=784, out_features=128, bias=True)
#   (2): ReLU()
#   (3): Linear(in_features=128, out_features=10, bias=True)
# )
batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=lr)
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

 

 4.1 模型拟合相关知识

将模型在 训练数据上拟合的比在潜在分布中更接近的现象称为过拟合(overfitting),用于对抗过拟合的技术 称为 正则化(regularization)。

我们需要了解训练误差和泛化误差。训练误差(training error)是指,模型在训 练数据集上计算得到的误差泛化误差(generalization error)是指,模型应用在 同样从原始样本的分布中 抽取的无限多数据样本时,模型误差的期望

为了评估模型,将我们的数据分成三份,除了训练和测试数据集之外,还增加一个 验证数据集(val‐ idation dataset),也叫验证集(validation set)。

训练误差和验证误差都很严重,但它们之间仅有一点差距。如果模型不能降低训练误差,这可能意味着模型过于简单(即 表达能力不足),无法捕获试图学习的模式。此外,由于我们的训练和验证误差之间的泛化误差很小,我们有 理由相信可以 用一个更复杂的模型 降低训练误差。这种现象被称为欠拟合(underfitting)。验证集可以用于模型选择,但不能过于随意地使用它

另一方面,当我们的训练误差明显低于验证误差时要小心,这表明严重的 过拟合(overfitting)。最终,我们 通常更关心验证误差,而不是训练误差和验证误差之间的差距

另一个重要因素是数据集的大小。训练数据集中的样本越少,我们就越有可能过拟合。随着 训练数据量的增加,泛化误差通常会减小

我们应该选择一个复杂度适当的模型,避免使用数量不足的训练样本。

我们总是可以通过去收集更多的 训练数据来缓解过拟合。但这可能成本很高,耗时颇多,或者完全超出我们的控制,因而在短期内不可能做 到。假设我们已经拥有尽可能多的高质量数据,我们便可以将重点放在 正则化技术 上。

4.2 正则化相关

1 权重衰减(weight decay)是最广泛使用的正则化的技术之一,它通常也被 称为 L2正则化

2 暂退法在前向传播过程中,计算每一内部层的同时注入噪声,这已经成为 训练神经网络的常用技术。这种方法之所以被称为暂退法,因为我们从表面上看是在训练过程中丢弃(drop out)一些神经元。在整个训练过程的每一次迭代中,标准暂退法包括在计算下一层之前 将当前层中的一些节 点置零

当我们将暂退法应用到隐藏层,以p的概率 将隐藏单元置为零时,结果可以看作一个只包含原始神经元子集的网络。比如在 图4.6.1中,删除了h2和h5, 因此输出的计算不再依赖于h2或h5,并且它们各自的梯度在执行反向传播时也会消失。这样,输出层的计算 不能过度依赖于h1, . . . , h5的任何一个元素

  • 暂退法在前向传播过程中,计算每一内部层的同时丢弃一些神经元
  • 暂退法可以避免过拟合,它通常与控制权重向量的维数和大小结合使用的。
  • •暂退法仅在训练期间使用。

五 前向传播、反向传播和计算图

前向传播(forward propagation或forward pass)指的是:按顺序(从输入层到输出层)计算和存储神经网 络中每层的结果

反向传播(backward propagation或backpropagation)指的是计算神经网络参数梯度的方法

该方 法根据微积分中的链式规则,按相反的顺序从输出层到输入层遍历网络

在训练神经网络时,前向传播和反向传播相互依赖。对于前向传播,我们沿着依赖的方向遍历计算图并计算 其路径上的所有变量。然后将这些用于反向传播,其中计算顺序与计算图的相反。一方面,在前向传播期间计算正则项取决于 模型参数W(1)和 W(2)的当前值。它 们是由优化算法根据最近迭代的反向传播给出的。另一方面,反向传播期间参数的梯度计算,取决于 由前向传播给出的隐藏变量h的当前值

因此,在训练神经网络时,在初始化模型参数后,我们交替使用前向传播和反向传播,利用反向传播给出的 梯度来更新模型参数。注意,反向传播重复利用前向传播中存储的中间值,以避免重复计算。带来的影响之 一是我们 需要保留中间值,直到反向传播完成。这也是 训练比单纯的预测需要更多的内存(显存)的原因之 一。此外,这些中间值的大小与网络层的数量和批量的大小大致成正比。因此,使用更大的批量来训练更深 层次的网络更容易导致内存不足(out of memory)错误。

  • 前向传播在神经网络定义的计算图中按顺序计算和存储中间变量,它的顺序是从输入层到输出层。
  • 反向传播按相反的顺序(从输出层到输入层)计算和存储神经网络的中间变量和参数的梯度。
  • 在训练深度学习模型时,前向传播和反向传播是相互依赖的。
  • 训练比预测需要更多的内存。

5.1 参数初始化

初始化方案的选择在神经网络学习中起着举足轻重的作用,它对保持数值稳定性至关重要。此外, 这些初始化方案的选择可以与非线性激活函数的选择有趣的结合在一起。我们选择哪个函数以及如何初始化 参数可以决定优化算法收敛的速度有多快糟糕选择可能会导致我们在训练时遇到梯度爆炸或梯度消失

神经网络设计中的另一个问题是 其参数化所固有的对称性

默认初始化,我们使用正态分布来初始化权重值。如果我们不指定初始化方法,框架将 使用默认的随机初始化方法,对于中等难度的问题,这种方法通常很有效。

需要用启发式的初始化方法来确保初始梯度既不太大也不太小,ReLU激活函数缓解了梯度消失问题,这样可以加速收敛。随机初始化是保证在进行优化前打破对称性的关键

Xavier初始化,,Xavier初始化从均值为零,方差  的高斯分布中采样权重。Xavier初始化表明,对于每一层,输出的方差不受输入数量的影响,任何梯度的方差不受输出数量的影 响。

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

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

相关文章

SpringAOP+自定义注解实现限制接口访问频率,利用滑动窗口思想Redis的ZSet(附带整个Demo)

目录 1.创建切面 2.创建自定义注解 3.自定义异常类 4.全局异常捕获 5.Controller层 demo的地址,自行获取《《—————————————————————————— Spring Boot整合Aop面向切面编程实现权限校验,SpringAop自定义注解自定义异常全局…

【微服务】Gateway服务网关

📝个人主页:五敷有你 🔥系列专栏:微服务 ⛺️稳中求进,晒太阳 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等响…

Windows 设置多显示器显示

Windows 设置多显示器显示 1. Windows 7 设置 HDMI 输出2. Windows 11 设置多显示器显示References 1. Windows 7 设置 HDMI 输出 2. Windows 11 设置多显示器显示 ​​​ References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

Ubuntu Desktop 安装谷歌拼音输入法

Ubuntu Desktop 安装谷歌拼音输入法 1. Installation1.1. 汉语语言包​1.2. 谷歌拼音输入法1.3. 安装语言包1.4. 键盘输入方式系统1.5. 重启电脑1.6. 输入法配置 2. configuration2.1. Text Entry Settings… 3. ExecutionReferences 1. Installation 1.1. 汉语语言包 strong…

odoo扩展导出pdf功能

1. 说明: odoo原生导出功能扩展导出pdf文件功能, 如有额外需求请联系博主 2. 版本说明: odoo版本: odoo15 其他odoo版本未进行测试,如有需要自行测试 3. 地址: 该补丁代码放在github仓库, 地址: https://github.com/YSL-Alpaca/odoo_export_pdf 4. 改补丁依赖于第三方软件wkh…

网盘——数据库操作

关于网盘的数据库模块,主要有以下几个内容:定义数据库操作类、将数据库操作类定义成单例模式、数据库操作 数据库是在Qt里面,定义成操作类,专门用这个类产生对象,对数据库实现操作,那么我们在产生对象的时…

音视频领域首个,阿里云推出华为鸿蒙 HarmonyOS NEXT 版音视频 SDK

近日,阿里云在官网音视频终端 SDK 栏目发布适配 HarmonyOS NEXT 的操作文档和 SDK,官宣 MediaBox 音视频终端 SDK 全面适配 HarmonyOS NEXT。 此外,阿里云播放器 SDK 也在华为开发者联盟官网鸿蒙生态伙伴 SDK 专区同步上线,面向所…

Linux系统——硬件命令

目录 一.网卡带宽 1.查看网卡速率——ethtool 网卡名 2.查看mac地址——ethtool -P 网卡名 二、内存相关 1.显示系统中内存使用情况——free -h 2.显示内存模块的详细信息——dmidecode -t memory 三、CPU相关 1.查看CPU架构信息——lscpu 2.性能模式 四、其他硬件命…

Java微服务分布式分库分表ShardingSphere - ShardingSphere-JDBC

🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 往期热门专栏回顾 专栏…

个人博客系列-后端项目-系统角色配置(8)

系统角色配置需要设置的接口 用户可以绑定多个角色,角色对应有多个路由权限。用户绑定角色后,可以访问当前角色下的各个api路由和菜单路由。 用户注册时设置用户角色修改用户角色(同时对应用户可以访问的路由将会同步变更)添加修…

python写爬虫爬取京东商品信息

工具库 爬虫有两种方案: 第一种方式是使用request模拟请求,并使用bs4解析respond得到数据。第二种是使用selenium和无头浏览器,selenium自动化操作无头浏览器,由无头浏览器实现请求,对得到的数据进行解析。 第一种方…

[Java基础揉碎]单例模式

目录 什么是设计模式 什么是单例模式 饿汉式与懒汉式 饿汉式vs懒汉式 懒汉式存在线程安全问题 什么是设计模式 1.静态方法和属性的经典使用 2.设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、 以及解决问题的思考方式。设计模式就像是经典的棋谱&am…

数据分析和机器学习库Pandas的使用

Pandas 库是一个免费、开源的第三方 Python 库,是 Python 数据分析和机器学习的工具之一。Pandas 提供了两种数据结构,分别是 Series(一维数组结构)与 DataFrame(二维数组结构),极大地增强的了 …

STM32微控制器的中断优先级设置对系统性能有何影响?

STM32微控制器的中断优先级设置对系统性能有着显著的影响。正确配置中断优先级可以确保关键任务得到及时响应,提高系统的实时性和可靠性。相反,如果中断优先级设置不当,可能会导致系统响应延迟,甚至出现死锁等问题。本文将详细探讨…

边缘计算【智能+安全检测】系列教程-- Jeton Agx Orin 基础环境搭建

1 .前期准备 Jetson Agx Orin 比Jetson Agx Orin Xavier的算力要高,性能要好通常用来做自动驾驶的AI推理,具体外观如下图 1.刷机软件sdkmanager:下载链接 NVIDIA账号需要注册,正常一步一步往下走就行。在ubuntu18以上的系统安…

pycharm搭建新的解释器及删除处理

目录 1.创建虚拟环境 个人实际操作: 对于“继承全局站点包”: 2.创建一个新项目 3.删除操作 (1)删除解释器 (2)删除新建项目 1.创建虚拟环境 Pycharm官方文档说明网址: Configure a virt…

C语言 数组指针 指针数组

指针数组 什么是指针数组&#xff0c;他是一个数组&#xff0c;数组的元素是指针。但是指针也有多种数据类型&#xff0c;有数组指针、函数指针、整形指针、字符串指针。 现在我就使用函数指针来写代码&#xff0c;也就是函数指针数组的应用代码&#xff1a; #include <s…

Qt实现简易的多线程TCP服务器(支持多个客户端连接)附源码

目录 一.UI界面的设计 二.服务器的启动 三.实现自定义的TcpServer类 1.在widget中声明自定义TcpServer类的成员变量 2.在TcpServer的构造函数中对于我们声明的m_widget进行初始化&#xff0c;m_widget我们用于后续的显示消息等&#xff0c;说白了就是主界面的更新显示等 …

自注意力机制的理解

一、自注意力要解决什么问题 循环神经网络由于信息传递的容量以及梯度消失问题&#xff0c;只能建立短距离依赖关系。为了建立长距离的依赖关系&#xff0c;可以增加网络的层数或者使用全连接网络。但是全连接网络无法处理变长的输入序列&#xff0c;另外&#xff0c;不同的输…

计算机三级——网络技术(综合题第五题)

第一题 填写路由器RG的路由表项①至④。 目的网络&#xff0f;掩码长度输出端口输出端口172.19.63.192&#xff0f;30S0(直接连接)172.19.63.188&#xff0f;30S1(直接连接) 路由器RG的S0的IP地址是172.19.63.193&#xff0c;路由器RE的S0的IP地址是172.19.63.194。 【解析】…