第3章 多层感知器

这章节我们来解决的问题是:如何使用神经网络实现逻辑电路中的“异或门”模型?

如下图:

根据第2章我们知道,单层感知器是能够解决“与门”、“或门”、“非门”这些简单的线性问题,但是不能解决“异或门”这类非线性问题。

1.1 解决异或门问题的思路

如果在单层感知器上增加一层,能够很好的解决异或问题。

例如网络结构如下:

我们把每一个感知器节点代表了一个分类器,那么几个节点学习到的分割线如下:

以上3个节点的组合就可以解决异或门问题。

1.2 sigmoid激活函数 -- 线性转为非线性

多层感知器中,我们期望分割面是非线性的,故选择为sigmoid为激活函数

sigmoid表达式和曲线:

sigmoid函数也叫 Logistic 函数,取值范围为(0,1),它可以将一个实数映射到(0,1)的区间。

求导如下:

这个公式在计算梯度的时候用到。

那么采样非线性激活函数,神经网络就有可能学习到平滑的曲线来分割平面,从线性到非线性

1.3 新的问题

按照单层感知器的权重更新,节点3的权重更新可以轻松求得;但是节点1和节点2权重的更新如何求解呢?

按照公式如下:

要求得w111必须要知道节点1的期望值,但是节点1,2的期望值不存在,不能直接求其梯度。

解决方案:误差反向传播算法(Backpropagation,BP算法)

1.4 误差反向传播算法 -- BP算法

神经网络的训练关键在于如何调整权值和阈值,采用的算法:

(1)单层感知机的算法:梯度下降算法;

(2)多层感知器的算法:误差反向传播算法(error Back Propagation),简称BP算法。

反向传播过程如下:

在多层神经网络中,从最后一层开始,逐层的反向进行误差信息传递,并更新相应权重。使用BP算法的多层前馈(向前传播方式没有回路或者环路)网络又称之为BP神经网络;

BP神经网络学习过程:

以下图来源:http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html

(1)以一个3层全连接网络来为例子

下面通过一个3层全连接网络来讲解,包含2个输入、2个隐藏层(第1层3个节点、第2层2个节点)、一个输出(第3层1个节点),节点计算如右图:

(2)前向传播

输入层到隐藏层的计算,即计算第一层输出y1,y2,y3

隐藏层到隐藏层的计算,即计算第2层输出y4,y5。

隐藏层到输出层,即计算输出y

(3)反向传播

反向传播,根据网络的连接路径,从输出层反向把误差项前向传递,并更新权重和偏置参数的过程。

误差项计算:将网络输出信号y与训练数据集的输出值z(期望值)进行比较,得到的差异被称为输出层神经元的误差信号d(不是均方误差,是计算梯度的某一项)

内部神经元的误差项的计算,有2种情况:

<1>误差权重:即前向传播的权重;

<2>如果传播的误差来自多个关联神经元,它们将被叠加。

(4)权重更新

权重更新,根据网络的连接路径,从输出层反向把误差反向传递并更新权重和偏置的过程。

权重更新公式:

(5)总结

来源:http://neuralnetworksanddeeplearning.com/chap2.html

1.5 多层感知器 -- 异或门例子

异或门数据集定义:

import numpy as np

def get_xy_data():
    """ XOR的训练集 -- 真值表 """
    x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
    y = np.array([0, 1, 1, 0])
    return x,y

多层感知器模型定义:

import numpy as np

""" 定义感知器模型结构 """
class XORGateModel():
    def __init__(self):
        """ 初始化权重、偏置 """
        self.w = np.random.normal(size=6).reshape((3, 2))   # 权重
        self.b = np.random.normal(size=3)                   # 偏置
        self.lr = 0.1                                       # 学习率(超参数)

    def sigmoid(self, x):
        return 1/(1 + np.exp(-x))
    
    def dsigmoid(self, x):
        y = self.sigmoid(x)
        return y * (1 - y)

    def forward(self, x):
        """ 前向计算 """
        y1 = self.sigmoid((x[0]*self.w[0][0]) + (x[1]*self.w[0][1]) + self.b[0])
        y2 = self.sigmoid((x[0]*self.w[1][0]) + (x[1]*self.w[1][1]) + self.b[1])
        y3 = self.sigmoid((y1*self.w[2][0]) + (y2*self.w[2][1]) + self.b[2])
        return y3
    
    def update_weight(self, x, n, d):
        e = (x[0] * self.w[n][0]) + (x[1] * self.w[n][1]) + self.b[n]
        self.w[n][0] = self.w[n][0] + (self.lr * d * self.dsigmoid(e) * x[0])
        self.w[n][1] = self.w[n][1] + (self.lr * d * self.dsigmoid(e) * x[1])
        self.b[n]    = self.b[n]    + (self.lr * d * self.dsigmoid(e))

    def train(self, X, Y):
        """
        X,Y -- 训练集
        """
        for i in range(100000):   # 迭代
            j = 0
            C = 0
            for xi in X:
                yi = self.forward(xi)               # 前向计算
                Ci = np.power((Y[j] - yi), 2) / 2   # 计算误差
                C += Ci
                # 更新权重跟偏置
                if Ci > 0:
                    d = Y[j] - yi
                    d1 = self.w[2][0] * d
                    d2 = self.w[2][1] * d
                    self.update_weight(xi, 0, d1)   # 节点1
                    self.update_weight(xi, 1, d2)   # 节点2
                    self.update_weight(xi, 2, d)    # 节点3
                j += 1
            print("epoch{} 误差:{}, 权重:{}".format(i, C, self.w))
            # 什么时候退出?
            if C <= 0.05:
                print("=== 与门的4数据都正确了, 退出迭代")
                break

训练并保存参数:

# 训练
    import data_manager
    X, Y = data_manager.get_xy_data()  # 读取数据集
    model = XORGateModel()            # 实例化类对象
    model.train(X, Y)               # 执行训练
    # 验证训练结果是否正确
    for xi in X:
        print("验证  输入:{}   模型的前向计算结果:{}".format(xi, model.forward(xi)))
    # 保存模型参数
    np.savez("./params", model.w, model.b)

读取参数并预测:

import numpy as np

if __name__ == "__main__":
    # 加载参数
    r = np.load("./params.npz")
    print("权重", r["arr_0"])
    print("偏置", r["arr_1"])
    # 设置参数到网络结构
    import model
    and_model = model.AndGateModel()
    and_model.w = r["arr_0"]
    and_model.b = r["arr_1"]
    # 预测
    X = [[0,0], [0, 1], [1, 0], [1, 1]]
    for xi in X:
        print("预测  输入:{}  结果:{}".format(xi, and_model.forward(xi)))

代码地址:https://download.csdn.net/download/qq_21386397/87567645

有帮助,一键三连哦~~~~~~~~~~~~~~~~~~~~~~~~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值