BP神经网络(Back Propagation Neural Network)算法原理推导与Python实现详解

简介: BP神经网络(Back Propagation Neural Network)算法原理推导与Python实现详解

正文


##BP神经网络算法推导

给定训练集:

D={(x1,y1),(x2,y2),...,(xm,ym)},xiRI,yiRO

即数据有D 个特征,标签为O 维实值向量。


因此,我们定义一个拥有I 个输入层神经元、O个输出层神经元的神经网络,且设该网络的隐藏层神经元个数为H。

其中,隐藏层第h 个神经元的阀值用γ h 表示,输出层第o 个神经元的阀值用θ  表示。

输入层第i ii个神经元与隐藏层第h hh个神经元之间的连接权重为ν i h,记隐藏层第h hh个神经元接收到的输入为α h = ∑ i = 1 I ν i h x i  

隐藏层第h hh个神经元与输出层第o oo个神经元之间的连接权重为ω h o ,记输出层第o oo个神经元接收到的输入为β o = ∑ h = 1 H ω h o b h 其中b h 为隐藏层第h 个神经元的输出。

假设隐藏层和输出层都使用Sigmoid函数作为激活函数

Sigmoid函数:

5.png

对于训练集中的一个训练例k :6.png假设神经网络的输出为7.png,则有:

8.png

由此可以得到,神经网络在训练例k kk上的均方误差为:

9.png

BP是一个迭代学习算法,迭代的每一轮都会对权重进行更新,基于梯度下降算法和链式求导法则,我们可以得到:

1、对隐藏层第h hh个神经元与输出层第o oo个神经元之间的连接权重ω h o  的更新估计式为:

10.png

其中

11.png

因此,权重ω h o 的更新估计式为:


12.png

2、对输入层第i ii个神经元与隐藏层第h hh个神经元之间的连接权重ν i h 的更新估计式为:


13.png

其中:

14.png15.png16.png

因此,权重ν i h  的更新估计式为

18.png


##BP神经网络Python实现

该神经网络被设置为三层:一层输入层、一层隐藏层、一层输出层

样本集:

特征一 特征二 标签
0 0 0
0 1 1
1 0 1
1 1 0


可以看出,这就是一个异或样本集,使用这个样本集可以展现出神经网络与感知机在处理非线性可分问题上的差别。

import math
import random
# 用于设置权重矩阵的大小并给定初始权重
def weight_matrix(row, col, weight=0.0):
    weightMat = []
    for _ in range(row):
        weightMat.append([weight] * col)
    return weightMat
# 用于给权重矩阵内的每元素生成一个初始随机权重
def random_weight(parm_1, parm_2):
    return (parm_1 - 1) * random.random() + parm_2
# Sigmoid激活函数
def sigmoid(x):
    return 1.0 / (1.0 + math.exp(-x))
# Sigmoid激活函数的导函数
def sigmoid_derivate(x):
    return x * (1 - x)
# 定义BP神经网络类
class BPNeuralNetwork:
    def __init__(self):
        # 定义输入层、隐藏层、输出层,所有层的神经元个数都初始化为0
        self.input_num, self.hidden_num, self.output_num = 0, 0, 0
        # 定义输入层、隐藏层、输出层的值矩阵,并在setup函数中初始化
        self.input_values, self.hidden_values, self.output_values = [], [], []
        # 定义输入-隐藏层、隐藏-输出层权重矩阵,并在setup函数中设置大小并初始化
        self.input_hidden_weights, self.hidden_output_weights = [], []
    # 神经网络的初始化函数
    # 四个参数分别代表:对象自身、输入层神经元个数、隐藏层神经元个数、输出层神经元个数
    def setup(self, input_num, hidden_num, output_num):
        # 设置输入层、隐藏层、输出层的神经元个数,其中输入层包含偏置项因此数量+1
        self.input_num, self.hidden_num, self.output_num = input_num + 1, hidden_num, output_num
        # 初始化输入层、隐藏层、输出层的值矩阵,均初始化为1
        self.input_values = [1.0] * self.input_num
        self.hidden_values = [1.0] * self.hidden_num
        self.output_values = [1.0] * self.output_num
        # 设置输入-隐藏层、隐藏-输出层权重矩阵的大小
        self.input_hidden_weights = weight_matrix(self.input_num, self.hidden_num)
        self.hidden_output_weights = weight_matrix(self.hidden_num, self.output_num)
        # 初始化输入-隐藏层、隐藏-输出层的权重矩阵
        for i in range(self.input_num):
            for h in range(self.hidden_num):
                self.input_hidden_weights[i][h] = random_weight(-0.2, 0.2)
        for h in range(self.hidden_num):
            for o in range(self.output_num):
                self.hidden_output_weights[h][0] = random_weight(-0.2, 0.2)
    # 神经网络的前向预测
    # 两个参数分别代表:对象自身、单个数据
    def predict(self, data):
        # 将数据放入输入层,-1是由于输入层中的偏置项不需要接收数据
        for i in range(self.input_num - 1):
            self.input_values[i] = data[i]
        # 隐藏层计算
        for h in range(self.hidden_num):
            # 激活函数的参数
            total = 0.0
            # 激活函数的参数值由输入层权重和输入层的值确定
            for i in range(self.input_num):
                total += self.input_values[i] * self.input_hidden_weights[i][h]
            # 将经过激活函数处理的输入层的值赋给隐藏层
            self.hidden_values[h] = sigmoid(total - 0)
        # 输出层计算
        for o in range(self.output_num):
            total = 0.0
            for h in range(self.hidden_num):
                total += self.hidden_values[h] * self.hidden_output_weights[h][o]
            self.output_values[o] = sigmoid(total - 0)
        return self.output_values[:]
    # 神经网络的反向传播
    # 四个参数分别代表:对象自身、单个数据、数据对应的标签、学习率(步长)
    # 本函数皆为数学推导的实现
    def back_propagate(self, data, label, learn):
        # 反向传播前先进行前向预测
        self.predict(data)
        # 计算输出层的误差
        output_datas = [0.0] * self.output_num
        for o in range(self.output_num):
            error = label[o] - self.output_values[o]
            output_datas[o] = sigmoid_derivate(self.output_values[o]) * error
        # 计算隐藏层的误差
        hidden_datas = [0.0] * self.hidden_num
        for h in range(self.hidden_num):
            error = 0.0
            for o in range(self.output_num):
                error += output_datas[o] * self.hidden_output_weights[h][o]
            hidden_datas[h] = sigmoid_derivate(self.hidden_values[h]) * error
        # 更新隐藏-输出层权重
        for h in range(self.hidden_num):
            for o in range(self.output_num):
                self.hidden_output_weights[h][o] += learn * output_datas[o] * self.hidden_values[h]
        # 更新输入-隐藏层权重
        for i in range(self.input_num):
            for h in range(self.hidden_num):
                self.input_hidden_weights[i][h] += learn * hidden_datas[h] * self.input_values[i]
        # 计算样本的均方误差
        error = 0
        for o in range(len(label)):
            error += 0.5 * (label[o] - self.output_values[o]) ** 2
        return error
    # 神经网络训练函数
    # 四个参数分别代表:对象自身、数据集、标签、最大循环次数、学习率、终止误差
    def train(self, datas, labels, limit=50000, learn=0.05, stop_error=0.02):
        for i in range(limit):
            error = 0
            for i in range(len(datas)):
                data = datas[i]
                label = labels[i]
                error += self.back_propagate(data, label, learn)
            if error <= stop_error:
                break
    # 神经网络验证函数
    def test(self):
        # 数据集及其标签
        datas = [[0, 0], [0, 1], [1, 0], [1, 1]]
        labels = [[0], [1], [1], [0]]
        # 调用神经网络的初始化函数并传入参数作为输入层、隐藏层、输出层的神经元个数
        # 其中输入层的神经元个数应与数据集的特征数保持一致
        self.setup(2, 5, 1)
        self.train(datas, labels)
        for data in datas:
            print(self.predict(data))
# 定义BP神经网络对象并调用其进行预测
if __name__ == '__main__':
    nn = BPNeuralNetwork()
    nn.test()


神经网络训练结果:

[0.018648283776391633]
[0.9754998553712237]
[0.9806999914518663]
[0.02997622156919269]


该结果与真实值labels[0, 1, 1, 0]基本类似,可以认为神经网络在预测异或这类非线性可分问题上是有效的。



相关文章
|
9月前
|
机器学习/深度学习 监控 数据挖掘
Python 高效清理 Excel 空白行列:从原理到实战
本文介绍如何使用Python的openpyxl库自动清理Excel中的空白行列。通过代码实现高效识别并删除无数据的行与列,解决文件臃肿、读取错误等问题,提升数据处理效率与准确性,适用于各类批量Excel清理任务。
794 0
|
9月前
|
数据可视化 关系型数据库 MySQL
【可视化大屏】全流程讲解用python的pyecharts库实现拖拽可视化大屏的背后原理,简单粗暴!
本文详解基于Python的电影TOP250数据可视化大屏开发全流程,涵盖爬虫、数据存储、分析及可视化。使用requests+BeautifulSoup爬取数据,pandas存入MySQL,pyecharts实现柱状图、饼图、词云图、散点图等多种图表,并通过Page组件拖拽布局组合成大屏,支持多种主题切换,附完整源码与视频讲解。
887 4
【可视化大屏】全流程讲解用python的pyecharts库实现拖拽可视化大屏的背后原理,简单粗暴!
|
9月前
|
机器学习/深度学习 PyTorch TensorFlow
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic,深度学习探索者。深耕TensorFlow与PyTorch,分享框架对比、性能优化与实战经验,助力技术进阶。
|
9月前
|
监控 负载均衡 安全
WebSocket网络编程深度实践:从协议原理到生产级应用
蒋星熠Jaxonic,技术宇宙中的星际旅人,以代码为舟、算法为帆,探索实时通信的无限可能。本文深入解析WebSocket协议原理、工程实践与架构设计,涵盖握手机制、心跳保活、集群部署、安全防护等核心内容,结合代码示例与架构图,助你构建稳定高效的实时应用,在二进制星河中谱写极客诗篇。
WebSocket网络编程深度实践:从协议原理到生产级应用
|
10月前
|
机器学习/深度学习 人工智能 算法
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic带你深入卷积神经网络(CNN)核心技术,从生物启发到数学原理,详解ResNet、注意力机制与模型优化,探索视觉智能的演进之路。
830 11
|
10月前
|
机器学习/深度学习 文字识别 Java
Python实现PDF图片OCR识别:从原理到实战的全流程解析
本文详解2025年Python实现扫描PDF文本提取的四大OCR方案(Tesseract、EasyOCR、PaddleOCR、OCRmyPDF),涵盖环境配置、图像预处理、核心识别与性能优化,结合财务票据、古籍数字化等实战场景,助力高效构建自动化文档处理系统。
2661 0
|
10月前
|
安全 测试技术 虚拟化
VMware-三种网络模式原理
本文介绍了虚拟机三种常见网络模式(桥接模式、NAT模式、仅主机模式)的工作原理与适用场景。桥接模式让虚拟机如同独立设备接入局域网;NAT模式共享主机IP,适合大多数WiFi环境;仅主机模式则构建封闭的内部网络,适用于测试环境。内容简明易懂,便于理解不同模式的优缺点与应用场景。
1424 0
机器学习/深度学习 算法 自动驾驶
1500 0
|
9月前
|
机器学习/深度学习 算法 机器人
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
399 8
|
9月前
|
机器学习/深度学习 算法 自动驾驶
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
463 8

推荐镜像

更多