f15baff7-6813-eb11-8da9-e4434bdf6706.png
人工神经网络是基于统计学和人工智能两个领域发展起来的一种非常流行的深度学习方法,它最根本的设计思想是模拟人脑的运行方式建立一个非线性模型,将输入的数据当做特征处理,并得到反馈的结果。自其诞生以来,人工神经网络技术已经取得了长足的发展,并成为深度学习最重要的方法之一。

目录

一、人工神经网络简介

二、BP算法

三、训练神经网络解决回归问题

四、训练神经网络解决分类问题(以手写数字识别为例)

五、结语

一、人工神经网络简介

面对分类问题,人类的思维通常是寻找特征。譬如在对鸟雀分类时,我们会考虑其体态,身长,喙长,翼展等等因素,寻找它最有可能属于的类别。同样面对回归问题,我们也会通过学习不同变量与响应的关系,估计出大概的回归模型。人工神经网络则是将这一过程建造成数学模型。主要问题是我们要如何根据需求,训练一个神经网络出来。

神经网络主要由三大结构组成:输入层(Input Layer),隐藏层(Hidden Layer)和输出层(Output Layer)。每个变量对应的数据都在输入层进入神经网络,并在隐藏层和输出层被处理,最后在输出层输出。下图为一般神经网络的简单示意图:

f25baff7-6813-eb11-8da9-e4434bdf6706.png
Fig1.1 包含一层隐藏层的神经网络示意图

其中对每一个隐藏层或者输出层的节点而言,每一次传入都是一次对上一层数据加权求和的过程,每一次传出都是一次激活输出的过程。针对不同的问题,我们需要用不同的激活函数来处理加权结果。常用的激活函数如下表所示:

f35baff7-6813-eb11-8da9-e4434bdf6706.png
Table1.1 常用激活函数

隐藏层和输出层每个神经元的工作过程如下所示:

f45baff7-6813-eb11-8da9-e4434bdf6706.png
Fig1.2 神经元结构

一般而言,激活函数会从已有的函数集里面挑选,所以我们最重要的目标是调整神经网络中的每一个权重,从而减少预测结果和实际结果之间的误差。

二、BP(Back Propagation)算法

以简单的单隐藏层结构为例,在开始训练神经网络时,一般会将权重初始化为一组和为1的相等的数,或者一组和为1的随机数。这时候,神经网络就像一个在混沌中出生的婴儿一样,不具备任何判断的知识。要增加这个网络的判断能力,需要用一定的学习样本去训练它,这一训练指的就是如何依靠样本的信息去更新网络的权重。实现这一过程的就是BP算法。

BP算法即反向传播算法,其核心思想是根据现有权重得到预测结果后,与准确结果对比,得到误差,再根据误差对现有权重进行有策略的调整,使得能在权重调整程度最小的情况下,得到模型判断力最大程度的改善。

下面是一个权重已经初始化的,以

为激活函数的神经网络示意图,其中
指输入层
对节点
的权重向量,
指常数项1对节点
的权重,其余同理:

f55baff7-6813-eb11-8da9-e4434bdf6706.png
Fig2.1 权重初始化后的简单神经网络

假设在一定的权重下,神经网络得到的判断结果为

,准确结果是
。有一定线性回归模型基础的读者会知道,第
项的误差可以被写成:

其中:

上面提到,最佳的更新样本方法应该能在权重调整幅度最小的情况下,达到模型判断力的最大改善,也就是误差下降最快。因此,我们将误差

对权重向量
里的各分量求导,以得到各分量的最速下降方向,譬如分量
的最速下降方向是:

式子比较长,但本质上就是高中数学里面的链式求导法则。式子的意思是,当

在上述方向改变的时候,就能以最小的变动代价达到最大的模型改善效果。记其最速下降方向为
,则
应该更新为:

的意义就是
要在其最速下降方向上走多远。在相关领域,它一般被称为学习率。不难想象,学习率是个非常玄学的概念,调小了模型更新得慢,调大了模型可能一直不能达到最好效果。所以调参一直是众多AI狗(误)乐而不疲的事情。遍历
,就可以对所有的
权重都进行更新。

权重的更新也是同理的,读者有兴趣可自行推导,核心思路也是对每一个权重分量,寻找它对误差的最速下降方向。当所有权重都被更新完一次以后,称作完成了一个训练周期(epoch)。一般神经网络的训练需要多个周期来反复优化权重,直至效果稳定下来。得到的结果就是我们想要的神经网络。BP算法作为神经网络的反馈学习的根本算法,无论什么类型的神经网络,基本都会用到。

(BTW,简单说所谓的BP算法本质上就是链式求导法则加最速下降方向的应用而已)

三、训练神经网络解决回归问题

例一、假设某系统的响应范围是(0,1),且有三个重要的参数变量,每个变量都被标记为{0,1}。现在我们有五个学习样本:

f65baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 3.1 五个学习样本

我们希望根据这五个样本训练一个简单的神经网络模型,使得我们下次输入特征,网络就能预测响应值。简便起见,本题先尝试训练一个无常数项,无隐藏层的简单神经网络来解决问题:

f75baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 3.2 简单神经网络示意图

先将学习样本以矩阵的形式输入到MATLAB中:

clear
clc
X=[0,0,1;0,1,1;1,1,1;1,0,0;1,1,0];    %特征矩阵
O=[0.05;0.82;0.97;0.24;0.86];         %正确的响应

然后初始化权重,此处我们使用随机初始化:

W=2*rand(1,3)-1;

定义激活函数,此处我们选用logistic函数:

function y=Sigmond(x)
y=1./(1+exp(-x));
end

并且定义了更新过程如下:

function W=TrainANN(W,X,O)
a=0.9;  %学习率为0.9
N=size(X,1);
for k=1:N
    x=X(k,:)';  %获取第k个样本的特征信息
    o=O(k);     %获取第k个样本的正确分类
    v=W*x;      %将特征信息加权求和,输入隐藏层细胞
    y=Sigmond(v);  %细胞将求和结果激活并输出
    e=o-y;       %计算输出结果和正确结果的误差
    delta=y*(1-y)*e;  %计算最速下降方向
                      %值得注意的是,y*(1-y)正是logistic函数的求导结果,其良好的计算形式也是我们选择logistic的原因之一
    dW=a*delta*x;  %权重调整值
    W(1)=W(1)+dW(1);%调整权重
    W(2)=W(2)+dW(2);
    W(3)=W(3)+dW(3);
                   %更新后的权重被输出,函数结束
end
end

上述是一个epoch的权重调整过程。实际上,我们需要调整多次。将神经网络训练1000次的过程为:

for i=1:1000
    W=TrainANN(W,X,O);
end

最后,检查原样本在该网络下的预测结果:

for i=1:N
    x=X(i,:)';
    v=W*x;
    y(i,1)=Sigmond(v);
end

对比y和O,即可大致了解该网络的精度:

f85baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 3.3 预测结果对比

此时的变量W就是训练后的最佳权重。

例二、沿用上一题的问题和学习样本:

f65baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 3.4 五个学习样本

本题计划在上一题的神经网络基础上,增加一个隐藏层,但仍然不增加常数项。

fa5baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 3.5 含有一个隐藏层的神经网络

同样,先将学习样本以矩阵的形式输入到MATLAB中:

clear
clc

X=[0,0,1;0,1,1;1,1,1;1,0,0;1,1,0];  %特征矩阵
O=[0.05;0.82;0.97;0.24;0.86];        %正确响应

然后是权重初始化。此处我们需要初始化两组权重,一组是输入层和隐藏层之间的,一组是隐藏层和输出层之间的:

W1=2*rand(4,3)-1;
W2=2*rand(1,4)-1;

激活函数沿用上面定义的logistics函数:

function y=Sigmond(x)
y=1./(1+exp(-x));
end

并且定义更新过程为:

function [W1,W2]=TrainANN2(W1,W2,X,D)
    a=0.9;         %学习率为0.9
    N=size(X,1);
    for k=1:N      %遍历抽取每次事件对应的三个参数变量进行学习
        x=X(k,:)';
        d=D(k);
        v1=W1*x;
        y1=Sigmond(v1);
        v=W2*y1;
        y=Sigmond(v);
        
        e=d-y;     %计算隐藏层与输出层之间的误差
        delta=y.*(1-y).*e;   %第二组权重的最速下降方向
        e1=W2'*delta; %将误差传递到输入层和隐藏层之间
        delta1=y1.*(1-y1).*e1; %第一组权重的最速下降方向
        
        dW2=a*delta*y1';
        dW1=a*delta1*x';
        W1=W1+dW1;
        W2=W2+dW2;
    end
end

上述为一个epoch的训练,一般需要训练多次以达到效果:

for i=1:10000
    [W1,W2]=BackpropXOR(W1,W2,X,O);
end

最后检查神经网络对原样本的预测准确性:

N=size(X,1);
for i=1:N
    x=X(i,:)';
    v1=W1*x;
    y1=Sigmond(v1);
    v=W2*y1;
    y(i)=Sigmond(v);
end

最终结果:

fb5baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 3.6 训练结果

和例题一对比起来,增加了隐藏层以后,模型的预测能力得到了极大增强,可见隐藏层对神经网络而言也是一个非常重要的结构。实际上,深度学习中的神经网络一般也包含极深的隐藏层结构。

四、训练神经网络解决分类问题

运用神经网络解决分类问题的思路与上面是一样的,不过回归问题的响应值一般是连续量,可以直接由输出层输出,但分类问题的响应一般是有限的离散值,所以要对输出作一定的处理。在此介绍softmax函数。假设神经网络的输出值为向量

,则softmax对该向量的处理方式为:

以四分类问题为例,建造输出层为四个节点的神经网络,并将四个分类的响应分别记作[1,0,0,0],[0,1,0,0],[0,0,1,0]和[0,0,0,1],下面是softmax处理的示意图:

fc5baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 4.1 Softmax处理示意图

根据上面的结果,神经网络最终会判断响应为第四类。

例一、某系统需要对手写数字进行识别,现在有数字1~6的二值图片各一张作为学习样本:

fd5baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 4.1 训练样本

上面六张图片分别被标注正确分类响应为[1,0,0,0,0,0],[0,1,0,0,0,0],[0,0,1,0,0,0],[0,0,0,1,0,0],[0,0,0,0,1,0]和[0,0,0,0,0,1],分别代表数字1,2,3,4,5,6。现提供一张新的图片:

fe5baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 4.2 测试样本

根据已有的学习样本训练神经网络,并判断测试样本是什么数字。

首先将二值图片的信息以矩阵的形式输入MATLAB:

clear all
clc
rng(3)
X=zeros(5,5,5);
X(:,:,1)=[1,0,0,1,1;1,1,0,1,1;1,1,0,1,1;1,1,0,1,1;1,0,0,0,1];  %数字1对应的二值矩阵,下同
X(:,:,2)=[0,0,0,0,1;1,1,1,1,0;1,0,0,0,1;0,1,1,1,1;0,0,0,0,0];
X(:,:,3)=[0,0,0,0,0;1,1,1,1,0;1,0,0,0,1;1,1,1,1,0;0,0,0,0,0];
X(:,:,4)=[1,1,1,0,1;1,1,0,0,1;1,0,1,0,1;0,0,0,0,0;1,1,1,0,1];
X(:,:,5)=[0,0,0,0,0;0,1,1,1,1;0,0,0,0,0;1,1,1,1,0;0,0,0,0,0];
X(:,:,6)=[1,0,0,0,0;1,0,1,1,1;1,0,0,0,0;1,0,1,1,0;1,0,0,0,0];
D=diag(ones(1,6));                                             %按顺序每行代表一张图片的正确响应

采用含有一个隐藏层的神经网络结构,其中输入层含有25个节点(图片像素数量),隐藏层含有50个节点,输出层含有6个节点。对权重进行随机初始化:

W1=2*rand(50,25)-1;   %输入层和隐藏层之间的权重
W2=2*rand(6,50)-1;    %隐藏层和输出层之间的权重

激活函数继续采用Logistics函数,此处不再重复。定义训练过程如下:

function [W1,W2]=Multiclass(W1,W2,X,D)
a=0.9;
N=size(X,1);
for k=1:N
    x=reshape(X(:,:,k),25,1);   %对每张5x5的训练图片拉直,变成1x25的向量,进入输入层
    d=D(k,:)';                  %图片的正确响应
    
    v1=W1*x;
    y1=Sigmond(v1);
    v=W2*y1;
    y=Softmax(v);
    
    e=d-y;
    delta=e;
    e1=W2'*delta;
    delta1=y1.*(1-y1).*e1;
    dW1=a*delta1*x';
    W1=W1+dW1;
    dW2=a*delta*y1';
    W2=W2+dW2;
end
end    

反复训练10000次:

for epoch=1:10000
    [W1,W2]=Multiclass(W1,W2,X,D);
end

将测试图片以二值矩阵的形式输入MATLAB:

X=[0,0,0,0,0;1,1,1,0,0;1,0,0,0,0;1,1,1,0,0;0,0,0,0,0];

利用训练好的神经网络对测试图片进行分类:

x=reshape(X,25,1);  %改变二值矩阵为1x25向量
v1=W1*x;            %进入隐藏层
y1=Sigmond(v1);     %激活
v=W2*y1;           %进入输出层
y=Softmax(v)';      %softmax处理

Softmax处理后得到的最终结果为:

ff5baff7-6813-eb11-8da9-e4434bdf6706.png
Fig 4.3 预测结果

Softmax处理结果显示在六种响应中,分类结果最接近[0,0,1,0,0,0],也就是对应数字3,分类成功。

五、结语

工业级的神经网络往往需要海量的学习材料,极深的隐藏层结构和低损失的预处理方法,而上述仅仅是为了说明原理而编写出来的简单例子。以手写数字识别为例,以下转载一个大型的手写数字数据库,有兴趣的读者可以自行下载,并改进我给出的分类神经网络,实现精度更高,更可靠的手写数字分类器:

MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐