欢迎光临 x-algo
关注算法在工业界应用
Hi, 这是一个关注大数据算法在工业界应用的网站

神经网络(Neural Network)实现

为了更好的理解deep learning,自己动手实现一个神经网络还是很有必要的。 本文先生成了一个数据集,然后使用LR(逻辑回归)做了一下分类,然后绘制出来了LR的分类面(一条直线)。 接着用一个三层的神经网络训练,从而训练出来一个非线性的分类面,非常直观。

生成数据集

生成数据集通过scikit-learn的make_moon函数:

figure_1

使用逻辑回归做分类

使用逻辑回归(LR)对上面数据进行拟合,同事求出来其对应的分类面,完整可执行代码:

 

figure_1

训练一个神经网络

一个三层的神经网络,输入层节点个数是样本特征维数,这里样本是在一个二维空间的点,所以输入节点个数是2;隐层节点个数人工指定,隐层节点越多就越可以你和复杂的函数;因为是二分类问题,所以输出层有两个节点,分别表示属于某类别的概率(得分)。网络可以用图表示为:

nn-from-scratch-3-layer-network-1024x693

层之间是全连接,隐层需要选择一个激活函数,一般是tanh或者sigmoid,这里选择tanh函数。激活函数的选择也是有很多考虑的因素,例如导数是否可以自表示、函数本身的表达能力(想想百变的beta分布)。

输出层我们希望输出一个概率,所以使用softmax函数将其概率化,softmax函数可以看做是逻辑函数在高维的推广。

网络如何做预测

很多资料中,将这个过程称为正向传播,这个过程其实很简单,就是拿到一个样本,按照我们的网络结构计算一遍即可。

\(\begin{aligned}z_1 & = xW_1 + b_1\\a_1 &= \tanh(z_1)\\z_2 & = a_1W_2 + b_2\\a_2 & = \hat{y} = \mathrm{softmax}(z_2)\end{aligned}\)

x表示输入样本, \(W_i\) 表示层之间的权重, \(z_i\) 表示第i层的输入, \(a_i\) 表示第i层应用激活函数之后的输出。

两层之间的运算可以看做是矩阵的运算(变换),站在矩阵变换的角度,矩阵A * B可以有理解为:

  1. 对A进行列变换
  2. 对B进行行变换

仔细体会这个变化,个人认为对后面可以直观理解神经网络的『表达能力』很重要。

参数学习

这个过程常常被称为反向传播,就是根据当前预估的结果,调整参数,使得损失函数变小。损失函数的选择一般是交叉熵(cross-entropy),这个损失函数和极大似然在有些情况下是等价的,如果C是所有的类别,那么我们的损失函数可以写为:

\(\begin{aligned} L(y,\hat{y}) = - \frac{1}{N} \sum_{n \in N} \sum_{i \in C} y_{n,i} \log\hat{y}_{n,i}\end{aligned}\)

上式想要表达的意思就是求和预估值和真实值之间的『差别』,然后求最小化上式的参数 \(W_1, b_1, W_2, b_2\) , 对上式对个个参数求偏导(使用到链式法则)可以得到:

\(\begin{aligned} & \delta_3 = \hat{y} - y \\ & \delta_2 = (1 - \tanh^2 z_1) \circ \delta_3W_2^T \\ & \frac{\partial{L}}{\partial{W_2}} = a_1^T \delta_3 \\ & \frac{\partial{L}}{\partial{b_2}} = \delta_3\\ & \frac{\partial{L}}{\partial{W_1}} = x^T \delta2\\ & \frac{\partial{L}}{\partial{b_1}} = \delta2 \\ \end{aligned}\)

下面仅对 \(W_2^1\) 的偏导数进行推导:

\(\begin{aligned}-\frac{\partial{L}}{\partial{W_2^1}} &= \frac{\partial{\sum_{i \in C}}{y_i\log{\hat{y_i}}}}{\partial{W_2^1}}\\&= \frac{\partial{\sum_{i \in C}}{y_i\log{{softmax(a_1W_2^i + b_2)}}}}{\partial{W_2^1}}\\&=\frac{\partial{\sum_{i \in C}}{y_i\log{\frac{e^{-(a_1W_2^i+b_2)}}{\sum_{k\in C}{e^{-(a_1W^k_2 + b_2)}}}}}}{\partial{W_2^1}} \\&=y_1\frac{-a_1 e^{-(a_1 W_2^2 + b_2)}}{\sum} + y_2\frac{a_1e^{-(a_1W_2^1 + b_2)}}{\sum}\\&=-a_1\left(y_1\frac{ e^{-(a_1 W_2^2 + b_2)}}{\sum} - (1-y_1)(1- \frac{e^{-(a_1W_2^2 + b_2)}}{\sum}) \right)\\&=a_1(y_1 - \hat{y_1})\end{aligned}\)

其中:

\(\sum = e^{-(a_1 W_2^2 + b_2)} + e^{-(a_1W_2^1 + b_2)}\)

并且容易证明softmax对数导数可以自表示:

\(\frac{\partial {\log softmax(x)}}{\partial x} = 1-softmax(x)\)

剩余的偏导数利用链式法则应该也可以推导出来(虽然我没有推)。理解反向传播和链式法则的好文 反向传播

实现

理论终于结束了,盼望已久的代码时刻O(∩_∩)O~

下面实现代码加入了L2正则,偏导数和上面写的略有不同。 实现的可执行的完整代码(点击展开):

figure_1

修改隐层节点个数

上面是将隐层节点数目设置为3,可以设置不同的隐层节点个数感受一下拟合结果:

结果如下图:

nn-from-scratch-hidden-layer-varying

拓展

  1. 本文中使用的是batch的方式,其实可以使用minibatch的方式,按照经验这种方式效果要好一些。
  2. 学习率有优化的空间,有不少自适应的方法
  3. 激活函数除了tanh之外可以尝试一下别的函数,例如sigmoid函数
  4. 将二分类变为分类
  5. 添加层数

参考

Implementing a Neural Network from Scratch in Python – An Introduction

 

未经允许不得转载:大数据算法 » 神经网络(Neural Network)实现

评论 抢沙发

*

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注大数据算法在工业界应用

本站的GitHub关于本站