神经网络的原理

本文重点介绍的是“多层感知器”(Multilayer Perceptron),即MLP算法,也被称为前馈神经网络,或者被称为人工神经网络(Artificial Neural Network, ANN)。

线性模型的一般公式可表示为:

MLP神经网络结构 mlp神经网络模型_MLP神经网络结构

其中y-hat表示对y的估计值,x[0]到x[p]是样本特征值,w表示每个特征值的权重,y-hat可以看成是所有特征值的加权求和,可以用下图表示这个过程:

MLP神经网络结构 mlp神经网络模型_权重_02


上图中,输入的特征和预测的结果用节点进行表示,系数w用来连接这些节点。而在MLP模型中,算法在过程里添加了隐藏层(Hidden Layers),然后在隐藏层重复进行上述加权求和计算,最后再把隐藏层所计算的结果用来生成最终结果:

MLP神经网络结构 mlp神经网络模型_神经网络_03


这样一来,模型要学习的特征系数(权重)就会多很多了。每一个输入的特征和隐藏单元(hidden unit)之间,都有一个系数,这一步也是为了生成这些隐藏单元。而每个隐藏单元到最终结果之间,也都有一个系数。在生成隐藏层之后,会使用激活函数(activation function)对激活单元进行非线性化,因为非线性处理是为了将样本特征进行简化,从而使神经网络可以对复杂的非线性数据集进行学习。常见的激活函数有:

  • relu:非线性矫正函数,把小于0的x值全部去掉,用0来代替。
  • tanh:双曲正切处理函数,把特征x的值压缩进-1到1的区间内,-1代表的是x中较小的数值,而1代表x中较大的数值。
  • logistic:sigmod函数,将特征x的值压缩进0到1的区间内。

以tanh为例,经过非线性处理后,MLP模型可分解为:

MLP神经网络结构 mlp神经网络模型_数据集_04


            ······

MLP神经网络结构 mlp神经网络模型_神经网络_05


在权重系数w之外,又多了一个权重系数v,用来通过隐藏层h计算y-hat。在有明确的训练样本后,网络的输入层结点数(特征的数量)和输出层结点数(因变量的数量)便已确定,因此神经网络结构设计主要解决设置几个隐含层和每个隐含层设置几个结点的问题,w和v都是通过对数据的学习得出的。

一般来讲,对于小规模数据集或者简单数据集,节点数量设置为10就己经足够了,但是对于大规模数据集或者复杂数据集来说,有两种方式可供选择:一是增加隐藏层中的节点数量;添加更多的隐藏层。在大型神经网络当中,往往有很多这样的隐藏层,这也是“深度学习”中“深度”二字的来源。

案例分析

telecom_churn.csv数据集是一份移动通信用户消费特征数据,其中churn(用户是否流失)是target,subscriberlD仅用于标识用户编号,剩余的18个变量是自变量,信息如下:

MLP神经网络结构 mlp神经网络模型_神经网络_06

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import classification_report
churn = pd.read_csv(r'C:\Users\Zekun\Desktop\telecom_churn.csv', skipinitialspace=True)
churn.head()
churn.head()
Out[5]: 
   subscriberID  churn  gender  ...  posPlanChange  negPlanChange  call_10000
0      19164958      1       0  ...              0              0           0
1      39244924      1       1  ...              1              0           1
2      39578413      1       0  ...              0              0           1
3      40992265      1       0  ...              0              0           1
4      43061957      1       1  ...              0              0           0

[5 rows x 20 columns]

神经网络需要对数据进行极值标准化神经网络是一个黑盒模型,无法获取其参数,更无法解释,因此我们也不需要知道测试集变量的意义,仅知道变量是连续变量还是分类变量即可。一般的数据处理要求是连续变量需要进行极差标准化,分类变量需要转变为虚拟变量,不过也可以变通处理,只有多分类名义变量才必须转化为虚拟变量,等级变量和二分类变量可以不转换,当作连续变量处理即可。本例中的edu_class和curPlan是等级变量,还有gender和posTrend等二分类变量可以当作连续变量处理。在数据标准化和划分好测试集、训练集后,直接使用网格搜索方法找出最优模型:

#进行极值归一化( MinMaxScaler:归一到 [0,1] )
scaler = MinMaxScaler()
scaler.fit(train_data)
scaled_train_data = scaler.transform(train_data)
scaled_test_data = scaler.transform(test_data)
#网格搜索最优模型
from sklearn.model_selection import ParameterGrid,GridSearchCV
grid = {'hidden_layer_sizes':[(10,),(15,),(20,),(5,5)],\
        'activation':['logistic','tanh','relu'],\
            'alpha':[0.001, 0.01, 0.1, 0.2, 0.4, 1, 10]}
mlp_cv = ridSearchCV(estimator=MLPClassifier(max_iter=1000),param_grid=grid,scoring='roc_auc',\
                      cv=5,n_jobs=-1)
mlp_cv.fit(scaled_train_data, train_target)
mlp_cv.best_estimator_
Out[12]: 
MLPClassifier(activation='tanh', alpha=0.01, hidden_layer_sizes=(20,),max_iter=1000)
#模型评估
mlp_cv.best_score_#返回的是AUC值
Out[13]: 0.9216099107158259
mlp_cv.score(scaled_test_data, test_target)#测试集 Mean accuracy
Out[14]: 0.9227205309602313
mlp_cv.score(scaled_train_data, train_target)#训练集 Mean accuracy
Out[15]: 0.9287678706215576

可以看到ROC曲线下的面积为0.92,且测试集和训练集的得分都很高且相近,说明模型拟合效果很好。以上MLPClassifier的参数中:

  • hidden_layer_sizes参数, 默认[100, ],这意味着模型中只有一个隐藏层,而隐藏层中的节点数是100。如果我们定义为[10,10],即模型中有两个隐藏层,每层有10个节点。
  • activation参数即激活函数的选择,可选“ identity”、“logistic”、“tanh”以及 “relu”, 默认情况下参数值是“relu” 。其中 “identity”表示对样本特征不做处理。
  • alpha值和线性模型的alpha值是一样的,是一个L2惩罚项,默认的数值是0.0001。
  • max_iter是设定的最大迭代次数。
  • n_jobs=-1表示线程数与CPU一致,加快训练速度。
  • 详细解释和其他参数说明可参照AI_Engine:MLPClassifier简单应用与参数说明

一般来说,有4种方法可以调节模型的复杂程度,第一种是调整神经网络每一个隐藏层上的节点数,第2种是调节神经网络隐藏层的层数,第3种是调activation的方式,第4种是通过调整alpha值来改变模型正则化的程度。

神经网络模型中的参数调节是一门艺术。对于初学者来说,建议参考这样一个原则,那就是神经网络中隐藏层的节点数约等于训练数据集的特征数量,但是一般不要超过500。在开始训练模型的时候,可以让模型尽量复杂,然后再对正则化参数alpha进行调节来提高模型的表现

参考文献

段小手《深入浅出Python机器学习》,清华大学出版社
常国珍等《Python数据科学:技术详解与商业实践》,机械工业出版社