西瓜书之神经网络

双层感知机解决非线性可分(异或)问题

在这里插入图片描述

BP算法原理推导+数据演示

原理推导

在这里插入图片描述
第一层网络的参数
在这里插入图片描述
因为该网络要解决的是一个二分类问题,所以输出层的激活函数可以使用一个Sigmoid型函数

反向传播的计算

很好的推导例子: https://blog.csdn.net/weixin_39441762/article/details/80446692.

很好的推导例子: https://zhuanlan.zhihu.com/p/38006693.
我们已经了解了数据沿着神经网络前向传播的过程,这一节我们来介绍更重要的反向传播的计算过程。假设我们使用随机梯度下降的方式来学习神经网络的参数,损失函数定义为,其中是该样本的真实类标。使用梯度下降进行参数的学习,我们必须计算出损失函数关于神经网络中各层参数(权重w和偏置b)的偏导数。
步骤

1.初始化网络中的权值和偏置项,w,b
2.激活前向传播,得到各层输出和损失函数的期望值,E=1/n(y-yi)的平方
3.据损失函数,计算输出单元的误差项和隐藏单元的误差项
4.更新神经网路中的权值和偏置项
5.重复步骤2-4,直到损失函数小于事先给定的阈值或迭代次数用完为止,输出此时的参数即为目前最佳参数。

在这里插入图片描述

1.激活函数的种类

在这里插入图片描述
在这里插入图片描述

2.前向传播

在这里插入图片描述

在这里插入图片描述

3.反向求梯度

请添加图片描述

数据演示

在这里插入图片描述
1.求出每层的值
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2.求出每层的误差
在这里插入图片描述

在这里插入图片描述
3.更新参数
在这里插入图片描述

BP算法缺陷与改进

BP算法缺陷:

 
  1.局部极小值
     对于多层网络,误差曲面可能含有多个不同的局部极小值,梯度下降可能导致陷入局部极小值。

 2.权值过多
       当隐藏节点过多,层数越多时,权值成倍增长。权值的增长意味着对应的空间维数的增加,过高的维数易导致训练后期的过拟合。
       
3.容易过拟合
      训练的次数过多、空间维数过高均容易过拟合。

BP算法改进:

1.利用动量法改进BP算法
    动量法权值调整算法的具体做法是:将上一次权值调整量的一部分迭加到按本次误差计算所得的权值调整量上,作为本次的实际权值调整量,即:


其中,表示动量系数,表示学习率。
2)自适应调整学习率
 调整的基本指导思想是:在学习收敛的情况下,增大以缩短学习时间;当偏大致使不能收敛时,要及时减小它的值,知道收敛为止。此方法适用于设置阈值的情况下。

3)动量-自适应学习速率调整算法
  采用动量法,BP算法可以找到更优的解;采用自适应学习速率法时,BP算法可以缩短训练时间。将以上两种方法结合起来,就得到动量-自适应学习率调整算法。
上述2)和3)都适应于设置阈值来停止程序的方法。

在这里插入图片描述

代码

from __future__ import division
import math
import random
import pandas as pd


flowerLables = {0: 'Iris-setosa',
                1: 'Iris-versicolor',
                2: 'Iris-virginica'}

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
def sigmoid(x):
    return 1.0 / (1.0 + math.exp(-x))


# 函数 sigmoid 的导数
def dsigmoid(x):
    return x * (1 - x)


class NN:
    """ 三层反向传播神经网络 """

    def __init__(self, ni, nh, no):
        # 输入层、隐藏层、输出层的节点(数)
        self.ni = ni + 1  # 增加一个偏差节点
        self.nh = nh + 1
        self.no = no

        # 激活神经网络的所有节点(向量)
        self.ai = [1.0] * self.ni
        self.ah = [1.0] * self.nh
        self.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 j in range(self.nh):
            for k in range(self.no):
                self.wo[j][k] = rand(-2, 2)

    def update(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.0
            for i in range(self.ni):
                sum = sum + self.ai[i] * self.wi[i][j]
            self.ah[j] = sigmoid(sum)

        # 激活输出层
        for k in range(self.no):
            sum = 0.0
            for j in range(self.nh):
                sum = sum + self.ah[j] * self.wo[j][k]
            self.ao[k] = sigmoid(sum)

        return self.ao[:]

    def backPropagate(self, targets, lr):
        """ 反向传播 """

        # 计算输出层的误差
        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.nh
        for j in range(self.nh):
            error = 0.0
            for 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] + lr * change

        # 更新输入层权重
        for i in range(self.ni):
            for j in range(self.nh):
                change = hidden_deltas[j] * self.ai[i]
                self.wi[i][j] = self.wi[i][j] + lr * change

        # 计算误差
        error = 0.0
        error += 0.5 * (targets[k] - self.ao[k]) ** 2
        return error

    def test(self, patterns):
        count = 0
        for p in patterns:
            target = flowerLables[(p[1].index(1))]
            result = self.update(p[0])
            index = result.index(max(result))
            print(p[0], ':', target, '->', flowerLables[index])
            count += (target == flowerLables[index])
        accuracy = float(count / len(patterns))
        print('accuracy: %-.9f' % accuracy)

    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=1000, lr=0.1):
        # lr: 学习速率(learning rate)
        for i in range(iterations):
            error = 0.0
            for p in patterns:
                inputs = p[0]
                targets = p[1]
                self.update(inputs)
                error = error + self.backPropagate(targets, lr)
            if i % 100 == 0:
                print('error: %-.9f' % error)



def iris():
    data = []
    # 读取数据
    raw = pd.read_csv('iris.csv')
    raw_data = raw.values
    raw_feature = raw_data[0:, 0:4]
    for i in range(len(raw_feature)):
        ele = []
        ele.append(list(raw_feature[i]))
        if raw_data[i][4] == 'Iris-setosa':
            ele.append([1, 0, 0])
        elif raw_data[i][4] == 'Iris-versicolor':
            ele.append([0, 1, 0])
        else:
            ele.append([0, 0, 1])
        data.append(ele)
    # 随机排列数据
    random.shuffle(data)
    training = data[0:100]
    test = data[101:]
    nn = NN(4, 7, 3)
    nn.train(training, iterations=10000)
    nn.test(test)


if __name__ == '__main__':
    iris()

链接: https://cloud.tencent.com/developer/article/1460637.

在这里插入图片描述

数据示例: https://blog.csdn.net/hcxddd/article/details/119137414.
两个输出的推导: https://zhuanlan.zhihu.com/p/38006693.
推导: https://blog.csdn.net/weixin_44378835/article/details/111323770.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值