11-08 周三 图解机器学习之实现逻辑异或,理解输出层误差和隐藏层误差项和动量因子

11-08 周三 图解机器学习之实现逻辑异或,理解输出层误差和隐藏层误差项
时间版本修改人描述
2023年11月8日14:36:36V0.1宋全恒新建文档

简介

 最近笔者完成了《图解机器学习》这本书的阅读,由于最近深度学习网络大行其是,所以也想要好好的弄清楚神经网络的工作原理。比如说训练、比如说验证,比如说权重更新,之前也曾经写过两个博客来描述感知机和BP算法示意。

  • 10-09 周一 图解机器学习之深度学习感知机学习
  • 11-06 周一 神经网络之前向传播和反向传播代码实战

 反向传播这个博客里主要通过一个样本,来不断的更新参数,但实际的神经网络结构是不会像博客中name简单的,因此还是需要给出一个计算公式的。在阅读图解机器学习P169页,如下代码时,自己没有看懂:

        # 计算输出层误差for k in range(self.no):error = targets[k] - self.ao[k]output_deltas[k] = dsigmoid(self.ao[k]) * error# 计算隐藏层的误差hidden_deltas = [0.0]*self.nhfor j in range(self.nh):error = 0for k in range(self.no):error = error + output_deltas[k] * self.wo[j][k]hidden_deltas[j] = dsigmoid(self.ah[j]) * error# 更新输出层权重for j in range(self.nh):for k in range(self.no):change = output_deltas[k]*self.ah[j]self.wo[j][k] = self.wo[j][k] + N*change + M * self.co[j][k]

 上述在计算过程中求出了输出层误差和隐藏层误差项。如何理解这个代码片段呢?

完整代码

import math
import random
import string
random.seed(0)# 生成区间[a, b)内的随机数
def rand(a, b):return (b - a) *random.random() + a# 生成I*J大小的矩阵, 默认零矩阵
def makeMatrix(I, J, fill=0.0):m = []for i in range(I):m.append([fill]*J)return m# 函数 sigmoid, 采用tanh函数, 比起标准的1/(1+exp(-x))更好
def sigmoid(x):return math.tanh(x)# 函数sigmoid的派生函数 tanh(x)' = 1 - tanh(x)^2
def dsigmoid(x):return 1.0 - x**2class BPNeuralNet:'''建立三层反向传播神经网络'''def __init__(self, ni, nh, no) -> None:self.ni = ni + 1self.nh = nhself.no = no# 激活神经网络的所有节点self.ai = [1.0]* self.niself.ah = [1.0]*self.nhself.ao = [1.0]* self.no# 建立权重矩阵self.wi = makeMatrix(self.ni, self.nh)self.wo = makeMatrix(self.nh, self.no)# 设为随机值for i in range(self.ni):for j in range(self.nh):self.wi[i][j] = rand(-0.2, 0.2)for i in range(self.nh):for j in range(self.no):self.wo[i][j] = rand(-2.0, 2.0)# 建立动量因子self.ci = makeMatrix(self.ni, self.nh)self.co = makeMatrix(self.nh, self.no)# 前向传播,得到预计的输出。# 各个神经元的输出分别位于self.ah 和self.ao# inputs 代表一个样本def fp(self, inputs):if len(inputs) != self.ni -1:raise ValueError('与输入层节点数不符错误!')for i in range(self.ni-1):self.ai[i] = inputs[i]for j in range(self.nh):sum = 0.0for i in range(self.ni):sum += self.ai[i]* self.wi[i][j]self.ah[j] = sigmoid(sum)# 激活输出层for j in range(self.no):sum = 0for i in range(self.nh):sum += self.ah[i]*self.wo[i][j]self.ao[j] = sigmoid(sum)return self.ao[:]# N 学习速率 learning factor# M 动量因子 momentum factor# 基本思路是直接求出每个神经元的误差def back_propagate(self, targets, N, M):'''反向传播'''if len(targets) != self.no:raise ValueError("与输出层节点数不符!")output_deltas = [0.0] * self.no# 计算输出层误差for k in range(self.no):error = targets[k] - self.ao[k]output_deltas[k] = dsigmoid(self.ao[k]) * error# 计算隐藏层的误差hidden_deltas = [0.0]*self.nhfor j in range(self.nh):error = 0for k in range(self.no):error = error + output_deltas[k] * self.wo[j][k]hidden_deltas[j] = dsigmoid(self.ah[j]) * error# 更新输出层权重for j in range(self.nh):for k in range(self.no):change = output_deltas[k]*self.ah[j]self.wo[j][k] = self.wo[j][k] + N*change + M * self.co[j][k]self.co[j][k] = change# 更新输入层权重for i in range(self.ni):for j in range(self.nh):change=hidden_deltas[j]*self.ai[i]self.wi[i][j] += N * change + M * self.ci[i][j]self.ci[i][j] = changeerror = 0.0for k in range(len(targets)):error = error + 0.5*(targets[k]-self.ao[k])**2return errordef test(self, patterns):for p in patterns:print(p[0], '->', self.fp(p[0]))def weights(self):print('输入层权重')for i in range(self.ni):print(self.wi[i])print()print("输出层权重")for j in range(self.nh):print(self.wo[j])def train(self, patterns, iterations=100000, N =0.5, M=0.1):for i in range(iterations):error = 0.0for p in patterns:inputs = p[0]targets = p[1]self.fp(inputs)error = error + self.back_propagate(targets, N, M)if i % 100 ==0:print('计算误差的值是: %-.5f'%error)def trainprog():# BP神经网络学习逻辑异或pat = [[[0, 0], [0]],[[0, 1], [1]],[[1, 0], [1]],[[1, 1], [0]]]# 创建一个神经网络,输入层两个节点, 输出层两个节点,输出层一个节点:net = BPNeuralNet(2, 3, 1)net.train(pat)# 测试训练的成果net.test(pat)if __name__ == '__main__':trainprog()

 上述代码在理解上并不复杂,主要是通过三层神经网络来拟合逻辑异或运算。采用的是个案更新的策略来更新权重参数。

权重更新

基础知识

 多层前馈神经网络。

 一个示例: 奶酪是否喜爱。

 为此我们构建一个神经网络:

激活函数

  激活函数

  • 指数函数
  • sigmoid
  • 逻辑回归

 校正因子的概念如下:

 权重更新的策略有多种:

  • 个案更新 case-based 更容易得到准确的结果。
  • 批量更新 batch 优点就是比较快,加速。

迭代终止条件

 迭代终止条件:

  • 当权重和偏置差异与上一次非常小
  • 误差达到之前设置的阈值
  • 运行次数

存疑代码

        # 计算输出层误差for k in range(self.no):error = targets[k] - self.ao[k]output_deltas[k] = dsigmoid(self.ao[k]) * error# 计算隐藏层的误差hidden_deltas = [0.0]*self.nhfor j in range(self.nh):error = 0for k in range(self.no):error = error + output_deltas[k] * self.wo[j][k]hidden_deltas[j] = dsigmoid(self.ah[j]) * error# 更新输出层权重for j in range(self.nh):for k in range(self.no):change = output_deltas[k]*self.ah[j]self.wo[j][k] = self.wo[j][k] + N*change + M * self.co[j][k]self.co[j][k] = change# 更新输入层权重for i in range(self.ni):for j in range(self.nh):change=hidden_deltas[j]*self.ai[i]self.wi[i][j] += N * change + M * self.ci[i][j]self.ci[i][j] = change

 上述分别计算出了输出层的误差项和输出层的误差项。按照上述代码理解,前两个for循环用于计算误差项,后两个循环用来更新权重,顺序从后向前,这也是反向传播得名的由来。关键是为什么输出层的误差是这么得来的呢?

 参考 BP神经网络-第6集 反向传播误差,调整全部权重,这对于理解是非常关键的。

 我们以同样的方式,就可以得到每个神经元的误差。如下图

 可以采用矩阵相乘的方法

 权重通过矩阵乘表示。

gpt辅助理解

 自己还是无法理解,但感觉输出层的误差项与选用的损失函数密切相关,因此,笔者询问了GPT,得到了如下的结果:

  • 为什么要乘以激活函数的导数?
  • 交叉熵损失函数的输出层误差项
  • 均方差 输出层误差项:

 由此,我们可以得到如下的图示:

在计算h1节点的误差项时,输出层两个误差项以w7 和 w8进行作用,进而可以得到h1神经元的误差项:

errorh1=w7*e1 + w8 * e2。 依次可以得到h1, h2, h3神经元的误差项损失。

动量因子

 代码片段,其实整体贯彻了P166 图解机器学习图13.10,

 相互映照,也可以通过代码来理解上述的过程:

 代码参见 11-06 周一 神经网络之前向传播和反向传播代码实战

总结

 这部分的代码片段比之前的全部手动计算权重更新的过程复杂一些,因为抽象出了输出层误差项和隐藏层误差项,代码的抽象知识更加复杂了,但 BP神经网络-第6集 反向传播误差,调整全部权重则直接给出了误差项的矩阵乘表示,而这种方式,应该也是机器学习库中默认使用的方式吧。总之,这篇文章试图解释《图解机器学习》中第13章深度学习网络的代码,弄清楚其中权重更新的方式,包括为什么使用动量因子进行更新这种优化技术。希望读者能够读懂,进而在自己的工程实践中使用深度学习解决自己的问题。

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

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

相关文章

Effective C++ 系列和 C++ Core Guidelines 如何选择?

Effective C 系列和 C Core Guidelines 如何选择? 如果一定要二选一,我会选择C Core Guidelines。因为它是开源的,有300多个贡献者,而且还在不断更新,意味着它归纳总结了最新的C实践经验。最近很多小伙伴找我&#xff…

基于springboot实现智慧外贸平台系统【项目源码+论文说明】计算机毕业设计

基于springboot实现智慧外贸平台系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把智慧外贸管理与现在网络相结合,利用java技术建设智慧外贸平台,实现智慧外贸的信息化。则对于进一步提高智慧外贸管理发展,丰富智慧外贸管理经验能…

Java进阶篇--Executors类创建常见线程池

目录 线程池架构 newSingleThreadExecutor newFixedThreadPool newCachedThreadPool newScheduledThreadPool Executors和ThreaPoolExecutor创建线程池的区别 两种提交任务的方法 线程池架构 线程池是一种线程管理的机制,用于维护和复用线程,以…

Leetcode2834. 找出美丽数组的最小和

Every day a Leetcode 题目来源:2834. 找出美丽数组的最小和 解法1:贪心 从最小正整数 1 开始枚举,设当前数为 num,如果 nums 里没有 target - num,就说明可以添加 num,依次填满直到有 n 个数即可。 用…

【k8s-1】基于docker Desktop一键式搭建k8s环境

在docker desktop中一键启动k8s环境很简单。 下面介绍如何启动dashboard,dashboard仪表盘是新手学习k8s至关重要的一个工具。 1、配置控制台 kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.1/aio/deploy/recommended.yaml 2、开…

k8s的安装部署,详细过程展示(保姆级安装教程)

k8s应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其它技术的参与 缺点:不能为应用程序定义资源使用…

Java面向对象(进阶)-- 面向对象特征之三:多态性

文章目录 一、多态的形式和体现(1)为什么需要多态性(polymorphism)?(2) 对象的多态性 二、 多态的理解(1)如何理解多态性(2)Java中多态性的体现(3&#xff09…

数据分析实战 | KNN算法——病例自动诊断分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 九、模型调参 十、模型改进 十一、模型预测 一、数据及分析对象 CSV文件——“bc_data.csv” 数据集链接:https://dow…

LeetCode146.LRU缓存

写了一个小时,终于把示例跑过了,没想到啊提交之后第19/22个测试用例没过 我把测试用例的输出复制在word上看看和我的有什么不同,没想到有18页的word,然后我一直检查终于找出了问题,而且这个bug真的太活该了&#xff0c…

Rocky Linux 配置邮件发送

Rocky Linux 配置邮件发送 使用自己的有邮箱发送 第一步-开启STMP授权 首先要开启STMP授权码,以QQ邮箱为例 第二步-下载安装包 说明一点不用命令行安装也可以,在命令行中输入会提示你是否安装s-nail,一直y即可 mail下载必须要的安装包 …

在ubuntu sudo apt-get update 更新报错

sudo apt-get update 更新报错 解决办法: 用你自己的key 根据上图自己找 sudo gpg --keyserver keyserver.ubuntu.com --recv-keys **********运行完成有一个ok 见下图 运行命令,中间的还是上面的key复制下来即可 sudo gpg --export --armor **********…

Android 多点触控

三种类型 :接力型 /配合型 /单独型 单点触控 package com.example.myapplication.viewimport android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.util.AttributeSet import android.view.MotionEvent import android.vi…

10 # 手写 every 方法

every 使用 every() 方法测试一个数组内的所有元素是否都能通过指定函数的测试。它返回一个布尔值。 ele&#xff1a;表示数组中的每一个元素index&#xff1a;表示数据中元素的索引array&#xff1a;表示数组 <script>var arr [1, 3, 5, 7, 8];var result arr.ever…

win 命令替代鼠标的操作

操作方式都是在 winR 输入框输入或者终端输入 1、快速打开 控制面板 运行control 2、快速打开 电源选项 运行powercfg.cpl 3、快速打开 网络连接 运行ncpa.cpl 4、快速打开 程序和功能 运行appwiz.cpl 5、快速打开 Windows Defender防火墙 运行Firewall.cpl 6、快速打开 鼠标 …

Matlab的多项式留数与极点的计算

Matlab的多项式留数与极点的计算 以下面的多项式为例&#xff1a; 运算代码&#xff1a; clc clear closesyms p % 定义多项式 Zp(5*p^571*p^370*p)/(2*p^635*p^4117*p^236); % 提取分子与分母 [I,D]numden(Zp); Idouble(coeffs(I,p,"All"));%分子 Ddouble(coeffs…

多目标优化框架

随着模型越来越复杂&#xff0c;优化目标越来越多&#xff0c;传统算法都慢慢地无法胜任复杂优化任务&#xff0c;更为智能的优化方法也就应运而生了。其中有一类是进化优化算法&#xff0c;这类算法的思想来源是自然界的“优胜劣汰”法则&#xff0c;通过不停地保留好的个体最…

大漠插件(二、Qt使用插件时注意事项)

本章目的 在上篇已经注册完毕大漠&#xff0c;那么怎么使用大漠来制作脚本&#xff0c;我选择了我最熟悉的Qt来开发&#xff0c;毕竟只是小软件&#xff0c;用脚本或者c都差不了多少。本章就是开发途中的一些坑。 本人开发环境是 win11 64、Qt 5.15.2安装了5.10.0的msvc2015 32…

Linux - 基础IO(Linux 当中的文件,文件系统调用接口,文件描述符)- 上篇

前言 首先&#xff0c;关于文件我们最先要理解的是&#xff0c;文件不仅仅存储的是数据&#xff0c;一个文件包括 内容 数据。内容好理解&#xff0c;就是我们先要这文件存储哪一些数据&#xff0c;这些数据就是文件的内容。 但是&#xff0c;在计算机当中&#xff0c;有两种…

【数据结构】树与二叉树(十):二叉树的先序遍历(非递归算法NPO)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

WAF入侵防御系统标准检查表

软件开发全文档获取&#xff1a;进主页