LionKing数据科学专栏

购买普通会员高级会员可以解锁网站精华内容且享受VIP服务的优惠

想要查看更多数据科学相关的内容请关注我们的微信公众号知乎专栏

神经网络(neural network)原理及算法实现

神经网络原理

神经网络是一种适用回归问题和多分类问题的非线性模型。

神经网络主要有前向传播神经网络(Feed-Forward Neural Network),卷积神经网络(Convolutional Neural Network),和递归神经网络(Recurrent Neural Network)。这里介绍前向传播神经网络。

一个基本的神经元有若干个输入和一个输出,该输出为输入的线性变换结合一个激活函数(activation function)。

假设神经元的输入为$i_1, i_2, \ldots, i_k$,对应的权重为$w_1, \ldots, w_k$,偏置(bias)为$b$,激活函数为$f$,则线性组合为$$z = b + i_1w_1 + \ldots + i_kw_k$$

输出为$h = f(z)$。

一个神经网络由大量神经元通过一层层的网络连接在一起,中间每一层被称作隐藏层(hidden layer),数据$x_1, \ldots, x_p$被称为输入层(input layer),最后有一层输出层(output layer)。

对于回归问题,输出层只有一个结点用来预测$y$;对于$K$分类问题,输出层有$K$个结点用来预测每一个类型的概率。

前向传播神经网络的架构

对于一个神经网络,假设其有$L$层,其中$L_1$为输入层,$L_L$为输出层。

假设第$l$层有$n_l$个神经元。

第$l$层的$n_l$个神经元和第$l + 1$层的$n_{l + 1}$个神经元两两之间有连接,记录$W_{i, j}^{(l)}$是第$l$层第$i$个神经元到第$l + 1$层第$j$个神经元的权重,$b_i^{(l)}$是第$l + 1$层第$i$个神经元的偏置。

用$z_i^{(l)}$表示第$l$层第$i$个神经元在激活前的值,$a_i^{(l)}$表示该神经元在激活后的值。

对于回归问题,输出层的单个神经元的预测结果即整个神经网络的预测。

对于分类问题,输出层的$K$个神经元给出$K$个输出$a_1^{(L)}, \ldots, a_K^{(L)}$。

对应$K$个类别的概率预测为$$p_1 = \frac{\exp{(a_1^{(L)})}}{Z}, \ldots, p_K = \frac{\exp{(a_K^{(L)})}}{Z}$$其中$$Z = \sum_{k=1}^{K}\exp{(a_k^{(L)})}$$

下图是两个隐藏层,分别有两个隐藏神经元,数据维度为3,输出类别个数为3的一个神经网络的例子。

训练

神经网络的训练中,每次使用一小批(mini-batch)训练样本,进行前向传播(forward propagation)和后向传播(backward propagation)两个步骤不断地更新$W$和$b$。

神经网络的前向传播(forward propagation)即对于一个数据,将该数据在当前神经网络的权重下从$L_1$传播到$L_L$得到最终输出。

对于训练数据$(x_1^{(i)}, x_2^{(i)}, \ldots, x_p^{(i)}, y^{(i)})$,我们有

$$\begin{align*} z_i^{(l + 1)} &= \sum_{j=1}^{n_l}a_j^{(l)}W_{j, i}^{(l)} + b_i^{(l)}\\ a_i^{(l + 1)} &= f(z_i^{(l + 1)}) \end{align*}$$

神经网络的反向传播(backward propagation)是参数的更新步骤,在得到该数据的预测值$\hat{y}^{(i)}$后,我们将该预测和真实值$y^{(i)}$的损失关于各个参数的导数利用链式求导法则(chain rule)得出后,对所有参数进行小批量梯度下降。

对于回归问题,损失使用$\ell_2$范数;对于分类问题,损失使用交叉熵(cross-entropy),如果真实类别为$k$,则损失为$$-\log{p_k}$$其中$$p_k = \frac{\exp{(a_k^{(L)})}}{\sum_{j=1}^{K}\exp{(a_j^{(L)})}}$$

我们总结神经网络算法如下:

预测

Python实现

主流的神经网络框架包括tensorflow, pytorch等。这里为了方便起见,我们使用sklearn内置的实现。

from sklearn import neural_network
import numpy as np
from matplotlib import pyplot as plt

n_train = 1000
n_test = 200

np.random.seed(10)
# 生成X
X = np.random.randn(n_train + n_test, 2)
# 生成y = (X1^2 + X2^2 < 0.5)并加上10%随机扰动
y = (X[:, 0] ** 2 + X[:, 1] ** 2 < 0.5) ^ (np.random.rand(n_train + n_test) < 0.1)
y = y.reshape((n_train + n_test, 1))

# 拆分训练和测试数据集
X_train = X[:n_train, :]
y_train = y[:n_train, :]
X_test = X[n_train:, :]
y_test = y[n_train:, :]

# 创建神经网络分类器
neural_network_classifier = neural_network.MLPClassifier(solver='lbfgs', alpha=1e-5, hidden_layer_sizes=(5, 5), random_state=0)
# 训练模型
neural_network_classifier.fit(X_train, y_train)
# 测试集预测
yhat_test = neural_network_classifier.predict(X_test)
# 测试集错误率
err_test = np.mean(yhat_test ^ y_test.flatten())
print('测试集错误率为%f' % (err_test, ))

# 绘制数据和决策边界
xmin = X_train[:, 0].min()
xmax = X_train[:, 0].max()
ymin = X_train[:, 1].min()
ymax = X_train[:, 1].max()
xs, ys = np.meshgrid(np.arange(xmin, xmax, 0.01), np.arange(ymin, ymax, 0.01))
f = neural_network_classifier.predict(np.c_[xs.ravel(), ys.ravel()]).reshape(xs.shape)
plt.close()
plt.contourf(xs, ys, f, cmap=plt.cm.cool)
plt.scatter(X_train[:, 0], X_train[:, 1], color=['darkorange' if col else 'green' for col in y_train], s=10)
plt.savefig('neural-network-data.png')
        
输出:

测试集错误率为0.120000
        

训练数据和神经网络模型的决策边界(decision boundary)如下:

常见面试问题

Q:比较常用的激活函数

需要购买普通会员高级会员登录后刷新该页面查看

Q:使用0作为神经网络的权重初始值可以吗?

需要购买普通会员高级会员登录后刷新该页面查看

Q:神经网络防止过拟合的方式有哪些?

需要购买普通会员高级会员登录后刷新该页面查看

Q:简述Dropout

需要购买普通会员高级会员登录后刷新该页面查看

Q:简述提前终止(early stopping)

需要购买普通会员高级会员登录后刷新该页面查看

Q:简述批标准化(batch normalization)

需要购买普通会员高级会员登录后刷新该页面查看

Q:卷积神经网络(CNN)为什么适合图像问题?

需要购买普通会员高级会员登录后刷新该页面查看

更多机器学习相关问题见本网站论坛机器学习理论版面机器学习实践版面

更多面试问题见面试真题汇总

想要查看更多数据科学相关的内容请关注我们的微信公众号知乎专栏