利用pytorch进行深度学习(3)
本章内容基于刘老师的https://www.bilibili.com/video/BV1Y7411d7Ys?p=3
(一)寻找权重
我们遇到数据时,首先会去使用线性模型来尝试其是否符合,因为线性模型比较简单,在使用线性模型的过程中,我们需要去猜测 y = w*x+b中的权重w,当我们猜测的权重符合数据时,我们所得到的模型输出就会与实际值相符,如下图中的红线那样。

但我们在一开始并不知道模型的权重具体是有多大,因此我们需要想办法来锁定目标权重。
(1)穷举法
我们首先想到了穷举法,利用穷举法在一定范围内试探w所得到的结果是否与实际值相符合来确定最终权重,如上一讲中的案例,但穷举法有个很大的缺点就是当权重数量比较多,算法的时间复杂度会迅速上升,比如y(w1,w2,b)时,对每个权重穷举100次,那么总的就要穷举10万次,这样做很不明智。
(2)分治算法
我们联想到了分治算法来找最佳权重,例如在一个范围内原先是进行穷举100次,现在我只对这个范围穷举4次,如果权重有两个w1,w2,那么我们就相当于把范围划分为了16个区域,我们对每个区域进行求算,找出比较小的区域,然后再对该区域进行划分,又划分为16个小区域,寻找每个小区域中最优区域,这样我们找到最优区域也许只要花16+16=32次

但我们在找最优值时有个致命缺点,那就是容易陷入局部最优,因此我们只有在凸函数的情况下才可以去用分治算法

所以我们需要去找使目标函数最好的权重组合,这样的问题叫做优化问题
(二)梯度下降(Gradient Descent)

(1)定义及其问题
权重问题的寻找迎来我们本节的主题——梯度下降算法。首先要注意的是我们在定义的时候,为什么要用减法,这是因为我们要找损失函数的最小值,当导数是正的时候,则应该往导数的反方向行进才可以到达最小值,所以取符号。其次与导数相乘的为学习率,学习率在设置的时候应该尽可能的小,因为太大的学习率可能导致导数跑得太快找不到收敛的地方,就像图中小邱那样大幅度折线跑。梯度下降的本质就是贪心算法,贪心算法有一个缺点就是只能得到局部的最优值而不一定是全局的最优点,同理梯度下降算法也有相同的困扰。所以当我们对非凸函数(函数中任意两点间连线不能保证其都在函数上方)进行优化时,很可能会陷入局部最优就收敛。但为什么在深度学习里面会大量使用梯度下降算法呢,因为在深度学习中并不存在很多局部最优点,但是它存在特殊的点——鞍点,即导数为零的点。


由于鞍点的存在,会导致梯度下降算法陷入鞍点里无法运动,在高维空间上的鞍点(如上右图),在某个方向上看他可能是最小值,但在另外一个方向可能是最大值,因此在深度学习中困扰的不是局部最优问题,而是鞍点问题,因为鞍点的存在可能导致无法进行迭代。
(2)推导公式
我们对损失函数进行求导,将求导得到的公式对梯度下降算法进行更新

(3)代码展示
x_data = [1.0,2.0,3.0] y_data = [2.0,4.0,6.0] w = 1.0 #初始权重 def forward(x): return x*w def cost(xs,ys): cost = 0 for x,y in zip(xs,ys): y_pred = forward(x) cost += (y_pred-y)**2 return cost/len(xs) def gradient(xs,ys): grad = 0 for x,y in zip(xs,ys): grad += 2 * x * (x * w - y) return grad/len(xs) print('Predict (before training)', 4 , forward(4)) for epoch in range(100): cost_val = cost(x_data,y_data) grad_val = gradient(x_data,y_data) w -= 0.01*grad_val print('Epoch:', epoch, 'w=', w, 'loss=', cost_val) print('Predict (after training)' , 4 , forward(4))
(4)结果分析
我们将数据的结果绘制成图保存下来

我们可以看到在一开始损失函数快速下降,到后面趋于平缓,这个时候预示着我们快收敛到最优值了。在这个例子里面损失值降到了0,但在实际生活中我们一般是无法降到0的,因为存在噪声,实际的损失值应该是波动下降,因此我们可以做一个叫做指数加权平均的方法,把波动的曲线变为一个平滑曲线,关于指数加权平均的方法可看:https://zhuanlan.zhihu.com/p/29895933

但如果将来的损失函数迭代过程变为下图这样的整体为一个凹向,那么就代表着,损失函数发散了,虽然他也有一个最小值,但这并不代表那个最小值就是最优的,因为正常的收敛肯定是趋近于上图那样的情况,对于训练集来说这样凹着代表这次训练失败了,训练是失败的原因有很多,其中一种常见的原因就是学习率取得太大,可以尝试把学习率降低一点来观察损失函数的情况。
(5)随机梯度下降
事实上在深度学习中,梯度下降我们用的并不多,我们一般用的都是梯度下降的延伸版本——随机梯度下降(stochastic gradient descent,SGD)

随机梯度下降与梯度下降的不同之处在于将对全体损失函数的求导转为了随即对单个样本的损失函数进行求导然后进行更新,为什么要这样做呢?这是为了解决鞍点问题,当我们在对于鞍点无法迭代时,我们利用随机梯度下降就可能跨过鞍点直接下降,这已经在神经网络中被证明了是非常有效的方法。
在深度学习的真正问题中,我们用模型计算每个点的函数值,比如计算得到的f(xi)函数值和f(xi+1)函数值之间是没有关系的,所以这些运算是可以并行的,但如果我们用了随机梯度下降,由于下一个的权重g(xi+1)是由上一个的权重g(xi)传递下来的,所以每个样本的函数值计算是不可以并行的。

所以利用梯度下降性能是最优的,因为可以并行计算,而利用随机梯度下降,时间复杂度比较高,所以我们可以得到一个表:

所以我们经常会想在性能和时间复杂度之间取一个这种,这种批量的随机梯度下降算法被称为Batch,Batch会把所有样本分为许多组,每个组进行随机梯度下降,而对组内的样本进行梯度下降,在深度学习中梯度下降算法默认使用Batch,实际上Batch原始含义为“全部的”,所以我们正式的叫法应该是叫Mini-Batch,有的时候有些接口会说采用的是Batch,实际上我们应该知道它采用的是Mini-Batch,现在的含义中Batch即为Mini-Batch.

浙公网安备 33010602011771号