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…

使用Grafana与MySQL监控监控网络延迟

文章目录 前言python程序使用Grafana步骤1:安装和配置 Grafana步骤2:配置 Grafana 数据源步骤3:创建 Grafana 仪表盘步骤4:将 Grafana 仪表盘嵌入到博客中 前言 在网络应用中,网络延迟是一个重要的指标,它…

基于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…

说说 React 性能优化的手段有哪些?

一、是什么 React凭借virtual DOM和diff算法拥有高效的性能,但是某些情况下,性能明显可以进一步提高 在前面文章中,我们了解到类组件通过调用setState方法, 就会导致render,父组件一旦发生render渲染,子组…

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 **********…

【华为OD机试AB高分必刷题目】拆分(Python-贪心算法实现)

🚀你的旅程将在这里启航!本专栏所有题目均包含优质解题思路,高质量解题代码,详细代码讲解,助你深入学习,高分通过! 文章目录 【华为OD机试AB高分必刷题目】拆分(Python-贪心算法实现)题目描述解题思路Python题解代码代码OJ评判结果代码讲解寄语【华为OD机试AB高分必刷…

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…

HTTPS 的工作原理是什么?

HTTPS(HyperText Transfer Protocol Secure)是一种通过加密和认证保护数据传输安全的通信协议。它是基于传统的 HTTP 协议,通过使用 SSL(Secure Sockets Layer)或 TLS(Transport Layer Security&#xff09…

mysql explain extra值枚举

Extra 值说明Using index仅使用索引进行数据查询Using where在取得所需数据前使用了 WHERE 子句进行过滤Using temporary使用了临时表来保存中间结果Using filesort查询中使用了文件排序Using join buffer告诉MySQL在内存中建立了一个表连接缓冲区以容纳连接类型为索引的行。Im…

CHATGPT----自然辩证法分析

CHATGPT----自然辩证法的要素,结构与功能 Chatgpt的要素组成: ChatGPT的构成主要包括语言模型、对话管理、知识库和用户接口等几个方面。 语言模型:ChatGPT的核心是语言模型,它是一种基于深度学习技术的自然语言处理模型&#…

IntelliJ IDEA 2023.2.1 (Ultimate Edition) 版本 Git 如何找回被 Drop Commit 的提交记录

本心、输入输出、结果 文章目录 IntelliJ IDEA 2023.2.1 (Ultimate Edition) 版本 Git 如何找回被 Drop Commit 的提交记录前言查询 reflog 日志通过 Git Reset HEAD (hard) 找回已经 Drop Commit 的提交记录Git Reset HEAD (hard) 模式和 mixed 模式有啥区别git reset --h…

10 # 手写 every 方法

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