机器学习第五章——神经网络

一、神经元模型

神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界体所作出的交互反应。

M-P神经元模型 :神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接(connection)进行传递,神经元接收到的总输入值将与神经元的阈值进行比较,然后通过“激活函数”(activation function)处理以产生神经元的输出。

常用 Sigmoid函数作为激活函数

sigmoid(x)=\frac{1}{1+e^{-x}}

二、感知机与多层网络

感知机(Perceptron)由两层神经元组成,输入层接收外界输入信号后传递给输出层,输出层是M-P神经元,亦称“阈值逻辑单元”(threshold logic unit).

权重w_{i}(i=1,2,...,n),阈值\theta可看作一个固定输入为-1.0的“哑结点”(dummy node)所对应的连接权重w_{n+1}。对训练样例(x,y),若当前感知机的输出为\hat{y},则感知机权重将这样调整:(\eta \in (0,1)称为学习率(learning rate))

w_{i}\leftarrow w_{i}+\Delta w_{i}
 \Delta w_{i}=\eta (y-\hat{y})x_{i}

若两类模式是线性可分的,如“与”、“或”、“非”问题,则感知机的学习过程一定会收敛(converge);否则感知机学习过程将会发生振荡(fluctuation),如“异或”问题。

要解决非线性可分问题,需考虑使用多层功能神经元。输出层与输入层之间的一层神经元,被称为隐层或隐含层(hidden layer),隐含层和输出层神经元都是拥有激活函数的功能神经元.

多层前馈神经网络”(multi-layer feedforward neural networks):每层神经元与下一层神经元全互连,神经元之间不存在同层连接,也不存在跨层连接.

神经网络的学习过程,就是根据训练数据来调整神经元之间的“连接权”(connection weight)以及每个功能神经元的阈值。

三、误差逆传播算法

误差逆传播(errorBackPropagation,简称BP)算法不仅可用于多层前馈神经网络,还可用于其他类型的神经网络,例如训练递归神经网络。

BP算法:给定训练集D=\left \{ (x_{1},y_{1}),(x_{2},y_{2}),...,(x_{m},y_{m}) \right \},x_{i}\in \mathbb{R}^{d},y_{i}\in \mathbb{R}^{l},即输入示例由d个属性描述,输出l维实值向量.如下图:(假设隐层和输出层神经元都使用Sigmoid 函数)

对训练例(x_{k}.y_{k}),假定神经网络的输出为\hat{y}_{k}=(\hat{y}^{k}_{1},\hat{y}^{k}_{2},...,\hat{y}^{k}_{l}),即

\hat{y}^{k}_{j}=f(\beta _{j}-\theta _{j})

则网络在(x_{k}.y_{k})上的均方误差为

E_{k}=\frac{1}{2}\sum_{j=1}^{l}(\hat{y}_{j}^{k}-y_{j}^{k})^{2}

BP算法中的更新公式(推导见西瓜书P102、P103):

\Delta w_{hj}=\eta g_{j}b_{h}

 \Delta \theta _{j}=-\eta g_{j}

\Delta v_{ih}=\eta e_{h}x_{i}

\Delta \gamma _{h}=-\eta e_{h}

其中: 

g_{j}=\hat{y}_{j}^{k}(1-\hat{y}_{j}^{k})(y_{j}^{k}-\hat{y}_{j}^{k})

e_{h}=b_{h}(1-b_{h})\sum_{j=1}^{l}w_{hj}g_{j}

BP算法的工作流程:

标准BP算法:更新规则基于单个的E_{k}推导;更新频繁;可能出现“抵消”现象;需进行更多次数的迭代

累积BP算法:更新规则基于累积误差最小化;更新的频率低;累积误差下降到一定程度之后,进一步下降会非常缓慢

只需一个包含足够多神经元的隐层,多层前馈网络就能以任意精度逼近任意复杂度的连续函数.
BP神经网络经常遭遇过拟合,两种缓解BP网络的过拟合的策略:

早停”(early stopping):若训练集误差降低但验证集误差升高,则停止训练,同时返回具有最小验证集误差的连接权和阈值.
正则化”(regularization) :在误差目标函数中增加一个用于描述网络复杂度的部分,例如连接权与阈值的平方和。

构建的BP神经网络预测类,创建神经网络模型: 


from __future__ import division    
import math      
import random    
import pandas as pd    
import numpy as np
 
""" 三层反向传播神经网络 """
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 = self.makeMatrix(self.ni, self.nh)  # 输出层到隐藏层的映射矩阵
        self.wo = self.makeMatrix(self.nh, self.no)  # 隐藏层到输出层的映射矩阵
        for i in range(self.ni):          
            for j in range(self.nh):    
                self.wi[i][j] = self.rand(-0.2, 0.2)  
        for j in range(self.nh):
            for k in range(self.no):
                self.wo[j][k] = self.rand(-2, 2)  
 
    #前向传播,激活神经网络的所有节点
    def update(self, inputs):
        if len(inputs) != self.ni - 1:
            print(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):                  # self.nh表示隐藏层的节点数
            sum = 0.0                            # 激活项a = g(z)  z = Θ^T x ;sum相当于z,每次循环归零
            for i in range(self.ni):                  #通过循环z = Θ^T x ,因为Θ、x均为向量
                sum = sum + self.ai[i] * self.wi[i][j]  #〖 Z〗^((2))=Θ^((1)) a^((1))
            self.ah[j] = self.sigmoid(sum)    # a^((2))=g(z^((2))),这里使用sigmoid()函数作为激活函数
        for k in range(self.no):
            sum = 0.0
            for j in range(self.nh):
                sum = sum + self.ah[j] * self.wo[j][k]  #〖 Z〗^((3))=Θ^((2)) a^((2))
            self.ao[k] = self.sigmoid(sum)    # a^((3))=g(z^((3)))
        return self.ao[:]
    
    #反向传播,计算节点激活项的误差
    def backPropagate(self, targets, lr):               # targets为某样本实际种类分类,lr为梯度下降算法的学习率
        output_deltas = [0.0] * self.no
        for k in range(self.no):
            error = targets[k] - np.round_(self.ao[k])
            output_deltas[k] = self.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] = self.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
        for k in range(self.no):                                    
            error += 0.5 * (targets[k] - np.round_(self.ao[k])) ** 2  
        return error                                          
 
    #用测试集输出准确率
    def test(self, patterns):                            
        count = 0
        num=0
        for p in patterns:
            target = p[1]
            result = self.update(p[0])                    
            print(p[0], ':', target, '->', np.round_(result))
            num=0
            for k in range(self.no):
                if (target[k] == np.round_(result[k])):
                    num +=1
            print(num)
            if num==3:
                count +=1
            print("******************",(target) == (np.round_(result)),"******************")
            accuracy = int(float(count / len(patterns))*100)
        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):  
        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("percent:",int(i/iterations*100),"%",'   error: %-.9f' % error)
 
    #生成区间[a, b)内的随机数
    def rand(self, a, b):    
        return (b - a) * random.random() + a    
    
    # 生成大小 I*J 的矩阵,默认零矩阵
    def makeMatrix(self, I, J, fill=0.0):    
        m = []    
        for i in range(I):    
            m.append([fill] * J)    
        return m   
 
    # 函数 sigmoid,bp神经网络前向传播的激活函数
    def sigmoid(self, x):
        return 1.0 / (1.0 + math.exp(-x))       
     
    # 函数 sigmoid 的导数,反向传播时使用
    def dsigmoid(self, x):
        return x * (1 - x)
 
if __name__ == '__main__':
    data = []                            
    raw = pd.read_csv('iris.csv')    
    raw_data = raw.values            
    raw_feature = raw_data[1:, 1:5]    
    for i in range(len(raw_feature)):          
        ele = []                    
        ele.append(list(raw_feature[i]))  
        if raw_data[i][5] == 0:   
            ele.append([0, 0,1])    
        elif raw_data[i][5] == 1:
            ele.append([0,1, 0])
        elif raw_data[i][5] == 2:
            ele.append([1, 1,1])
        else:
            ele.append([0, 0,0])
        data.append(ele)
    nn = NN(4, 10, 3)  
    training = data[1:100]            
    test = data[101:]            
    nn.train(training, iterations=1000)  
    nn.test(test)

 

 四、全局最小与局部最小

局部极小解:w^{*}\theta ^{*},若存在\epsilon >0 使得

\forall (w;\theta )\in\left \{ (w;\theta )\mid \left \| (w;\theta )- (w^{*};\theta^{*} ) \right \|\leqslant \epsilon \right \}

都有E(w;\theta ) \geqslant E(w^{*};\theta^{*} )成立,则(w^{*};\theta^{*} )为局部极小解;

全局最小解:若对参数空间中的任意(w;\theta )都有E(w;\theta ) \geqslant E(w^{*};\theta^{*} ),则(w^{*};\theta^{*} )为全局最小解.

五、其他常见神经网络 

  1. RBF(Radial Basis Function,径向基函数)网络是一种单隐层前馈神经网络,它使用径向基函数作为隐层神经元激活函数,而输出层则是对隐层神经元输出的线性组合。
  2. ART(Adaptive Resonance Theory,自适应谐振理论)网络是竞争型学习的重要代表.该网络由比较层、识别层、识别阈值和重置模块构成.其中,比较层负责接收输入样本,并将其传递给识别层神经元。
  3. SOM(Self-Organizing Map,自组织映射)网络 是一种竞争学习型的无监督神经网络,它能将高维输入数据映射到低维空间(通常为二维),同时保持输入数据在高维空间的拓扑结构。

  4. 级联相关(Cascade-Correlation)网络是结构自适应网络的重要代表。结构自适应网络则将网络结构也当作学习的目标之一,并希望能在训练过程中找到最符合数据特点的网络结构.级联相关网络有两个主要成分:“级联”和“相关”。
  5. Elman网络是最常用的递归神经网络之一,“递归神经网络”(recurrent neural networks)允许网络中出现环形结构,隐层神经元的输出被反馈回来,与下一时刻输入层神经元提供的信号一起,作为隐层神经元在下一时刻的输入.隐层神经元通常采用Sigmoid激活函数,网络的训练则常通过推广的BP算法进行。

  6. Boltzmann机就是一种“基于能量的模型”(energy-basedmodel),其神经元分为两层:显层与隐层.显层用于表示数据的输入与输出,隐层则被理解为数据的内在表达. Boltzmann机中的神经元都是布尔型的,状态1表示激活,状态0表示抑制。

六、深度学习

典型的深度学习模型就是很深层的神经网络.显然,对神经网络模型,提高容量的一个简单办法是增加隐层的数目.然而,多隐层神经网络难以直接用经典算法(例如标准BP算法)进行训练,因为误差在多隐层内逆传播时,往往会“发散”(diverge)而不能收敛到稳定状态。

无监督逐层训练(unsupervised layer-wise training)是多隐层网络训练的有效手段,其基本思想是每次训练一层隐结点,训练时将上一层隐结点的输出作为输入,而本层隐结点的输出作为下一层隐结点的输入,这称为“预训练”(pre-training);在预训练全部完成后,再对整个网络进行“微调”(fine-tuning)训练。

“预训练+微调”的做法可视为将大量参数分组,对每组先找到局部看来比较好的设置,然后再基于这些局部较优的结果联合起来进行全局寻优。

另一种节省训练开销的策略是“权共享”(weight sharing),即让一组神经元使用相同的连接权.这个策略在卷积神经网络(Convolutional NeuralNetwork,简称CNN)中发挥了重要作用.以CNN进行手写数字识别任务为例,如下图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值