连载|神经网络(下)

简介: 连载|神经网络(下)

误差逆传播算法(BP神经网络)

BP神经网络是一种按误差反向传播(简称误差反传)训练的多层前馈网络,其算法称为BP算法,它的基本思想是梯度下降法,利用梯度搜索技术,以期使网络的实际输出值和期望输出值的误差均方差为最小。

基本BP算法包括信号的前向传播和误差的反向传播两个过程。即计算误差输出时按从输入到输出的方向进行,而调整权值和阈值则从输出到输入的方向进行。


下面让我们从数学原理上来看一下BP算法是怎样工作的。


我们给定训练集image.png输入示例有d个属性,输出是一个l维的实值向量,转换成如下图所示的前馈神经网络的输入输出的形式,该神经网络拥有d个输入神经元、l个输出神经元以及q个隐藏神经元。

98.png

image.png

image.png

对于上图中的神经网络我们需要确定输入层到隐层的d*q个权值、隐层到输出层的q*l个权值、q个隐层神经元的阈值、l个输出层神经元的阈值,一共则是(d+l+1)*q+l个参数需要确定。


和之前的参数更新方式一样,我们对于任意参数v的更新方式可以表示为如下的形式:

image.png

image.png

image.png

我们在前面假设神经元内都是sigmoid函数,并且sigmoid函数有一个很重要的导数性质如下:

image.png

因此我们可以根据式(1)(2)得到如下的式子image.png

image.png

我们把式子(5)(6)带入(4)式再带入(3)式可以得到如下的参数更新公式:

image.png

类似的我们也可以得到其他参数的更新公式:

image.png

以上便是我们BP算法的推导过程,在整个过程中我们先通过输出层得到误差,再从误差入手进行反向传播更新参数就OK了。


注:通常我们把学习率设置为0.1,学习率控制着算法的每一轮迭代时的更新步长,若太大则容易震荡,太小则收敛速度又会过慢,有时我们会在不同的网络层之间设定不同的学习率。


下面给出BP神经算法的简单代码实现(带有隐层的神经网络):

import numpy as np
def nonlin(x, deriv=False):
    if deriv == True:
        # 如果deriv=True我们就进行求导
        return x * (1 - x)
    else:
        # 返回sigmoid函数
        return 1 / (1 + np.exp(-x))
# 给定输入输出
x = np.array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
y = np.array([[0, 1, 1, 0]]).T
# 均值与标准差
mu, sigma = 0, 0.1
w0 = np.random.normal(mu, sigma, (3, 5))
w1 = np.random.normal(mu, sigma, (5, 1))
# 定义迭代次数
iter_size = 1000
# 定义学习率
lr = 1
for i in range(iter_size):
    # 输入层
    L0 = x
    # 隐藏层(输入层和隐藏层间权重为w0)
    L1 = nonlin(L0.dot(w0))
    # 输出层(隐藏层和输出层间权重为w1)
    L2 = nonlin(L1.dot(w1))
    # 损失函数
    L2_loss = L2 - y
    # 输出层的导数
    L2_delta = L2_loss * nonlin(L2, True)
    # 隐藏层到输出层的梯度
    grad1 = L1.T.dot(L2_delta)
    # 隐藏层到输出层参数更新
    w1 -= grad1 * lr
    # L1对L2_loss贡献了多少,反过来传梯度时就要乘以这个权重
    L1_loss = L2_delta.dot(w1.T)
    # 隐藏层的导数
    L1_delta = L1_loss * nonlin(L1, True)
    # 输入层到隐藏层的梯度
    grad0 = L0.T.dot(L1_delta)
    # 输入层到隐藏层的参数更新
    w0 -= grad0 * lr
print(L2)


相关文章
|
Linux 内存技术
U-BOOT小全(六):BootLoader源码(UBoot-Kernel 1)
U-BOOT小全(六):BootLoader源码(UBoot-Kernel 1)
229 0
|
9月前
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
255 2
|
存储 开发框架 数据可视化
深入解析Android应用开发中的四大核心组件
本文将探讨Android开发中的四大核心组件——Activity、Service、BroadcastReceiver和ContentProvider。我们将深入了解每个组件的定义、作用、使用方法及它们之间的交互方式,以帮助开发者更好地理解和应用这些组件,提升Android应用开发的能力和效率。
1169 5
|
数据可视化 数据挖掘 定位技术
Python和Geopandas进行地理数据可视化
【10月更文挑战第22天】本文介绍了如何使用Python和Geopandas进行地理数据可视化和分析,涵盖从准备工作、加载数据、数据探索与处理、地理数据可视化、空间分析与查询到交互式地理数据可视化等内容。通过丰富的代码示例和案例演示,帮助读者掌握地理数据分析的基本方法,为实际应用提供支持。
967 19
|
存储 分布式计算 大数据
【Flume的大数据之旅】探索Flume如何成为大数据分析的得力助手,从日志收集到实时处理一网打尽!
【8月更文挑战第24天】Apache Flume是一款高效可靠的数据收集系统,专为Hadoop环境设计。它能在数据产生端与分析/存储端间搭建桥梁,适用于日志收集、数据集成、实时处理及数据备份等多种场景。通过监控不同来源的日志文件并将数据标准化后传输至Hadoop等平台,Flume支持了性能监控、数据分析等多种需求。此外,它还能与Apache Storm或Flink等实时处理框架集成,实现数据的即时分析。下面展示了一个简单的Flume配置示例,说明如何将日志数据导入HDFS进行存储。总之,Flume凭借其灵活性和强大的集成能力,在大数据处理流程中占据了重要地位。
321 3
|
安全 Nacos 数据安全/隐私保护
【技术干货】破解Nacos安全隐患:连接用户名与密码明文传输!掌握HTTPS、JWT与OAuth2.0加密秘籍,打造坚不可摧的微服务注册与配置中心!从原理到实践,全方位解析如何构建安全防护体系,让您从此告别数据泄露风险!
【8月更文挑战第15天】Nacos是一款广受好评的微服务注册与配置中心,但其连接用户名和密码的明文传输成为安全隐患。本文探讨加密策略提升安全性。首先介绍明文传输风险,随后对比三种加密方案:HTTPS简化数据保护;JWT令牌减少凭证传输,适配分布式环境;OAuth2.0增强安全,支持多授权模式。每种方案各有千秋,开发者需根据具体需求选择最佳实践,确保服务安全稳定运行。
1390 0
|
Windows
如何使用GUID硬盘分区格式安装新windows系统
这篇文章介绍了全局唯一标识分区表(GUID Partition Table, GPT)与主引导记录(Master Boot Record, MBR)两种硬盘分区格式的区别。
1036 0
|
机器学习/深度学习 自然语言处理 算法
用Python实现一个基础的神经网络模型
用Python实现一个基础的神经网络模型
634 0
|
Java BI API
Java开发的开源SaaS进销存,便于二次开发
越来越多的企业选择使用Java开发的SaaS进销存软件来管理业务流程。Java作为一种面向对象的编程语言,拥有广泛的应用领域。其跨平台性、高可靠性、面向对象、丰富的API以及易于调试等特点,使得Java成为许多SaaS进销存软件的首选。
470 0
Java开发的开源SaaS进销存,便于二次开发