【深度学习】多层感知机的从零开始实现与简洁实现

news2025/1/10 2:44:36

可以说,到现在我们才真正接触到深度网络。最简单的深度网络称为多层感知机。

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

和以前相同,先介绍它的基本内容,再从零开始实现,最后利用 Pytorch 框架简洁实现。

一、多层感知机

隐藏层

回想一下我们上一节中的 softmax 模型架构,该模型通过线性变换将输入映射为输出,然后进行 softmax 操作。

softmax 模型架构

但是,这样的线性模型可能会出错。线性意味着单调,即如果权重为正的话,任何特征的增大都将引起输出的增大。

有时这样的模型是适合的,且我们还可以通过一些处理(如对数运算),使得线性模型能够起作用。

然而,现实生活中更多的是不单调的情况。例如,根据体温预测死亡率,对于高于 37 度的人来说,体温越高越危险;而对于低于 37 度的人来说,温度越高,风险越低。

再想想我们上一节实现的分类问题,一张 28 × 28 28\times28 28×28 的图片,我们将其视为了具有 784 个特征的输入,分别对应于 784 个像素点。

我们增强某个像素的强度,是否就能增大这张图片属于某个类别的概率呢?显然是不会的。

图像分类的结果与图片的像素强度具有更加复杂的关系,并且我们也难以通过一些简单的变换使得线性模型可行。

我们可以在网络中加入一个或多个隐藏层来克服线性模型的缺陷,使其能处理更复杂的函数关系。

其中一个简单的办法是将许多全连接层堆叠在一起。每一层输出的上面的层,直到生成最后的输出。这种架构通常称为多层感知机(multilayer perceptron, MLP)。

单隐藏层的多层感知机

这个多层感知机有 4 个输入,3 个输出,其隐藏层包含 5 个 隐藏单元。

输入层不涉及任何计算,因此使用此网络产生输出只需要实现隐层和输出层的计算,故该多层感知机的层数为 2。

但是,加入了一层隐藏层后,实际上输入和输出还是线性关系,因为线性关系嵌套还是线性的。

为了发挥多层架构的潜力,我们还需要一个额外的因素:在线性变换之后对每个隐藏单元应用非线性的激活函数(activation function)。激活函数的输出被称为活性值(activations)。

一般来说,有了激活函数,就不可能再将我们的多层感知机退化为线性模型。

激活函数

激活函数通过计算加权和并加上偏置来确定神经元是否应该被激活,它们将输入信号转换为输出的可微运算。常见的激活函数有:

1. ReLU 函数

因为修正线性单元(Rectified linear unit, ReLU)实现简单,同时在各种预测任务中表现良好,因此它广受欢迎。

ReLU 提供了一种非常简单的非线性变换。给定元素 x x x,ReLU 函数被定义为该元素与 0 的最大值。

ReLu 函数曲线

2. Sigmoid 函数

对于一个定义域在 R R R 中的输入,sigmoid 函数将输入变换为区间(0, 1)上的输出。因此,sigmoid 通常被称为挤压函数。

Sigmoid 函数曲线

3. tanh 函数

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

tanh 函数曲线

二、多层感知机的从零开始实现

我们继续研究上一节的分类问题,同样使用 Fashion-MNIST 数据集。

初始化模型参数

回想一下我们在 softmax 里的初始化,因为 softmax 回归只有一层,故只需要初始化一个权重向量和一个偏置即可。

多层感知机多了一层线性层,故共有 4 个模型参数,隐藏层的权重、偏置以及输出层的权重及偏置。

此外,隐藏层的宽度需要我们确定,其可视为一个超参数。一般我们取 2 的若干次幂,且介于输入大小和输出大小之间,这里我们选择 256。

隐层的参数形状为 784 × 256 784\times 256 784×256,而输出层参数的形状为 256 × 10 256\times10 256×10

    num_inputs, num_outputs, num_hiddens = 784, 10, 256

    W1 = 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]

定义激活函数

这里我们选择 ReLU,用于处理隐层的输出,再出入输出层。

def relu(X):               # 激活函数
    a = torch.zeros_like(X)
    return torch.max(X, a)

定义模型

有了激活函数后,模型的定义可直接使用矩阵乘法实现。

def net(X):               # 模型
    X = X.reshape((-1, num_inputs))   # 展平
    H = relu(X@W1 + b1)  # 这里“@”代表矩阵乘法
    return (H@W2 + b2)

定义损失函数

这里我们通用采用交叉熵损失。值得一提的是,直接调用的 nn 模块里的交叉熵损失函数,它里面就包含了 softmax 操作。

    loss = nn.CrossEntropyLoss(reduction='none')   # 损失函数

训练

多层感知机的训练和 softmax 大差不差,直接用我们之前写好的那个训练函数。

    num_epochs, lr = 10, 0.1
    optimizer = torch.optim.SGD(params, lr=lr)
    train(net, train_iter, test_iter, loss, num_epochs, optimizer)

得到的结果为如下。可以发现,加了激活函数后,训练损失倒小了不少,但测试集精度并未有明显提升。

第10轮的训练损失为0.3840572128295898
第10轮的训练精度为0.8638666666666667
第10轮的测试集精度为0.8394

有了前面线性回归和 softmax 回归的基础,这里实现起来是很轻松的,只是模型参数多了需要单独初始化有些麻烦。

下面我们看看简洁实现。

三、多层感知机的简洁实现

定义模型与初始化参数

调用框架的话,在定义模型调用 nn.Sequential 时,注意有 4 层,第一层展平,第二层隐层,第三层激活,第四层输出。

模型的初始化可以利用前面定义过的初始化权重函数init_weights()

    net = nn.Sequential(nn.Flatten(),
                        nn.Linear(784, 256),
                        nn.ReLU(),
                        nn.Linear(256, 10))    # 定义模型
    net = net.to(try_gpu())
    net.apply(init_weights)     # 初始化模型参数

训练

可以直接把 softmax 回归的简洁实现代码复制过来,把定义模型和初始化参数的部分改了,就 OK 了。

训练情况如下:

10轮的训练损失为0.385405567804972310轮的训练精度为0.8633510轮的测试集精度为0.8503

两种实现方式的代码见资源。

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

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

相关文章

【深入解析】AI工作流中的HTTP组件:客户端与服务端执行的区别

在当今快速发展的技术环境中,AI工作流的设计和实现变得愈发重要。尤其是在处理HTTP组件时,前端执行与后端执行之间的区别,往往会对系统的安全性和数据的准确性产生深远的影响。今天,我们就来深入探讨这一话题,揭示前端…

音频基础学习四——声音的能量与分贝

文章目录 前言一、能量与分贝1.音频能量2.分贝3.两者的区别4. 应用场景 二、分贝的计算方式1.具体数学公式2.具体算法示例3.对于算法的释义大小端为什么通过计算得到的是负值范围实际结果 总结 前言 很多博客中经常会把声音的能量和分贝说成是一个东西,这种说法是错…

原型模式prototype

此篇为学习笔记,原文链接 https://refactoringguru.cn/design-patterns/prototype 能够复制已有对象, 而又无需使代码依赖它们所属的类 所有的原型类都必须有一个通用的接口, 使得即使在对象所属的具体类未知的情况下也能复制对象。 原型对…

云计算之云原生(上)

目录 一、消息队列RocketMQ 1.1 功能介绍 1.1.1 业务消息首选:消息队列 RocketMQ 1.1.2 【收发流量隔离约束】读写分离控制提高集群稳定性 1.1.3 【Dashboard 仪表盘】实时观测实例状态 1.1.4 【消息轨迹追踪】消息生命周期状态一目了然 1.1.5 【实时扩缩容】…

单点登录OAuth2.0

OAuth 2.0(Open Authorization 2.0)是OAuth协议的第二个版本,于2012年正式成为RFC 6749标准。在OAuth 2.0之前,OAuth 1.0版本已经为Web应用提供了一定程度的授权功能,但随着时间的推移,这些版本逐渐显露出一…

“Docker网络模式详解与应用“

目录 前言 Docker内置网络 bridge 基本概念 案例 工作原理 使用场景 host 基本概念 案例 工作原理 使用场景 none 基本概念 案例 !!!大佬救命 container 基本概念 案例 自定义网络 自定义bridge 基本概念 案例 Docker…

界面控件KendoReact中文教程 - 如何创建动态进度条?

Kendo UI致力于新的开发,来满足不断变化的需求。现在我们非常自豪地宣布,通过React框架的Kendo UI JavaScript封装来支持React Javascript框架。Kendo UI for React能够为客户提供更好的用户体验,并且能够更快地构建更好的应用程序。 KendoR…

树莓派外设驱动WiringPi库

树莓派外设驱动WiringPi库 文章目录 树莓派外设驱动WiringPi库一、树莓派安装WiringPi库二、WiringPi库的使用方法 一、树莓派安装WiringPi库 wiringPi库其实已经很熟悉了,在香橙派中大量使用过,这个库中集成了很多使用的功能性函数,树莓派安…

设计模式-行为型模式-状态模式

1.状态模式的定义 允许一个对象在其内部状态改变时改变他的行为,用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题,状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象的状态可以灵活变化&…

【STM32】GPIO输入实现按键控制LED

1.stm32cubemx配置 和上篇博客配置一样 2.代码编写 实现一个按键按下LED1亮,另一个按下LED灭 KEY1实现LED1亮,KEY2实现LED2灭 1.配置GPIOA,GPIOB时钟使能 2.配置GPIOB模式初始化 3.配置GPIOA模式初始化 基本和2一样,不一样的是按键使用的…

(详)Vue3 + Typescript 项目配置 eslint + prettier + husky + lint-staged

目录 1,前言1.1,eslint 和 prettier 的关系1.2,Node.js 版本的问题 1,eslint1.1,安装1.2,配置文件1.3,集成对 vue 文件的配置1.4,在 package.json 中添加命令 2,prettier…

【代码随想录训练营第42期 Day52打卡 - 岛屿问题2

目录 一、做题心得 二、题目与题解 题目一:卡码网 101. 孤岛的总面积 题目链接 题解:DFS 题目二:卡码网 102. 沉没孤岛 题目链接 题解:DFS 三、小结 一、做题心得 今天做题时间比较晚了,只打卡完成了岛屿问题…

条件生成模型 (conditional generation)

我们之前讲的 GAN 中的生 成器,它没有输入任何的条件,它只是输入一个随机的分布,然后产生出来一张图片。我们现 在想要更进一步的是希望可以操控生成器的输出,我们给它一个条件x,让他根据条件x跟 输入z 来产生输出y。那…

硬件-经典开机电路

文章目录 一:网友公司祖传的开机电路二:电路符号名称三:电路原理分析道友:对于利益相关的人,要展示你的实力和智力。对于利益不相关的人,展示你的礼貌就好。 一:网友公司祖传的开机电路 业务逻辑…

【二】TDEngine快速入门

TDEngine快速入门 目录 TDEngine深入理解 概述 一、核心概念解析 二、基本操作 三、可视化管理工具 总结 概述 TDEngine创始人在官方出品的书籍中写到:我观察到,无论是出行行业还是更广义的运输行业,以及分布式能源系统,都将…

【网络安全 | 渗透工具】Cencys+Shodan使用教程

原创文章,不得转载。 文章目录 Cencys准备语法全文搜索字段和值搜索通配符搜索布尔逻辑搜索嵌套搜索时间相关搜索范围搜索双引号 (")转义序列和保留字符Censys 搜索语言中的主机查询查看主机搜索结果Censys 搜索语言中的证书查询查看证书搜索结果生成报告其余Shodan准备使…

解决MongoDB创建用户报错command createUser requires authentication

1、执行创建用户报错如下: 2、解决方法 2.1 关闭 MongoDB /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/mongod.conf --shutdown 2.2 修改配置文件 vim /usr/local/mongodb/mongod.conf 将security.authorization值从enabled改为disabled 2.3 启动MongoD…

HTML/CSS/JS学习笔记 Day2(HTML--标签 上)

跟着该视频学习,记录笔记:【黑马程序员pink老师前端入门教程,零基础必看的h5(html5)css3移动端前端视频教程】https://www.bilibili.com/video/BV14J4114768?p12&vd_source04ee94ad3f2168d7d5252c857a2bf358 Day2 内容梳理:…

redission中的锁分类

redis 分布式锁的核心命令 redis分布式锁的实现主要是依靠setnx和expire两个命令完成。 注意:由于setnx和expire是两个命令,会存在如果 setnx 是成功的,但是 expire 设置失败,一旦出现了释放锁失败,或 者没有手工释放…

用华为智驾,开启MPV的下半场

作者 |老缅 编辑 |德新 8月28日,岚图正式对外公布了全球首款搭载华为乾崑智驾和鸿蒙座舱的MPV——全新岚图梦想家。 新车定位「全景豪华科技旗舰MPV」,全系标配四驱,分为四驱鲲鹏版和四驱乾崑版。 其中岚图逍遥座舱和鲲鹏智驾构成的鲲鹏版…