来补一下神经网络的基础
神经网络
人工神经网络中的神经元的结构
有n个输入以及一个偏置被一起加起来,加起来之后再对它应用一个所谓的激活函数,然后得到输出,前一部分加的过程就是一个线性的,加权的特征的相加,然后再加上一个偏置,然后就得到了我们最开始的结果。
一个神经元我们可以把它看成有线性的部分和非线性的部分。 非线性大致就指的是这个激活函数。
我们先来看一下最简单的神经网络,最简单的就是一个神经元构成的神经网络
这个的激活函数就是g,也被进行了限制,0以上返回值都是1,0以下返回值都是0
多层神经网络
神经网络是我们不停地增加神经元和层数,他们之间的连接最后会模拟出一个函数,和我本身想要拟合的函数已经是非常接近了,那么在这种情况下,我得到的预测值就跟本身这个东西应该有的值非常接近,这个就差不多是神经网络。
就类似于泰勒展开式,泰勒公式就是由一系列简单的函数组合形成的复杂函数。
结构就是
这次偏置放到了每个神经元的单元里。
只要不是输出的,也不是输入的,中间这个就叫做隐藏层。隐藏层对外是不可见的
sigma
sigma就是我们刚刚说的激活函数,而且我们希望它是非线性的。
函数的选择对模型训练的影响
之前用的大多数是sigmoid function,但是它会在训练中出现梯度弥散问题,也就是梯度值的大小越来越小,最后消失的问题,也就是训练就停止了,没有办法继续进行,也就没有办法训练的更好
现在最常用的就是这个ReLU,它就是小于0的时候就是0,大于0的时候斜率为1的函数。它最主要的特色就是可以去解决梯度弥散的问题。由于它小于0的时候就是0了,所以它会对这个神经网络进行一定的稀疏化。也就是有些神经元以后就没有用了。坏处也很明显,一个神经元死了之后,我可能就没有办法再把它激活了。所以后续又出现了几个ReLU的变形
随机梯度下降算法(optimizer)
梯度大家都了解吧,对于每一个参数求一个导数,这就是梯度。
w是我们神经网络中的参数
样本数是n个,Q是函数值,这个值可能是损失函数什么的,Q(w)是把我们所有的样本的损失函数做一个平均。
这就是它随机性的来源,这就是非常经典的随机梯度下降算法
它还有很多其他的随机梯度算法
随机梯度算法也有很多自己的问题,比如说你需要给他一个学习速率,那这个学习速率也会决定这个收敛的能力,因为随机速率如果过大的话,可能会进行一定的震荡,比较难收敛,过小的话,可能会太慢了。
理论上,梯度算法是针对于,一些有特定性质的函数,就是凹函数或者凸函数,这类性质比较好的函数。它是一定可以收敛到最优值得。对于一般得非凸函数它其实不一定收敛到最优值。所以神经网络最初得值呢,往往会给他一个随机分布,一个随机值。然后让他开始训练。为什么要是随机呢?其实也就是为了防止它会被卡在一些所谓得局部最优值,而不是全局最优值。
损失函数
损失函数有很多,损失函数的选择跟你想要得到的结果是有关系的。
比如你想训练的是一个分类器,那可能就不能用均方误差这样的损失函数。而应该用01的或者是交叉熵之类的误差,而如果是预测一个值的话,可能就可以使用均方误差或者是绝对值误差之类的。
现在我们求一下损失函数的梯度,比如我们假设损失函数是C,它肯定是我们真实的Y和我们估算出来的Y hat的一个函数,我们要对w求导,因为Y hat是一个w的函数,根据链式法则,我们要对这个误差求导的时候,就会先对Y求导,然后再用Y对z求导,再乘以z对w求导
非常巧的是,前一层的梯度,就等于后一层的梯度乘上激活函数的导数和下一层的权值
反向传播算法
对每一个样本,输入a之后,做一个前馈网络,前馈网络就是从第二层开始,我们不停地算z等于wa加上b,a就等于运用了激活函数z,然后它的输出output error就被用来计算下面的这个方程,这个方程它用了一个所谓的hadamard product,就是把两个向量,每一个对应位置都乘起来,再形成一个新的向量,就是它每一个对应位置的值,乘起来之后形成的新的向量。然后我们再说一下backpropagate the error,再回馈这个反向传播所谓的误差,但是它是从L-1 一直到 第2层来做的,那它其实也是同样地去乘hadamard product,那我们最后一步就是去做gradient descent ,它就是用w_l 等于w_l减去eta除以m,乘以这一串
在这个训练过程中,有一个 一直存在的东西,就是激活函数的导数,
这也就是为什么说激活函数可能对训练的过程产生质的影响
假如激活函数选的不太好的话,可能会出现激活函数的梯度可能大概率是一个小的东西,那如果它一直不停地乘起来,(因为我们反向传播,它每一层都去乘了这个东西,每一层都乘了一遍)最终到深层的时候,就会发现,这个神经网络基本上不更新了,因为这是反向传播,所以输出层的时候,那个梯度比较大,然后梯着梯着到最初那一层的时候,就是到输入层后面的,那个第一个隐藏层的时候,就已经没有什么值了,w就没办法更新了,就没有办法提高,没有办法优化我的损失函数了,这个就被称为梯度弥散。
通常就是换成ReLU,之类的解决这个问题。
Keras
它是由python编写地一个高级神经网络的api
它已经抽象地十分顶层了,所以运用起来非常方便
简单介绍一下上诉概念在keras的这些api中,到底是什么东西
比如这个神经网络叫做wide and deep,然后它有一个输入层,两个隐藏层,一个所谓的concat(连接层),还有最后的输出层。连接层就是说我把两个连接起来,就是两个输入直接连接起来就输出了
用Keras编写就是这样
这里的这个输入层就是一个一维的向量,第一个隐藏层是一个有三十个神经元的,激活函数是relu的的东西,参数是inpu,所以它就跟input连起来了。然后第二个隐藏层它是跟第一个隐藏层hidden one连起来的,它也是有三十个神经元,并且它的激活函数也是relu。concat就是直接把输入层和隐藏层2的输出连起来,最后一层就是一个只有一个神经元的输出层
这个model是要被编译的,然后这个编译的过程中,会给model一个损失函数,这里就用的是min squared error
这个模型被编译之后,我们就可以去选择做一个拟合,所谓的拟合就是训练的过程
epochs就是我们走了多少遍,我们给他的训练数据,走一遍所有的数据,就是一个epoch