news 2026/4/15 6:54:09

误差反向传播法(误差反向传播法的实现)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
误差反向传播法(误差反向传播法的实现)

误差反向传播法的实现

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

神经网络学习的全貌图

在进行具体的实现之前,我们再来确认一下神经网络学习的全貌图。神
经网络学习的步骤如下所示。

前提

神经网络中有合适的权重和偏置,调整权重和偏置以便拟合训练数据的
过程称为学习。神经网络的学习分为下面4 个步骤。

步骤1(mini-batch)

从训练数据中随机选择一部分数据。

步骤2(计算梯度)

计算损失函数关于各个权重参数的梯度。

步骤3(更新参数)

将权重参数沿梯度方向进行微小的更新。

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

现在来进行神经网络的实现。这里我们要把2层神经网络实现为TwoLayerNet。
首先,将这个类的实例变量和方法整理成表5-1 和表5-2。

这个类的实现稍微有一点长,但是内容和4.5 节的学习算法的实现有很
多共通的部分,不同点主要在于这里使用了层。通过使用层,获得识别结果
的处理(predict())和计算梯度的处理(gradient())只需通过层之间的传递就能完成。下面是TwoLayerNet的代码实现。

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 OrderedDict class 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 grads def gradient(self, x, t): # forward self.loss(x, t) # backward dout = 1 dout = self.lastLayer.backward(dout) layers = list(self.layers.values()) layers.reverse() for layer in layers: dout = layer.backward(dout) # 设定 grads = {} grads['W1'] = self.layers['Affine1'].dW grads['b1'] = self.layers['Affine1'].db grads['W2'] = self.layers['Affine2'].dW grads['b2'] = self.layers['Affine2'].db return grads

请注意这个实现中的粗体字代码部分,尤其是将神经网络的层保存为
OrderedDict这一点非常重要。OrderedDict是有序字典,“有序”是指它可以
记住向字典里添加元素的顺序。因此,神经网络的正向传播只需按照添加元
素的顺序调用各层的forward()方法就可以完成处理,而反向传播只需要按
照相反的顺序调用各层即可。因为Affine层和ReLU层的内部会正确处理正
向传播和反向传播,所以这里要做的事情仅仅是以正确的顺序连接各层,再
按顺序(或者逆序)调用各层。

像这样通过将神经网络的组成元素以层的方式实现,可以轻松地构建神
经网络。这个用层进行模块化的实现具有很大优点。因为想另外构建一个神
经网络(比如5 层、10 层、20 层……的大的神经网络)时,只需像组装乐高
积木那样添加必要的层就可以了。之后,通过各个层内部实现的正向传播和
反向传播,就可以正确计算进行识别处理或学习所需的梯度。

误差反向传播法的梯度确认

到目前为止,我们介绍了两种求梯度的方法。一种是基于数值微分的方
法,另一种是解析性地求解数学式的方法。后一种方法通过使用误差反向传
播法,即使存在大量的参数,也可以高效地计算梯度。因此,后文将不再使
用耗费时间的数值微分,而是使用误差反向传播法求梯度。

数值微分的计算很耗费时间,而且如果有误差反向传播法的(正确的)
实现的话,就没有必要使用数值微分的实现了。那么数值微分有什么用呢?
实际上,在确认误差反向传播法的实现是否正确时,是需要用到数值微分的。

数值微分的优点是实现简单,因此,一般情况下不太容易出错。而误差
反向传播法的实现很复杂,容易出错。所以,经常会比较数值微分的结果和
误差反向传播法的结果,以确认误差反向传播法的实现是否正确。确认数值
微分求出的梯度结果和误差反向传播法求出的结果是否一致(严格地讲,是
非常相近)的操作称为梯度确认(gradient check)。梯度确认的代码实现如下
所示(源代码在ch05/gradient_check.py中)。

importsys,os sys.path.append(os.pardir)importnumpyasnpfromdataset.mnistimportload_mnistfromtwo_layer_netimportTwoLayerNet# 读入数据(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)# 求各个权重的绝对误差的平均值forkeyingrad_numerical.keys():diff=np.average(np.abs(grad_backprop[key]-grad_numerical[key]))print(key+":"+str(diff))

和以前一样,读入MNIST数据集。然后,使用训练数据的一部分,确
认数值微分求出的梯度和误差反向传播法求出的梯度的误差。这里误差的计
算方法是求各个权重参数中对应元素的差的绝对值,并计算其平均值。运行
上面的代码后,会输出如下结果。

b1:9.70418809871e-13 W2:8.41139039497e-13 b2:1.1945999745e-10 W1:2.2232446644e-13

从这个结果可以看出,通过数值微分和误差反向传播法求出的梯度的差
非常小。比如,第1 层的偏置的误差是9.7 e − 13 ( 0.00000000000097 ) 9.7e-13(0.00000000000097)9.7e130.00000000000097。这样一来,
我们就知道了通过误差反向传播法求出的梯度是正确的,误差反向传播法的
实现没有错误。

数值微分和误差反向传播法的计算结果之间的误差为0 是很少见的。
这是因为计算机的计算精度有限(比如,32 位浮点数)。受到数值精
度的限制,刚才的误差一般不会为0,但是如果实现正确的话,可
以期待这个误差是一个接近0 的很小的值。如果这个值很大,就说
明误差反向传播法的实现存在错误。

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

最后,我们来看一下使用了误差反向传播法的神经网络的学习的实现。
和之前的实现相比,不同之处仅在于通过误差反向传播法求梯度这一点。这
里只列出了代码,省略了说明(源代码在ch05/train_neuralnet.py中)。

importsys,os sys.path.append(os.pardir)importnumpyasnpfromdataset.mnistimportload_mnistfromtwo_layer_netimportTwoLayerNet# 读入数据(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=10000train_size=x_train.shape[0]batch_size=100learning_rate=0.1train_loss_list=[]train_acc_list=[]test_acc_list=[]iter_per_epoch=max(train_size/batch_size,1)foriinrange(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.gradient(x_batch,t_batch)# 更新forkeyin('W1','b1','W2','b2'):network.params[key]-=learning_rate*grad[key]loss=network.loss(x_batch,t_batch)train_loss_list.append(loss)ifi%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)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 0:37:59

内网横向渗透:攻击者的内网扩张术与企业全维度防御实战指南

在网络攻击攻防对抗日趋激烈的当下,企业外网边界防御体系(如防火墙、WAF、蜜罐)的不断完善,让攻击者突破外网的难度大幅提升。但一旦攻击者通过钓鱼邮件、漏洞利用、远程办公入口等方式实现初始访问,后续的内网横向渗透…

作者头像 李华
网站建设 2026/4/13 12:54:58

计算机毕设java的停车场管理系统 基于Java技术的智能停车场管理系统开发 Java驱动的停车场综合管理平台设计与实现

计算机毕设java的停车场管理系统0k5o89 (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。随着城市化进程的加速,车辆数量不断增加,停车场管理成为城市交通管…

作者头像 李华
网站建设 2026/4/12 21:26:26

揭秘ES的BKD树索引:多维数据查询的加速引擎

在Elasticsearch的索引体系中,倒排索引(Inverted Index)是全文检索的基石,但面对数值范围查询、地理空间搜索等场景时,其性能短板逐渐显现。例如,当用户需要查询"价格在1000-5000元之间的商品"或…

作者头像 李华
网站建设 2026/4/8 10:27:39

用Qwen3-1.7B做AI助手,效果惊艳且成本极低

用Qwen3-1.7B做AI助手,效果惊艳且成本极低 1. 为什么你需要一个“能思考”的轻量级AI助手? 你有没有遇到过这些情况: 想在公司内部搭个智能客服,但发现主流大模型动不动就要24GB显存,连RTX 4090都跑得吃力&#xff…

作者头像 李华
网站建设 2026/4/14 15:42:42

开发技能学习打卡工具,设定技能学习时长,(如每天学一小时python),记录学习内容,时长,生成学习时长趋势图,连续打卡奖励标记。

技能学习打卡工具 - 全栈开发实践1. 实际应用场景描述本工具面向程序员、设计师、产品经理、学生等技能学习者,提供游戏化的学习打卡体验。在知识爆炸的时代,终身学习已成为必然,但坚持学习却是最难的挑战。典型使用场景:- 程序员…

作者头像 李华
网站建设 2026/4/13 6:12:57

用Paraformer做语音转写,长音频自动切分加标点超方便

用Paraformer做语音转写,长音频自动切分加标点超方便 关键词:Paraformer、语音识别、ASR、长音频处理、Gradio、离线语音转文字、标点预测、VAD端点检测 摘要:本文手把手带你用Paraformer-large离线语音识别镜像完成高质量中文语音转写。无需…

作者头像 李华