(Data Science Learning Handbook 34) Detailed explanation of the principle of multi-layer perceptron & Python and R implementation

1. Introduction

  Machine learning is divided into many fields, among which connectionism refers to a variety of neural networks with neurons as the basic structure. A network of connections that are organized to simulate the interactive responses of biological nervous systems to real-world stimuli. The neural network learning that we widely mentioned in machine learning is the intersection of machine learning and neural network. This article will introduce the basic neuron model, the knowledge of the perceptron model, and the specific application of the further multilayer perceptron (Note that the content introduced in this article is only the foreshadowing of the current popular deep learning, so only the corresponding modules without GPU acceleration are used. The knowledge about deep learning, the current popular deep learning methods and the corresponding GPU-accelerated training methods will be Introduced in subsequent blog posts)

 

2. From neuron model to multilayer feedforward network

2.1 Knowledge foreshadowing

  Before introducing the neuron model in neural network learning, let's compare the biological neuron. Neurons are the basic information processing units. Biological neurons are mainly composed of dendrites, axons and synapses. The structure diagram is as follows:

By observing its structure , the following characteristics can be summarized:

  1. Dendrites protrude from the cell body and have irregular surfaces and many shorter branches. Its role is the input end of signals for receiving nerve impulses;

  2. The axon refers to the longest branch extending from the cell body, that is, the nerve fiber, which is equivalent to the output end of the signal and is used to transmit nerve impulses;

  3. Neurons are interconnected in the form of axons (output) + dendrites (input), and for a single neuron, it is irreversible in the direction of input -> output;

Regarding the function of neurons , the following points are also summarized:

  1. Plasticity: There is a mechanism in neurons that enables the neural network to adapt to the environment through the generation of new synapses and the adjustment of existing synapses (just as people currently believe that memory is the relationship between existence and connections between neurons. assumptions in);

  2. Spatiotemporal integration: The stimulus input to a certain interneuron is the cumulative result of repeated adjustments from all previous related neurons;

  3. Excited and inhibited state: When the cumulative stimulation result of afferent impulses makes the cell membrane potential rise and successfully exceeds the threshold, the cell will enter the excited state, resulting in a step on the efferent stimulation; if the cumulative afferent stimulation result is low At the threshold where the step occurs, there is no subsequent neural activity, and the cell then enters an inhibitory state;

  4. Delay and refractory period of synapse: The transmission of synapse to neural activity has delay and refractory period, there is a time interval between two adjacent impulses, and the neuron is in a resting state during the time interval , does not produce spontaneous nerve impulses;

  5. Learning, forgetting and fatigue: Synaptic transmission has learning, forgetting and fatigue processes

Through the above description, we can be pleasantly surprised to find that these structural characteristics of biological neurons make it perfectly fit the purpose we hope to achieve in machine learning - that is, through a series of regular stimulus transmission process, and finally achieve the correct decision-making result output , as early as the 1940s and 1950s, people discovered this wonderful connection, and then constructed the basic neuron model;

2.2 Neuron Model

2.2.1 Basic structure

  The structure of a typical MP artificial neuron model is as follows:

where x j represents the input value from the jth "dendrite", w ji represents the connection weight (there is only one unique weight on each fixed input), and ui represents the linearity of all input signals on this neuron i combination, the coefficient is the corresponding weight, that is

θ i is the threshold of the neuron i, and the intermediate value vi can be obtained by simply adding ui and θ i :

And f() represents the activation function, y i represents the output of the neuron i, that is:

 

2.2.2 Activation function

  理想的激活函数是阶跃函数,如下图,它将连续域上的输入值映射为{0,1},1对应神经元兴奋 ,0对应神经元抑制;

  事实上,类似逻辑回归中的logit函数,我们需要用一些数学性质良好的函数来替代数学性质较差(不处处连续)的阶跃函数,常用的是sigmoid型函数,如下:

 

2.3 感知机与多层网络

2.3.1 单层感知机

   感知机(perceptron)由两层神经元组成,如下图所示,输入层接受外界输入信号后传递给输出层,输出层是M-P神经元,亦称作“阈值逻辑单元”(threshold logic unit);

 

感知机的学习过程就是对于给定的训练集,在每一轮迭代中同时调整各权重wi(i=1,2,...,n),以及阈值θ,直到满足预设精度为止,为了方便训练,阈值θ可看作第n+1个输入为1的结点的对应权重wn+1,亦称为哑结点(dummy node),这样权重和阈值的学习变得到了统一,例如下图这种表示形式,阈值θ就被视为一个特别的输入:

而单个感知机的学习规则也十分简单,对训练数据集(x,y),若当前感知机的输出为y*,则感知机各权重调整规则如下:

只有在y*=y或训练轮数达到预设的上限或精度第一次达到或超过设定的阈值时,该学习过程才会停止,否则都将进行一轮又一轮的权重调整;

  在整个感知机的结构中,只有输出层神经元包含激活函数的计算过程,输入层只管输入值*权重,即只拥有一层功能神经元(functional neuron),学习能力非常有限,只能处理线性可分问题,否则感知机的学习过程将会发生震荡,w难以稳定下来,即学习失效,例如对于常见的异或问题,感知机就无法习得其规则:

也正是这个原因,对于感知机学习的热度在上世纪60年代跌入谷底,但随着研究的深入,很多用于改造感知机的方法被提出,下面举几个例子:

  1、对神经元施加非线性输入函数

  类似部分非线性回归中我们常使用的线性化方法,对于单纯线性输入的感知机输入层,我们可以根据对具体问题的理解,在个别输入神经元上进行非线性改造,如下例:

  2、使用AND逻辑器构成割平面式的非线性化

  普通感知机的分割平面是线性的,我们思考一下,有哪种机器学习算法本质也是线性分割呢?没错,如果你看过我之前关于决策树的博文,一定还记得,决策树的分割平面式由很多段与各坐标轴平行的拼接而成的,那么我们可以将这种思想类似地迁移到感知机的改造中,用多条线性分割来围成近似的非线性分割:

 

2.3.2 多层感知机与神经网络

  之前介绍的几种改造线性感知机的方法,实际实施起来存在着很多局限,比如施加输入层非线性函数就存在着很多不确定的部分,要想更加通用地解决非线性可分问题,需要考虑使用多层功能神经元,例如下图所示的这个简单的两层感知机就可以解决异或问题,其中输入层与输出层间的若干层神经元被称为隐层或隐含层(hidden layer),隐层和输出层都是含有激活函数部分的功能神经元:

  而更一般的多层感知机,如下图所示具有规则的层级结构,这时它已经可以称作是神经网络了,每层神经元与下一层神经元全互连,且同层神经元之间不存在连接,也不存在跨层连接,这样的神经网络结构通常被乘称作“多层前馈神经网络”(multi-layer feedforward neural networks),其中输入层神经元依旧单纯地接收外界输入,隐层与输出层对信号进行处理,最终结果依旧是由输出层神经元处理并输出,所以我们平时对一个多层前馈神经网络的层数的称呼都来源于其隐含层的层数,例如下图a就是单隐含层前馈网络,b就是双隐含层前馈网络:

 

2.3.3 训练方法

  多层感知机的学习能力比单个感知机强得多,但随着其结构的复杂化,对应的训练方法也不同于前面简单感知机的简单规则,最常使用的方法是误差逆传播(error BackPropgation,即常用的BP算法);

算法过程:

  对一个给定的训练集D={(x1,y1),(x2,y2)...(xm,ym)},其中xi为d维向量,yi为l维向量,即自变量由d个维度组成,输出值为l个维度,对应的,构造一个由d个输入层神经元、q个隐含层神经元(隐含层神经元个数没有硬性要求)以及l个输出层神经元组成的单隐层前馈神经网络,其中输出层第j个神经元的阈值用θj表示,隐层第h个神经元的阈值用γh表示,输入层第i个神经元与隐层第h个神经元之间的连接权为vih,隐层第h个神经元与输出层第j个神经元之间的连接权为whj,记隐层第h个神经元接收到的输入为

输出层第j个神经元接收到的输入为

结构如下图:

且假设隐层和输出层每个功能神经元都使用Sigmoid型函数:

对于训练集中的任意(xk,yk),假定神经网络的输出为

则该网络在(xk,yk)上的均方误差为:

 而整个网络中需要确定的参数共有

需要确定,而BP是一种迭代学习算法,在迭代的每一轮采用广义的感知机学习规则对参数进行更新估计,即其任意参数v的更新估计式为:

  以隐层到输出层的连接权whj为例来进行推导:

  首先我们先确定一个事实,BP算法基于梯度下降(gradient descent)策略,以目标的负梯度方向对参数进行调整,所以对均方误差项

 给定学习率η

注意到whj先影响到第j个输出层神经元的输入值βj再影响其输出值,最后影响到Ek

又因为

且Sigmoid型函数有一个很好的性质:

于是综上,有

所有最终得到whj的更新公式:

类似的,其他参数的更新公式:

其中eh为:

学习率η控制着算法每一轮迭代中的更新步长,太大容易震荡(接近理想解时却跨过),太小则收敛速度又会过慢,有时为了做精细调节,可以更加灵活的设置学习率而不必一直固定不变;需要注意的是,标准BP算法在随机初始化各参数(一般是初始化一个较小的非0阵)后,经过一轮一轮地迭代,每一轮都只输入一个样本值来调整各参数,训练目的是逐渐缩小训练集D上的累积误差:

而上面推导的规则是基于每次一个样本输入的调整,即标准BP算法,特点是参数更新的非常频繁,并且前后的不同样本可能会导致训练效果的前后抵消,所以为了达到目标累积误差极小点,需要进行很多次的迭代,但优点是下降和计算都较快,特别是当训练集D非常大时,因此其被使用的最多;

一个重要的论点:

  只要一个隐层包含足够多神经元,多层前馈网络就可以以任意精度逼近任意复杂度的连续函数。但是在实际任务多层前馈网络的构造中,选择单隐层 还是双隐层,每一层隐层选取几个神经元,这都尚无可靠的理论支撑,存在着大量试错(trial-by-error)的成分,对神经网络最佳超参数的搜索方法的研究也是一个相当活跃的领域;

  也正是因为其强大的表示能力,多层前馈网络很容易过拟合,即其训练集上误差持续下降,而验证集上误差却可能上升,目前主要有两种缓解多层前馈网络过拟合的方法:

  1、早停(early stopping)

  通过将数据集分成训练集和验证集,训练集用来计算梯度、更新连接权和阈值,验证集用来估计误差,若训练集误差降低但验证集上误差升高,则停止训练,同时返回具有当前最小验证集误差的连接权与阈值(基于贪心算法的原则)

  2、正则化(regularization)

  正则化是指在误差目标函数中增加一个用于描述网络复杂度的部分,常用的是连接权与阈值的平方和,令Ek表示第k个训练样本上的误差,wi表示连接权和阈值,则误差目标函数变为:

其中λ属于(0,1),表示在经验误差和网络复杂度之间进行权衡,具体取值常通过交叉验证来进行搜索确定;

  3、惩罚项

  对目标函数附加惩罚项以强制无用的权值趋于0

局部极小情况:

  由于不能保证目标函数在权空间中的正定性,而误差曲面往往复杂且无规则,存在着多个分布无规则的局部极小点,因此基于梯度下降的BP算法很容易陷入局部极小,导致训练效果不好,而常用的改进措施有:

  1、引入全局优化技术

  包括同时训练多个神经网络模型,然后按照在验证集上的表现,选择其中验证误差最小的作为全局最小的近似值;使用诸如随机梯度下降、模拟退火、遗传算法、蚁群算法等启发式的算法来寻找最大可能接近全局最小值的局部最小值;

  2、平坦化优化曲面以消除局部极小

  3、设计合适的网络结构使得其不会产生局部极小

当然,后面两种方案实施起来比较复杂,因此实际任务中常使用的第一种策略。

 

 三、Python实现

  本文暂时不介绍带有GPU加速的神经网络训练方法,因此不适用于过大规模的样本集和过多超参数的神经网络;

  我们利用sklearn.neural_network中集成的方法来进行多层前馈神经网络的训练,下面分别针对分类问题和回归问题进行展开:

 

3.1 分类问题

  我们使用sklearn.neural_network中的MLPClassifier()来实现BP算法训练的多层感知机,其主要参数如下:

hidden_layer_size:tuple型输入,形如(m,n),其中m用来控制隐层神经元的个数,n用来控制隐层的层数,也可以理解为网络总层数-2(即减去输入层与输出层),默认值为(100,),即单隐层,隐层中含有100个神经元

activation:字符型,用于控制激活函数的类型,可选类型有'identity',表示无非线性激活函数,用于训练线性模型时;'logistic',logit函数;'tanh',双曲函数;'relu',f(x)=max(0,x)

solver:字符型,用来控制BP算法中使用到的求解器,'lbfgs',表示准牛顿法;'sgd',表示标准的随机梯度下降法;'adam',另一种类型的基于随机梯度下降的方法。默认为'adam'

alpha:惩罚项系数,默认为0.0001

 batch_size:当solver设置为随机梯度相关的求解器时,此参数控制随机优化器的小批量尺寸

learning_rate:字符型,控制学习率,当设置为'constant'时,训练过程中的学习率为另一参数learning_rate_init预设的常数;当设置为'invscaling',会逐步的降低学习率以减小在最优值附近震荡的风险;当设置为'adaptive'时,且early_stopping被设置为开启时,如果连续两次训练集上的累积误差没有下降或交叉验证得分无法得到提升时,学习率会变为原来的1/5,只有当solver设置为'sgd'时才生效

learning_rate_init:双精度浮点值,控制初始的学习率,配合learning_rate的设置值,共同控制学习率的变化情况,只有当solver设置为'sgd'或'adam'时才生效(即基于梯度)

max_iter:整型,控制训练的最大迭代轮数,默认值是200轮,当然,该方法也是只有solver设置为'sgd'或'adam'时才会生效

shuffle:bool型,控制是否在每一轮迭代中打乱样本的顺序,默认值是True,只有solver设置为'sgd'或'adam'时才会生效

random_state:整型,控制随机数种子,即控制训练开始时随时初始化权重的过程,默认不设置

tol:设定精度的阈值,默认是1e-4,设置的越小,理论上训练精度越高,同时迭代次数也相应越多

verbose:bool型,控制是否打印整个训练过程的细节

warm_start:bool型,控制是否进行预训练,即通过预训练得到一个较好的初始权重,再进行正式训练,默认为False

momentum:float型,设置梯度下降中的动量因子,默认为0.9,只有当solver设置为'sgd'时才会生效

early_stopping:bool型,是否在验证分数不再得到提高且未达到设置的最大迭代轮数之前”早停“训练,默认为False,只有solver设置为'sgd'或'adam'时才会生效

validation_fraction:float型,控制验证集的比例,默认为0.1,且只有在early_stopping设置为True时才会生效

函数返回项:

classes_:数组或列表形式,显示每一个输出对应的类别标签

loss_:float型,输出当前达到的最小累积误差水平

coefs_:列表,返回训练好的网络中的权重矩阵

n_iter_:整型,返回求解器迭代的总次数

n_layers_:整型,返回当前网络层数

n_outputs_:整型,返回当前网络输出个数

out_activation_:字符型,输出当前网络中的激活函数

下面我们以威斯康辛州乳腺癌数据为例,下面是基本功能的演示:

from sklearn.neural_network import MLPClassifier
from sklearn import datasets
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score

'''加载数据集'''
X,y = datasets.load_breast_cancer(return_X_y=True)


'''初始化多层感知机分类器,其中激活函数选择logit函数,求解器选择adam版随机梯度下降法,最小精度设置为1e-5,并设置早停处理,验证集比例为0.3'''
clf = MLPClassifier(activation='logistic',
                    solver='adam',
                    max_iter=1000,
                    tol=1e-5,
                    validation_fraction=0.3)

'''利用训练集训练网络'''
clf = clf.fit(X,y)

'''打印验证集上的混淆矩阵'''
print(confusion_matrix(y,clf.predict(X)))

'''打印验证集上的正确率'''
print(accuracy_score(y,clf.predict(X)))

运行结果:

 

下面我们来看看这个单隐层(100X1)的网络的各项返回值:

'''显示网络中的训练目标标签'''
print('训练目标标签',clf.classes_)

'''打印输入层与隐层之间所有连接上的权重矩阵的形状,即共30X100个权重'''
print('输入层与隐层之间所有连接上的权重矩阵形状:',clf.coefs_[0].shape)

'''打印隐层与输出层之间的权重矩阵形状,即100X1个权重'''
print('隐层与输出层之间的权重矩阵形状:',clf.coefs_[1].shape)

'''打印隐层上所有神经元内部的阈值向量的形状'''
print('隐层上所有神经元内部的阈值向量的形状:',clf.intercepts_[0].shape)

'''打印输出层神经元(本例中为单个输出)内部的阈值'''
print('输出层神经元(本例中为单个输出)内部的阈值:',clf.intercepts_[1])

'''打印总训练轮数'''
print('总训练轮数',clf.n_iter_)

运行结果:

 

3.2 回归问题

  讲完了上面的分类问题,下面我们来介绍一下多层感知机在拟合函数曲线上的应用,我们使用sklearn.neural_network.MLPRegressor()来完成回归任务,其主要参数与MLPClassifier相同,这里便不再做介绍,下面我们通过构造一个已知函数解析式的较复杂的非线性函数并生成对应的带有随机误差项修正的数据,进行多层感知机回归任务的演示:

from sklearn.neural_network import MLPRegressor
import matplotlib.pyplot as plt
import numpy as np
import math

'''生成仿真一维数据集'''
X = np.arange(-5,5,0.05).reshape((-1,1))

'''因变量计算函数,添加了随即误差项'''
def My_f(x):
    y = x**2-x**3+x+math.exp(x)+np.random.randn()
    return y

'''根据公式生成因变量仿真值'''
y = np.array([My_f(X[i]) for i in range(len(X))]).reshape((-1,1))

plt.figure(figsize=(14,9))
iter = 1000
for i in range(1,10):
    plt.subplot(330+i)
    plt.scatter(X,y,s=5)
    rg = MLPRegressor(activation='relu',max_iter=iter)
    rg = rg.fit(X,y)
    y_pre = rg.predict(X)
    plt.plot(X,y_pre,c='red')
    plt.title('iterations:'+str(iter))
    iter += 1000

运行结果:

可以看出,随着迭代次数的增多,拟合曲线(红线)越来越逼近与真实情况,为了检验是否存在过拟合现象,我们扩大定义域的范围,并在其上沿用前面的函数解析式创造虚假数据集,并利用9000次迭代后的网络来进行预测:

 

X = np.arange(-9,9,0.05).reshape((-1,1))

y = np.array([My_f(X[i]) for i in range(len(X))]).reshape((-1,1))

y_pre = rg.predict(X)
plt.scatter(X,y,s=3)
plt.plot(X,y_pre,c='red')

 

可以看出,随着定义域的扩大化,我们曾经表现优异的网络也发生大幅度的偏差,即我们常说的过拟合现象,所以实际中使用多层感知机进行回归需要在减少过拟合上有更多考虑。

 

 

四、R实现

  为了和前面Python保持一致(即不支持GPU加速的神经网络训练方法),我选择R中的nnet包进行演示,nnet中的nnet()可以创建单隐层前馈神经网络,其主要参数如下:

formula:R中常规的因变量~自变量的公式格式

weights:为每一个样本赋权,若无输入则默认每个样本权重都为1

size:因为nnet只能创建单隐层前馈网络,因此size传入的正整数代表了隐层的神经元个数

data:指定样本所在的数据框

Wts:初始化的权重向量,若此项无输入则随机初始化权重向量

rang:控制初始化权重的范围,为[-rang,rang]

maxit:最大迭代轮数,默认为100

abstol:设置精度阈值

library(nnet)

data(iris)
data <- iris

#训练我们的单隐层前馈神经网络,其中隐层神经元个数为2
clf <- nnet(Species~.,
            data=data,
            size=2,
            maxit=200)

pre <- predict(clf,iris[,-5])
pre <- apply(pre,1,which.max)

#打印混淆矩阵
table(pre,data$Species)

#打印正确率
cat('正确率:',sum(prop.table(table(pre,data$Species))))
    

运行结果:

 

  

  以上就是关于多层感知机(多层前馈神经网络)的基本知识,关于当下主流的带GPU加速的神经网络框架,将会在接下来的内容中介绍。

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325648868&siteId=291194637