人工神经网络(Artificial Neural Network)
后向传播公式:http://blog.csdn.net/yunpiao123456/article/details/52526907
历史沿袭:
人物关系:
感知器(Perceptrons) :
参考《统计学习方法》李航著中的第二章
感知机是二分类线模型。于1957年由Rosenblatt提出。是神经网络与支持向量机的基础。
感知机模型:
损失函数:
梯度计算:
参数更新:
收敛性:
由第二点我们可以看出,感知机的收敛性速度和学习速率无关,真的很神奇。而且速率小的话,更能够获得复杂度更低的参数。至于为什么收敛速度和学习速率无关,我觉可能是和这种模型有关。因为他的输出是sign函数,这个函数在除零以外的区域导数都为零,而在零处的导数不存在,就是说在零附近只要移动一点点,就能改变输出结果,学习率小也没有问题。而且我们初始化参数时,总是把w和b置为零,所以开始就在零处,所以只要动一点点就可以移动到对应的输出。这也让我想到了神经网络中使用的Batch Normailzation,BN会让我们的分布趋于原点附近,那么也就是说如果我们的参数输出化也在原点附近,那么就近似具有单层感知机的这种和学习速率无关的特性,能过尽快地进行收敛。
我这里写了份代码说明这件事情:
#include <iostream> #include <vector> using namespace std; std::vector<double> x[2],w; double y[2] = {1, -1},b=0; double rate = 0.00000001; bool notGood(int &t){ for (int i = 0 ; i < 2 ; i++){ double rr = 0; for (int j = 0 ; j < 2 ; j++){ rr += w[j]*x[i][j]; } rr += b; // cout << rr<<endl; if( y[i]*rr <= 0){ t = i; return true; } } return false; } void iterat(int t){ b += rate*y[t]; for (int i = 0 ; i < 2 ; i++){ w[i] += rate*y[t]*x[t][i]; } } void print(int t){ cout <<t<<":"; for (int i = 0 ; i < 2 ; i++){ cout << w[i]<<","; } cout << b<<endl; } int main(){ w.push_back(0); w.push_back(0); x[0].push_back(1); x[0].push_back(1); x[1].push_back(2); x[1].push_back(2); int t; while( notGood(t) ){ iterat(t); print(t); } return 0; }
支持向量机:
说到感知机,就不得不说一下支持向量机。
感知机给出的超平面会因为初始条件和学习率设置的不同而不同,答案不是唯一的。为了保证答案唯一,我们希望超平面能尽量处于两种数据点的中间,这就引入了最大间隔和支持向量的概念,也就有了支持向量机。支持向量机加上惩罚项和核函数等,就能够处理那些非线性可分的数据,大大提高了支持向量的能力。
多层感知机:
前面讲的是单层二分类线性感知机,但是为了处理非线性可分的数据,我们引入多层感知机(MLP, Multilayered Perceptron)。同时为了学习MLP,发明了误差后向传播算法(BP, Error Back Propagation)。MLP是最基本的人工神经网络结构。
其实一个机器学习模型最关键的不是它的结构,而是它的性质分析如收敛性,误差上下界以及优化方法。人工神经网络的向后传播算法可以说是一种十分优美的优化算法,它是对梯度下降算法的强大应用。
后向传播算法(BP, Error Back Propagation):
具体推导可看:http://wenku.baidu.com/view/802b9de9011ca300a6c3909e.html?from=search
就是这里梯度有个神奇的性质,就是从输出端到输入端的梯度可以逐级向后传导,而且就是沿着向前传播的方向路径。而且误差的权重和向前输出的权重竟然也是一样的。如果没有向后传播算法,我们就只能一下计算所有参数的偏导数,然后进行更新,然而数学不知为啥让梯度下降具有了如此优美的性质,让我们能够一级一级的向后传播梯度,大大减少了优化复杂度。我觉得神经网络最优美的地方不是什么模仿了人类的神经传递或者什么激活神经,而是这个向后传播算法,没有向后传播算法,神经网络也就是一个表面上搭起来好看的空壳子而已。而这个优美不是这个算法的优美,是数学的优美,是数学允许我们进行梯度的向后传播。
既然BP算法这么好,那么就有很多工作是基于优化BP算法的。首先就是加入动量信息。这是为了加快收敛速度,使得梯度下降在平坦的地方能够更快的移动。
激活函数可以使得神经网络具有非线性的特性,目前最常用的激活函数是RELU,下面展示一些常见的激活函数及其导数(activation functions):
Sigmoid函数:
导数为
tanh函数:
导数为
RELU:
导数为
在分类问题中,我们经常会用到softmax回归,关于softmax回归,ufldl上已经说得很清楚了:
前面讲的都是MLP,但是神经网络的发展肯定离不开卷积和池化操作。
由于池化比较简单,首先介绍池化:
池化英文名为pooling,分为mean-pooling,max-pooling和stochastic-pooling。一般用的都是max-pooling。pooling层的后向传播比较简单,对于mean-pooling,就把误差平均分为4分往后传,对于max-pooling和stochastic-pooling就是向后传到对应的位置。一般介绍pooling层会提到平移不变性(translation invariant),举个简单的例子就是:假如三个元素(1,5,3)取max就取到5,如果三个元素向右平移一下变成(3,1,5),那取max之后还是5,这就具备平移不变性。但是实际中通常用的pooling大小为2,这种平移不变形很难体现出来。最近做模型压缩的人甚至能把pooling层用卷基层给代替了,所以pooling层是否真的有必要,还需要更多讨论。
然后讲讲卷积层。个人觉得卷积层应该能够代替全连接层,还能减少参数,所以可能全卷积网络就足够了,当然激活函数是不能少的。卷积原理很简单,有趣的还是计算卷积的参数个数:
对于梯度下降优化,现在用得比较多的是Mini-batch Gradient Descent,就是每次取一定数量的样本进行梯度下降,这样会增加训练的稳定性和训练速度。最近有研究表明batch设得过大会造成形成的函数比较陡峭,所以batch要设置比较合适才行。
为了处理具有时序关系的数据,我们还会用到递归神经网络(RNN, Recurrent Neural Networks), RNN中比较著名的例子就是LSTM(Long Short-Term Memory)。其实RNN和普通ANN没什么区别,只是输入的数据有点不同,RNN会从以前的输出数据中作为现在的输入数据。
胡普菲尔得神经网络(HNN, Hopfield Neural Networks):
参考资料:http://wenku.baidu.com/view/334d3abafab069dc50220166.html?from=search
HNN有美国加州理工学院物理学家J. J. Hopfield教授于1982年提出,是一种单层反馈神经网络。分为离散值和连续值两种情况。连续值的网络能够解决旅行商问题(TSP)。关键词是串行工作,并行工作,稳定状态,能量函数。
训练神经网络还要防止过拟合,比较常见的办法就是dropout,一般加在全连接层后面。