穷举法的缺点
随着权重个数的增加,权重空间的维度提高,搜索区域呈指数型增长。
举例来说,假设对w搜索了100个数值,现在只有一个权重,只需要搜索一百次。如果有两个权重,那么需要搜索一个平面:100^2次;如果有10个权重,需要搜索100^10次。计算量太大,程序会算不出来。
![](https://i-blog.csdnimg.cn/blog_migrate/ee0e0c65f8a83f041bbfbbc382b3b436.png)
分治法思路及缺点
分治法思路
把权重空间划分成16个区域,先搜索16次找到最小的局部区域,再将这个小的局部区域划分为16个区域,这样一共搜索了16+16=32次。
比从一开始搜索16*16=256次 搜索次数减少。
![](https://i-blog.csdnimg.cn/blog_migrate/47d727174ce9adb8231c2c5384245ce1.png)
分治法的缺点
数据量过大时,划分空间搜索效率低。
针对凸函数成立,但针对非凸函数,可能最开始取的点略过了最小值区域,会陷入局部最小值。
凸函数的几何意义在于,定义域中任意两点连线组成的线段都在这两点的函数曲线(面)上方。由凸函数的定义可以类似地引出凹函数的定义:如果函数 f是凸函数,那么函数 −f是凹函数。从凸函数与凹函数的定义,我们可以发现所有的仿射函数(Affine Function)即满足凸函数的性质,又满足凹函数的性质,因此是“既凸又凹”的。
![](https://i-blog.csdnimg.cn/blog_migrate/8d559e83be204ce576065433d5b7376a.png)
优化问题
定义:寻找使目标函数最小的自变量的值,此处找的是权重组合
![](https://i-blog.csdnimg.cn/blog_migrate/454c19cffe33ac52bfd6403b6d664877.png)
梯度下降算法 Gradient Descent Algorithm
![](https://i-blog.csdnimg.cn/blog_migrate/06398bce1d681db2d41173d7cc36f694.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1874d74ea051c8baac4af4b1cd24ea93.png)
梯度方向上升最快,负梯度方向下降最快。
更新权重:往导数下降的方向走。
α:学习率,决定每一步走多远,一般取小一点,否则会出现以下情况。
![](https://i-blog.csdnimg.cn/blog_migrate/0e0db186c47a8a904f39292294ef138d.png)
数学分析
![](https://i-blog.csdnimg.cn/blog_migrate/13234dfb2136a09c93dee43f7b86f258.png)
![](https://i-blog.csdnimg.cn/blog_migrate/64168427e063c93a9f1b5a3c3ae98db1.png)
代码解析
计算损失函数
![](https://i-blog.csdnimg.cn/blog_migrate/8bdd300d1d24113aace522c4b3e7fdeb.png)
计算梯度,累加后除以长度
![](https://i-blog.csdnimg.cn/blog_migrate/de801fa3d99fb1b61de63d9d52537f25.png)
epoch:
epoch:当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一个 epoch。
其实cost_val不需要计算,是为了最后输出,能够画图,查看日志。
![](https://i-blog.csdnimg.cn/blog_migrate/592c858ea81b30af9de099f2d93407cd.png)
思想分析
利用了贪心法的思想:只看眼前最好的一步。不一定能得到最优的结果,但一定能得到在局部区域内最优的结果。
针对非凸函数,会出现陷在局部最优的情况。
![](https://i-blog.csdnimg.cn/blog_migrate/bacf47b79b1776dabf7e73e3fb70ad98.png)
但深度学习中仍然使用该方法的原因是:大家原本认为深度学习神经网络的目标函数会陷入上述情况,但实际上,神经网络的损失函数中的局部最优点较少。在深度学习中需要解决的最大问题是鞍点。
实际中,会存在特殊的点——鞍点:此处梯度=0
一维空间中,走到这已经无法迭代了。
![](https://i-blog.csdnimg.cn/blog_migrate/f6c3af1ae05c4322202054f4b377589f.png)
鞍点:高维空间中,从一个切面看是最小值,从另一个切面看是最大值。
![](https://i-blog.csdnimg.cn/blog_migrate/c1f35b36db032b51b4d33563efe16f14.png)
指数加权均值方法
能够将cost function 波动的曲线变圆滑
![](https://i-blog.csdnimg.cn/blog_migrate/8e3d8f82e41766ed93389a84733463e3.png)
如果cost function 曲线出现下降又上升,说明训练发散了,本次训练是有问题的,最有可能原因是学习率取得太大。
![](https://i-blog.csdnimg.cn/blog_migrate/9111d21bb7fd7521d8fa364aa2af2fa3.png)
随机梯度下降法SGD
stochastic gradient descent
实际在深度学习中,使用随机梯度下降法。在深度神经网络中被证明此方法是有效的。
数学分析
cost function中包含N个数据,我从这N个数据中随机选择一个。
权重更新公式发生变化:用单个样本的损失函数对权重求导进行更新
![](https://i-blog.csdnimg.cn/blog_migrate/7ff5e1b67ce0d67a82919b60d140d7cc.png)
用该方法的原因
原本用包含N个数据的cost function陷入了鞍点,无法继续更新w。现在使用一个样本作为w更新公式,这是因为实际拿到的数据基本都是有噪声的,引入了随机噪声,那么我们陷入鞍点时,可能会继续推动w的更新。
引入了随机性,将来有可能跨越这个鞍点,向最优值前进。
代码解析
计算损失函数
![](https://i-blog.csdnimg.cn/blog_migrate/30c34da47e3186f11c52b2bf56278037.png)
计算梯度
![](https://i-blog.csdnimg.cn/blog_migrate/81fb4f5c752371fed857ec3d45008078.png)
对每一个样本的梯度进行了更新。(嗯其实这里并没有体现出随机性,后文自己写的代码做了修改,用了random.randint函数
![](https://i-blog.csdnimg.cn/blog_migrate/591815575db8185921a18af04d5fd7dd.png)
Mini-Batch
在实际的深度学习中,会遇到问题:
使用梯度下降法时,计算xi和xi+1 的函数值时没有相互依赖关系。所以这些运算可以并行。效率高
个人理解,w计算时是前后相互依赖的,但每个点的梯度是固定的,这些计算可以并行
使用随机梯度下降法时,权重的更新有依赖,无法并行化。性能好
![](https://i-blog.csdnimg.cn/blog_migrate/1f3a11d7343d2322480e6e09fb60b0cd.png)
所以在深度学习中会用一种折中的方式
![](https://i-blog.csdnimg.cn/blog_migrate/2696d261dc2ee90cd4a80a9958a70f4c.png)
批量的随机梯度下降 称为Batch
小批量的随机梯度下降 Mini-Batch,由于目前该方法是主流,直接把前缀省略了,可以直接叫Batch
![](https://i-blog.csdnimg.cn/blog_migrate/2f12eaf96ac13a5f6a8b1f50d347d382.png)
梯度下降法代码
import matplotlib.pyplot as plt
# prepare the training set
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
# initial guess of weight
w = 1.0
# define the model linear model y = w*x
def forward(x):
return x*w
#define the cost function MSE
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)
# define the gradient function gd
def gradient(xs,ys):
grad = 0
for x, y in zip(xs,ys):
grad += 2*x*(x*w - y)
return grad / len(xs)
epoch_list = []
cost_list = []
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 # 0.01 learning rate
print('epoch:', epoch, 'w=', w, 'loss=', cost_val)
epoch_list.append(epoch)
cost_list.append(cost_val)
print('predict (after training)', 4, forward(4))
plt.plot(epoch_list,cost_list)
plt.ylabel('cost')
plt.xlabel('epoch')
plt.show()
学习率=0.01时,100个epoch后w=1.9999逼近2;
增大学习率=0.05时,在第58个epoch时能达到全局最优,w=2 能取到。
这里是为啥?还没想清楚...
![](https://i-blog.csdnimg.cn/blog_migrate/dee5c67212805884696e3fd9dc30403d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b752d0cb78bfc34c49a42b031b72b8a3.png)
随机梯度下降法代码
import matplotlib.pyplot as plt
import random
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = 5.0
def forward(x):
return x*w
# calculate loss function
def loss(x, y):
y_pred = forward(x)
return (y_pred - y)**2
# define the gradient function sgd
def gradient(x, y):
return 2*x*(x*w - y)
epoch_list = []
loss_list = []
print('predict (before training)', 4, forward(4))
# for epoch in range(100):
# for x,y in zip(x_data, y_data):
# grad = gradient(x,y)
# w = w - 0.01*grad # update weight by every grad of sample of training set
# print("\tgrad:", x, y, w,grad)
# l = loss(x,y)
for epoch in range(100):
rand = random.randint(0,2)
grad = gradient(x_data[rand],y_data[rand])
w = w - 0.01*grad # update weight by 三个数据集中的随机一个数据
print("\tgrad:", x_data[rand], y_data[rand], w, grad)
l = loss(x_data[rand], y_data[rand])
print("progress:",epoch,"w=",w,"loss=",l)
epoch_list.append(epoch)
loss_list.append(l)
弹幕提醒:视频中的代码是把所有数据都用来更新了w,没有提现随机性,所以我根据这个老哥梯度下降法解决线性模型_牛客博客 (nowcoder.net)的写法改了一下,跑的结果不错。
![](https://i-blog.csdnimg.cn/blog_migrate/4128e9f71dee4bbb499777665b74c231.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a2a71f5a1a129d7c0d8d4d30cf22a929.png)