
1. 问题
神经网络这几年成了最炙手可热的技术,大有一统江湖的气势。不搞懂神经网络,出去都不好意思和人吹牛自己学过机器学习。
今天我们就来剖析一下神经网络到底是怎么回事。
2. 分析
2.1. 正向传播
之前我们讨论的逻辑回归,可以用图形表示为
x0+---+
|
x1+---+
|
x2+-------g(z)--> Output y
|
x3+---+
|
x4+---+
其中 ,是X的一个线性组合。
通过组合,我们将X转换成了一个中间单元 z,然后再对 z 进行加工。因为梯度下降, z 可以比原始数据 X 更好的特性。
举个例子,比如我们预测房价,房子长度、宽度是可以直接测量的,但实际上面积和房价相关性更好,而面积就是由长度和宽度加工出来的。
所以我们很自然的就会想到,如果不仅仅使用一个拟合,是不是可以有更好的效果?那么就会有下面的情况
x0+--+ a20---+
| |
x1+--+ +---a21---+
| | |
x2+------+---a22---+--> Output y
| | |
x3+--+ +---a23---+
|
x4+--+
其中
这样,我们就通过变换,把原始输入X,变成了中间单元 a,然后用 a 再计算最终结果。所以 a 既不是输入也不是输出,我们是看不到的,故而称之为隐藏层(Hidden Layer)。
上面图中的 a0 有点特殊,它并不是像其他中间元一样,由 X 得出,而是额外添加的解释单元。可以理解为线性函数里面的截距。
用身高和年龄的关系打个比方就容易理解了。身高和年龄肯定是有一定关系的。如果我们把孩子出生的那一刻定为 x=0,身高在 x=0的时候显然不为0,而是某一个正数,我们用额外的变量截距来表达。
偏置单元也可以这样理解。
上式里面,有
: X的线性变换矩阵,通过
得出激活函数需要的参数 z。也称为权重(Weights);
: 激活函数,用于将 X 的线性组合 Z 转换成神经元的有效值。比如我们依然可以用类似逻辑回归的
作为激活函数,将神经元的值转换为 [0, 1]之间的概率;
经过上述处理,把 X 转换成 a 以后,就可以把 a 作为输入单元,再进行下一步类似计算。
具体而言,我们用

来得出最终的y。
我们大脑在处理信息的时候也是类似情况,现将外界输入信息在神经元处加工,然后输入大脑进行处理。
中间层类似于加工外界信息的神经元,模型又是由多个神经元及输入层组成的网状结构,所以这种模型称之为神经网络模型。
2.2. 反向传播
当我们有了 以后,就可以把 X 加工成 Z、T,然后加工成 y,从而给出预测。但问题是我们如何得到
呢?这就需要用到反向传播。
我们以分类模型为例。如果输出结果是二元变量,即只有 [0, 1] 两个值,那么模型就和逻辑回归类似。如果输出结果是多个值,我们就需要考虑多种情况。通常情况下,我们会为 k 个输出结果定义一个 k 阶向量,其中只有一个结果为 1,其他均为0。即
这样,我们就把神经网络的多分类问题,转换成了类似逻辑回归的问题。
那么类似于逻辑回归的代价函数,我们只需要增加一个对 k 个结果的循环,即可得到神经网络的代价函数
呃,上面这个公式很复杂,复杂到我看着它都觉得累。而实际上,还有正规化(Regularization)部分没有加入。不过我们先不要在意这些细节,继续往下挖挖。
所谓反向传播,是和正向传播相对的。我们从输入值 X 一步步计算到输出值 y 的过程,就是正向传播的过程;反向反过来,就是反向传播。只是反向传播的是误差,不是输入值。
我们以一个四层神经网络为例,如下图所示。其中a1是输入层,a2/a3是两个隐藏层,a4是输出层。

随机初始化,通过正向传播我们可以求出预测的结果和实际值之间的误差,也即
然后利用这个误差值来计算前一层的误差:
其中, 是权重导致的误差的和。类似的,我们可以继续计算前一层误差
由此,我们就可以由后面一层的误差,传递到前面一层。
有了所有的误差的表达式后,便可以计算代价函数的偏导数了
有了偏导数,我们就可以用梯度下降的方法,逐步逼近求解出合适的 了。
有了权重,针对新的输入 X,我们就可以计算出相应的预测结果 y 了。
3. 实现
相对之前聊的线性回归和逻辑回归,神经网络是一种更为复杂的算法。向前传播求解、向后传播误差求参数是其核心思想。具体数学细节没有办法在一篇文章里面讲清楚,而且对于绝大多数人来说,也没有必要完全实现其背后的公式推导。对数学原理感兴趣的朋友可以参考文献 [2] ,里面有详细的公式推导和数学原理讲解。
另外,上面举例是用的分类算法,实际上神经网络也可以输出连续值。这种情况下输出单元就只有一个,最后一步采用回归即可。逻辑和原理与分类算法一样。
在实际应用中,除非为了练习,我们无需自己编写代码实现神经网络。现在已经有很成熟的软件包可以用。我们以 scikit learning 为例。
import numpy as np
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
data = np.loadtxt('assets\ex3data.txt', delimiter=' ')
X = data[:, 0:400]; y = data[:, -1]
X_train, X_test, y_train, y_test = train_test_split(X, y)
mlp = MLPClassifier(solver='lbfgs', random_state=1).fit(X_train, y_train)
print("Training set score: {:.2f}".format(mlp.score(X_train, y_train)))
print("Test set score: {:.2f}".format(mlp.score(X_test, y_test)))
输出
Training set score: 1.00
Test set score: 0.92
呃,这个训练集是不是存在 Overfit 的情况啊……
4. 交流
独学而无友则孤陋寡闻。现有「数据与统计科学」微信交流群,内有数据行业资深从业人员、海外博士、硕士等,欢迎对数据科学、数据分析、机器学习、人工智能有兴趣的朋友加入,一起学习讨论。
大家可以扫描下面二维码,添加荔姐微信邀请加入,暗号:机器学习加群。

5. 扩展
5.1. 延伸阅读
5.2. 参考文献
- G. James, D. Witten, T. Hastie R. Tibshirani, An introduction to statistical learning: with applications in R. New York: Springer, 2013.
- T. Hastie, R. Tibshirani, J. H. Friedman, The elements of statistical learning: data mining, inference, and prediction, 2nd ed. New York, NY: Springer, 2009.
- W. Härdle, L. Simar, Applied multivariate statistical analysis, 3rd ed. Heidelberg ; New York: Springer, 2012.

本文使用 mdnice 排版