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]基本类似,可以认为神经网络在预测异或这类非线性可分问题上是有效的。



相关文章
|
8天前
|
机器学习/深度学习 数据采集 自然语言处理
理解并应用机器学习算法:神经网络深度解析
【5月更文挑战第15天】本文深入解析了神经网络的基本原理和关键组成,包括神经元、层、权重、偏置及损失函数。介绍了神经网络在图像识别、NLP等领域的应用,并涵盖了从数据预处理、选择网络结构到训练与评估的实践流程。理解并掌握这些知识,有助于更好地运用神经网络解决实际问题。随着技术发展,神经网络未来潜力无限。
|
6天前
|
安全 网络协议 网络安全
OWASP Top 10 网络安全10大漏洞——A01,源码+原理+手写框架
OWASP Top 10 网络安全10大漏洞——A01,源码+原理+手写框架
|
3天前
|
机器学习/深度学习 人工智能 算法
食物识别系统Python+深度学习人工智能+TensorFlow+卷积神经网络算法模型
食物识别系统采用TensorFlow的ResNet50模型,训练了包含11类食物的数据集,生成高精度H5模型。系统整合Django框架,提供网页平台,用户可上传图片进行食物识别。效果图片展示成功识别各类食物。[查看演示视频、代码及安装指南](https://www.yuque.com/ziwu/yygu3z/yhd6a7vai4o9iuys?singleDoc#)。项目利用深度学习的卷积神经网络(CNN),其局部感受野和权重共享机制适于图像识别,广泛应用于医疗图像分析等领域。示例代码展示了一个使用TensorFlow训练的简单CNN模型,用于MNIST手写数字识别。
18 3
|
8天前
|
机器学习/深度学习 算法 网络架构
什么是神经网络学习中的反向传播算法?
什么是神经网络学习中的反向传播算法?
12 2
|
8天前
|
机器学习/深度学习 存储 算法
卷积神经网络(CNN)的数学原理解析
卷积神经网络(CNN)的数学原理解析
37 1
卷积神经网络(CNN)的数学原理解析
|
8天前
|
开发框架 网络协议 Java
【计算机网络】—— 网络应用通信基本原理
【计算机网络】—— 网络应用通信基本原理
|
8天前
|
网络协议 程序员 网络性能优化
【网络原理】TCP 协议中比较重要的一些特性(三)
【网络原理】TCP 协议中比较重要的一些特性(三)
14 0
|
8天前
|
缓存 网络协议
【网络原理】TCP 协议中比较重要的一些特性(二)
【网络原理】TCP 协议中比较重要的一些特性(二)
18 0
|
8天前
|
网络协议
【网络原理】TCP 协议中比较重要的一些特性(一)
【网络原理】TCP 协议中比较重要的一些特性(一)
15 0
|
8天前
|
负载均衡 网络协议 安全
【计算机网络】虚拟路由冗余(VRRP)协议原理与配置
【计算机网络】虚拟路由冗余(VRRP)协议原理与配置
17 0