深度学习(鱼书)day08–误差反向传播(后三节)

在这里插入图片描述

一、激活函数层的实现

这里,我们把构成神经网络的层实现为一个类。先来实现激活函数的ReLU层和Sigmoid层。

  1. ReLU层

    激活函数ReLU(Rectified Linear Unit)由下式表示。
    y={x(x>0)0(x≤0) y = \begin{cases} x & (x > 0) \\ 0 & (x \leq 0) \end{cases} y={x0(x>0)(x0)
    y关于x的导数:
    ∂y∂x={1(x>0)0(x≤0) \frac{\partial y}{\partial x} = \begin{cases} 1 & (x > 0) \\ 0 & (x \leq 0) \end{cases} xy={10(x>0)(x0)
    在这里插入图片描述

    class ReLU:def __init__(self):self.mask = Nonedef forward(self, x):self.mask = (x <= 0)out = x.copy()out[self.mask] = 0def backward(self, dout):dout[self.mask] = 0dx = doutreturn dx
    

    这个变量mask是由True/False构成的NumPy数组,它会把正向传播时的输入x的元素中小于等于0的地方保存为True,其他地方(大于0的元素)保存为False。

    如果正向传播时的输入值小于等于0,则反向传播的值为0。因此,反向传播中会使用正向传播时保存的mask,将从上游传来的dout的mask中的元素为True的地方设为0。

    ReLU层的作用就像电路中的开关一样。正向传播时,有电流通过的话,就将开关设为 ON;没有电流通过的话,就将开关设为 OFF。反向传播时,开关为ON的话,电流会直接通过;开关为OFF的话,则不会有电流通过。

  2. Sigmoid层

    在这里插入图片描述

    正向传播:

在这里插入图片描述

反向传播:

步骤1

“/”节点表示 在这里插入图片描述
,它的导数可以解析性地表示为下式。

在这里插入图片描述

反向传播时,会将上游的值乘以-y 2 (正向传播的输出的平方乘以1后的值)后,再传给下游。计算图如下所示。
在这里插入图片描述

步骤2

“+”节点将上游的值原封不动地传给下游。计算图如下所示。

在这里插入图片描述

步骤3

“exp”节点表示y = exp(x),它的导数由下式表示。
在这里插入图片描述

上游的值乘以正向传播时的输出(这个例子中是exp(−x))后,再传给下游。
在这里插入图片描述

步骤4

×”节点将正向传播时的值翻转后做乘法运算。因此,这里要乘以1。

在这里插入图片描述

集约化的“sigmoid”节点。可以不用在意Sigmoid层中琐碎的细节,而只需要专注它的输入和输出,这一点也很重要。

在这里插入图片描述

进一步整理如下:

在这里插入图片描述

因此,Sigmoid层的反向传播,只根据正向传播的输出就能计算出来。
在这里插入图片描述

代码实现:


class Sigmoid:def __init__(self):self.out = Nonedef forward(self, x):out = 1 / (1 + np.exp(-x))self.out = outreturn outdef backward(self, dout):dx = dout * (1.0 - self.out) * self.outreturn dx

二、Affine/Softmax层的实现

  1. Affine层

    神经网络的正向传播中进行的矩阵乘积运算在几何学领域被称为“仿射变换”。因此,这里将进行仿射变换的处理实现为“Affine层”。

    现在将这里进行的求矩阵的乘积与偏置的和的运算用计算图表示出来。将乘积运算用“dot”节点表示的话,则np.dot(X, W) + B的运算可用下图所示的计算图表示出来。在各个变量的上方标记了它们的形状(计算图上显示了X的形状为(2,),X·W的形状为(3,))。

在这里插入图片描述

现在我们来考虑图5-24的计算图的反向传播。以矩阵为对象的反向传播,按矩阵的各个元素进行计算时,步骤和以标量为对象的计算图相同。实际写一下的话,可以得到下式:

在这里插入图片描述

尝试写出计算图的反向传播,如图所示:


在这里插入图片描述

  1. 批版本的Affine层

    前面介绍的Affi ne层的输入X是以单个数据为对象的。现在我们考虑N个数据一起进行正向传播的情况,也就是批版本的Affine层。先给出批版本的Affine层的计算图,如图所示。

    在这里插入图片描述

    正向传播时,偏置会被加到每一个数据(第1个、第2个……)上。因此,反向传播时,各个数据的反向传播的值需要汇总为偏置的元素。用代码表示的话,如下所示。

在这里插入图片描述

这里使用了np.sum()对第0轴(以数据为单位的轴,axis=0)方向上的元素进行求和。

class Affine:def __init__(self, W, b):self.W =Wself.b = bself.x = Noneself.dW = Noneself.db = Nonedef forward(self, x):self.x = xout = np.dot(x, self.W) + self.breturn outdef backward(self, dout):dx = np.dot(dout, self.W.T)self.dW = np.dot(self.x.T, dout)self.db = np.sum(dout, axis=0)return dx

输入数据为张量(四维数据)的情况:

class Affine:def __init__(self, W, b):self.W =Wself.b = bself.x = Noneself.original_x_shape = None# 权重和偏置参数的导数self.dW = Noneself.db = Nonedef forward(self, x):# 对应张量self.original_x_shape = x.shapex = x.reshape(x.shape[0], -1)self.x = xout = np.dot(self.x, self.W) + self.breturn outdef backward(self, dout):dx = np.dot(dout, self.W.T)self.dW = np.dot(self.x.T, dout)self.db = np.sum(dout, axis=0)dx = dx.reshape(*self.original_x_shape)  # 还原输入数据的形状(对应张量)return dx
  1. Softmax-with-Loss 层

    softmax函数会将输入值正规化之后再输出。比如手写数字识别时,Softmax层的输出如图所示。

在这里插入图片描述

神经网络中进行的处理有推理(inference)和学习两个阶段。神经网络的推理通常不使用 Softmax层。比如,用图 5-28的网络进行推理时,会将最后一个 Affine层的输出作为识别结果。神经网络中未被正规化的输出结果有时被称为“得分”。也就是说,当神经网络的推理只需要给出一个答案的情况下,因为此时只对得分最大值感兴趣,所以不需要 Softmax层。不过,神经网络的学习阶段则需要 Softmax层。

这里也包含作为损失函数的交叉熵误差(cross entropy error),所以称为“Softmax-with-Loss层”。Softmax-with-Loss层(Softmax函数和交叉熵误差)的计算图如图所示。

在这里插入图片描述
在这里插入图片描述

  • 这里假设要进行3类分类,从前面的层接收3个输入(得分)。Softmax层将输入(a1, a2, a3)正规化,输出(y1, y2, y3)。Cross Entropy Error层接收Softmax的输出(y1, y2, y3)和教师标签(t1, t2, t3),从这些数据中输出损失L。

  • 注意反向传播的结果:Softmax层的反向传播得到了(y1 − t1, y2 − t2, y3 − t3)这样“漂亮”的结果。由于(y1, y2, y3)是Softmax层的输出,(t1, t2, t3)是监督数据,所以(y1 − t1, y2 − t2, y3 − t3)是Softmax层的输出和教师标签的差分。神经网络的反向传播会把这个差分表示的误差传递给前面的层,这是神经网络学习中的重要性质

  • 考虑一个具体的例子,比如教师标签是 (0, 1, 0),Softmax层的输出是 (0.3, 0.2, 0.5)的情形。因为正确解标签处的概率是0.2(20%),这个时候的神经网络未能进行正确的识别。此时,Softmax层的反向传播传递的是(0.3, −0.8, 0.5)这样一个大的误差。因为这个大的误差会向前面的层传播,所以Softmax层前面的层会从这个大的误差中学习到“大”的内容。

  • 回归问题中输出层使用“恒等函数”,损失函数使用“平方和误差”,也是出于同样的理由。也就是说,使用“平方和误差”作为“恒等函数”的损失函数,反向传播才能得到(y1 −t1, y2 − t2, y3 − t3)这样“漂亮”的结果。

  • 再举一个例子,比如思考教师标签是 (0, 1, 0),Softmax层的输出是 (0.01, 0.99, 0)的情形(这个神经网络识别得相当准确)。此时Softmax层的反向传播传递的是 (0.01, −0.01, 0)这样一个小的误差。这个小的误差也会向前面的层传播,因为误差很小,所以Softmax层前面的层学到的内容也很“小”

Softmax-with-Loss层的实现:

class SoftmaxWithLoss:def __init__(self):self.loss = Noneself.y = Noneself.t = Nonedef forward(self, x, t):self.t = tself.y = softmax(x)self.loss = cross_entropy_error(self.y, self.t)return self.lossdef backward(self, dout=1):batch_size = self.t.shape[0]if self.t.size == self.y.size:  # 监督数据是one-hot-vector的情况dx = (self.y - self.t) / batch_sizeelse:dx = self.y.copy()dx[np.arange(batch_size), self.t] -= 1dx = dx / batch_sizereturn dx

注意反向传播时,将要传播的值除以批的大小(batch_size)后,传递给前面的层的是单个数据的误差。

三、误差反向传播法的实现

通过像组装乐高积木一样组装上一节中实现的层,可以构建神经网络。本节我们将通过组装已经实现的层来构建神经网络。

  1. 神经网络学习的全貌图

在这里插入图片描述

步骤2中,之前我们利用数值微分求得了这个梯度。数值微分虽然实现简单,但是计算要耗费较多的时间。和需要花费较多时间的数值微分不同,误差反向传播法可以快速高效地计算梯度

  1. 对应误差反向传播法的神经网络的实现

    import sys, os
    sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
    import numpy as np
    from common.layers import *
    from common.gradient import numerical_gradient
    from collections import OrderedDictclass TwoLayerNet:def __init__(self, input_size, hidden_size, output_size, weight_init_std = 0.01):# 初始化权重self.params = {}self.params['W1'] = weight_init_std * np.random.randn(input_size, hidden_size)self.params['b1'] = np.zeros(hidden_size)self.params['W2'] = weight_init_std * np.random.randn(hidden_size, output_size) self.params['b2'] = np.zeros(output_size)# 生成层self.layers = OrderedDict()self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])self.layers['Relu1'] = Relu()self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])self.lastLayer = SoftmaxWithLoss()def predict(self, x):for layer in self.layers.values():x = layer.forward(x)return x# x:输入数据, t:监督数据def loss(self, x, t):y = self.predict(x)return self.lastLayer.forward(y, t)def accuracy(self, x, t):y = self.predict(x)y = np.argmax(y, axis=1)if t.ndim != 1 : t = np.argmax(t, axis=1)accuracy = np.sum(y == t) / float(x.shape[0])return accuracy# x:输入数据, t:监督数据def numerical_gradient(self, x, t):loss_W = lambda W: self.loss(x, t)grads = {}grads['W1'] = numerical_gradient(loss_W, self.params['W1'])grads['b1'] = numerical_gradient(loss_W, self.params['b1'])grads['W2'] = numerical_gradient(loss_W, self.params['W2'])grads['b2'] = numerical_gradient(loss_W, self.params['b2'])return gradsdef gradient(self, x, t):# forwardself.loss(x, t)# backwarddout = 1dout = self.lastLayer.backward(dout)layers = list(self.layers.values())layers.reverse()for layer in layers:dout = layer.backward(dout)# 设定grads = {}grads['W1'], grads['b1'] = self.layers['Affine1'].dW, self.layers['Affine1'].dbgrads['W2'], grads['b2'] = self.layers['Affine2'].dW, self.layers['Affine2'].dbreturn grads
    

在这里插入图片描述

OrderedDict是有序字典,“有序”是指它可以记住向字典里添加元素的顺序。因此,神经网络的正向传播只需按照添加元素的顺序调用各层的forward()方法就可以完成处理,而反向传播只需要按照相反的顺序调用各层即可。因为Affine层和ReLU层的内部会正确处理正向传播和反向传播,所以这里要做的事情仅仅是以正确的顺序连接各层,再按顺序(或者逆序)调用各层

  1. 误差反向传播法的梯度确认
    在确认误差反向传播法的实现是否正确时,是需要用到数值微分的。数值微分的优点是实现简单,一般情况下不太容易出错。而误差反向传播法的实现很复杂,容易出错。所以,经常会比较数值微分的结果和误差反向传播法的结果,以确认误差反向传播法的实现是否正确。确认数值微分求出的梯度结果和误差反向传播法求出的结果是否一致(严格地讲,是非常相近)的操作称为梯度确认(gradient check)。

    import sys, os
    sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
    import numpy as np
    from dataset.mnist import load_mnist
    from two_layer_net import TwoLayerNet# 读入数据
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)x_batch = x_train[:3]
    t_batch = t_train[:3]grad_numerical = network.numerical_gradient(x_batch, t_batch)
    grad_backprop = network.gradient(x_batch, t_batch)for key in grad_numerical.keys():diff = np.average( np.abs(grad_backprop[key] - grad_numerical[key]) )print(key + ":" + str(diff))
    

在这里插入图片描述

通过数值微分和误差反向传播法求出的梯度的差非常小。所以误差反向传播法求出的梯度是正确的。

  1. 使用误差反向传播法的学习

    和之前的实现相比,不同之处仅在于通过误差反向传播法求梯度这一点。

    # coding: utf-8
    import sys, os
    sys.path.append(os.pardir)import numpy as np
    from dataset.mnist import load_mnist
    from two_layer_net import TwoLayerNet# 读入数据
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)network = TwoLayerNet(input_size=784, hidden_size=50, output_size=10)iters_num = 10000
    train_size = x_train.shape[0]
    batch_size = 100
    learning_rate = 0.1train_loss_list = []
    train_acc_list = []
    test_acc_list = []iter_per_epoch = max(train_size / batch_size, 1)for i in range(iters_num):batch_mask = np.random.choice(train_size, batch_size)x_batch = x_train[batch_mask]t_batch = t_train[batch_mask]# 梯度#grad = network.numerical_gradient(x_batch, t_batch)grad = network.gradient(x_batch, t_batch)# 更新for key in ('W1', 'b1', 'W2', 'b2'):network.params[key] -= learning_rate * grad[key]loss = network.loss(x_batch, t_batch)train_loss_list.append(loss)if i % iter_per_epoch == 0:train_acc = network.accuracy(x_train, t_train)test_acc = network.accuracy(x_test, t_test)train_acc_list.append(train_acc)test_acc_list.append(test_acc)print(train_acc, test_acc)
    

在这里插入图片描述

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

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

相关文章

C# 中生成随机数的常用方法

1. 使用 Random 类&#xff08;简单场景&#xff09; 2. 使用 RandomNumberGenerator 类&#xff08;安全场景&#xff09; 3. 生成指定精度的随机小数 C# 中生成随机数的常用方法&#xff1a; 随机数类型实现方式示例代码特点与适用场景随机整数&#xff08;无范围&#xf…

Flink 算子链设计和源代码实现

1、JobGraph &#xff08;JobManager&#xff09; JobGraph 生成时&#xff0c;通过 ChainingStrategy 连接算子&#xff0c;最终在 Task 中生成 ChainedDriver 链表。StreamingJobGraphGeneratorcreateJobGraph() 构建jobGrapch 包含 JobVertex setChaining() 构建算子链isCha…

对接八大应用渠道

背景最近公司想把游戏包上到各个渠道上&#xff0c;因此需要对接各种渠道&#xff0c;渠道如下&#xff0c;oppo、vivo、华为、小米、应用宝、taptap、荣耀、三星等应用渠道 主要就是对接登录、支付接口&#xff08;后续不知道会不会有其他的&#xff09;&#x…

学习:入门uniapp Vue3组合式API版本(17)

42.打包发行微信小程序的上线全流程 域名 配置 发行 绑定手机号 上传 提交后等待&#xff0c;上传 43.打包H5并发布上线到unicloud的前端页面托管 完善配置 unicloud 手机号实名信息不一致&#xff1a;请确保手机号的实名信息与开发者姓名、身份证号一致&#xff0c;请前往开…

SOLIDWORKS材料明细表设置,属于自己的BOM表模板

上一期我们了解了如何在SOLIDWORKS工程图中添加材料明细表?接下来&#xff0c;我们将进行对SOLIDWORKS材料明细表的设置、查看缩略图、模板保存的深度讲解。01 材料明细表设置菜单栏生成表格后左侧菜单栏会显示关于材料明细表的相关设置信息。我们先了解一下菜单栏设置详情&am…

全栈:Maven的作用是什么?本地仓库,私服还有中央仓库的区别?Maven和pom.xml配置文件的关系是什么?

Maven和pom.xml配置文件的关系是什么&#xff1a; Maven是一个构建工具和依赖管理工具&#xff0c;而pom.xml&#xff08;Project Object Model&#xff09;是Maven的核心配置文件。 SSM 框架的项目不一定是 Maven 项目&#xff0c;但推荐使用 Maven进行管理。 SSM 框架的项目可…

超越 ChatGPT:智能体崛起,开启全自主 AI 时代

引言 短短三年,生成式 AI 已从对话助手跨越到能自主规划并完成任务的“智能体(Agentic AI)”时代。这场演进不仅体现在模型规模的提升,更在于系统架构、交互范式与安全治理的全面革新。本文按时间线梳理关键阶段与核心技术,为您呈现 AI 智能体革命的脉络与未来趋势。 1. …

一杯就够:让大脑瞬间在线、让肌肉满电的 “Kick-out Drink” 全解析

一杯就够&#xff1a;让大脑瞬间在线、让肌肉满电的 “Kick-out Drink” 全解析“每天清晨&#xff0c;当闹钟还在哀嚎&#xff0c;你举杯一饮&#xff0c;睡意像被扔出擂台——这&#xff0c;就是 Kick-out Drink 的全部浪漫。”清晨 30 分钟后&#xff0c;250 mL 常温水里溶解…

系统开机时自动执行指令

使用 systemd 创建一个服务单元可以让系统开机时自动执行指令&#xff0c;假设需要执行的指令如下&#xff0c;运行可执行文件&#xff08;/home/demo/可执行文件&#xff09;&#xff0c;并输入参数&#xff08;–input/home/config/demo.yaml&#xff09;&#xff1a; /home/…

Docker 初学者需要了解的几个知识点 (七):php.ini

这段配置是 php.ini 文件中针对 PHP 扩展和 Xdebug 调试工具的设置&#xff0c;主要用于让 PHP 支持数据库连接和代码调试&#xff08;尤其在 Docker 环境中&#xff09;&#xff0c;具体解释如下&#xff1a;[PHP] extensionpdo_mysql extensionmysqli xdebug.modedebug xdebu…

【高阶版】R语言空间分析、模拟预测与可视化高级应用

随着地理信息系统&#xff08;GIS&#xff09;和大尺度研究的发展&#xff0c;空间数据的管理、统计与制图变得越来越重要。R语言在数据分析、挖掘和可视化中发挥着重要的作用&#xff0c;其中在空间分析方面扮演着重要角色&#xff0c;与空间相关的包的数量也达到130多个。在本…

dolphinscheduler中一个脚本用于从列定义中提取列名列表

dolphinscheduler中&#xff0c;我们从一个mysql表导出数据&#xff0c;上传到hdfs, 再创建一个临时表&#xff0c;所以需要用到列名定义和列名列表。 原来定义两个变量&#xff0c;不仅繁锁&#xff0c;还容易出现差错&#xff0c;比如两者列序不对。 所以考虑只定义列定义变量…

JavaWeb(苍穹外卖)--学习笔记16(定时任务工具Spring Task,Cron表达式)

前言 本篇文章是学习B站黑马程序员苍穹外卖的学习笔记&#x1f4d1;。我的学习路线是Java基础语法-JavaWeb-做项目&#xff0c;管理端的功能学习完之后&#xff0c;就进入到了用户端微信小程序的开发&#xff0c;用户端开发的流程大致为用户登录—商品浏览&#xff08;其中涉及…

灵敏度,精度,精确度,精密度,精准度,准确度,分辨率,分辨力——概念

文章目录前提总结前提 我最近在整理一份数据指标要求的时候&#xff0c;总是混淆这几个概念&#xff1a;灵敏度&#xff0c;精度&#xff0c;精确度&#xff0c;精密度&#xff0c;精准度&#xff0c;准确度&#xff0c;分辨率&#xff0c;分辨力&#xff0c;搜了一些文章&…

python-异常(笔记)

#后续代码可以正常运行 try:f open("xxx.txt","r",encodingutf-8)except:print("except error")#捕获指定异常&#xff0c;其他异常报错程序中止&#xff0c;管不到 try:print(name) except NameError as you_call:print("name error"…

[lvgl_player] 用户界面(LVGL) | 播放器核心设计

docs&#xff1a;基于LVGL的音乐播放器 本项目是为嵌入式设备设计的音乐播放系统&#xff0c;采用LVGL图形库构建用户界面。 系统支持播放WAV格式音频文件&#xff0c;具备播放列表管理功能&#xff0c;可实现播放/暂停控制、曲目切换等核心操作。 用户可通过交互界面实时调…

数据赋能(354)——数据分析——多角度分析原则

概述重要性如下&#xff1a;获得全面理解&#xff1a;多角度分析原则避免仅从单一角度解读数据&#xff0c;从不同角度、不同维度对数据进行分析&#xff0c;以获得更全面的理解。发现潜在规律&#xff1a;通过多角度分析&#xff0c;发现数据中的潜在规律和趋势&#xff0c;为…

【华为机试】127. 单词接龙

文章目录127. 单词接龙描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a;解题思路算法分析问题本质分析单向BFS算法详解双向BFS算法详解邻居单词生成过程算法流程图边界情况分析各种解法对比时间复杂度分析空间复杂度分析关键优化点实际应用场景图构建策略双向BFS优化…

仿艾莫迅MODBUS调试工具写一个上位机

公司采购了一个夹具&#xff0c;项目负责人想要试探这个夹具的性能&#xff0c;于是想要我这边写一个烤机的程序&#xff0c;小编结合官网资料 https://wiki.amsamotion.com/?title196&doc222查看其pdf说明文档和调试工具并按照其工具写一个烤机上位机根据项目负责人的要求…

云展厅:开启数字化展示新时代

在科技飞速发展的今天&#xff0c;数字化浪潮正席卷各个行业&#xff0c;展览展示领域也不例外。云展厅作为一种全新的展览形式&#xff0c;正逐渐崭露头角&#xff0c;以其独特的优势和创新的技术应用&#xff0c;为观众带来前所未有的观展体验&#xff0c;也为企业和机构提供…