穷举法的缺点
随着权重个数的增加,权重空间的维度提高,搜索区域呈指数型增长。
举例来说,假设对w搜索了100个数值,现在只有一个权重,只需要搜索一百次。如果有两个权重,那么需要搜索一个平面:100^2次;如果有10个权重,需要搜索100^10次。计算量太大,程序会算不出来。
分治法思路及缺点
分治法思路
把权重空间划分成16个区域,先搜索16次找到最小的局部区域,再将这个小的局部区域划分为16个区域,这样一共搜索了16+16=32次。
比从一开始搜索16*16=256次 搜索次数减少。
分治法的缺点
数据量过大时,划分空间搜索效率低。
针对凸函数成立,但针对非凸函数,可能最开始取的点略过了最小值区域,会陷入局部最小值。
凸函数的几何意义在于,定义域中任意两点连线组成的线段都在这两点的函数曲线(面)上方。由凸函数的定义可以类似地引出凹函数的定义:如果函数 f是凸函数,那么函数 −f是凹函数。从凸函数与凹函数的定义,我们可以发现所有的仿射函数(Affine Function)即满足凸函数的性质,又满足凹函数的性质,因此是“既凸又凹”的。
优化问题
定义:寻找使目标函数最小的自变量的值,此处找的是权重组合
梯度下降算法 Gradient Descent Algorithm
梯度方向上升最快,负梯度方向下降最快。
更新权重:往导数下降的方向走。
α:学习率,决定每一步走多远,一般取小一点,否则会出现以下情况。
数学分析
代码解析
计算损失函数
计算梯度,累加后除以长度
epoch:
epoch:当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一个 epoch。
其实cost_val不需要计算,是为了最后输出,能够画图,查看日志。
思想分析
利用了贪心法的思想:只看眼前最好的一步。不一定能得到最优的结果,但一定能得到在局部区域内最优的结果。
针对非凸函数,会出现陷在局部最优的情况。
但深度学习中仍然使用该方法的原因是:大家原本认为深度学习神经网络的目标函数会陷入上述情况,但实际上,神经网络的损失函数中的局部最优点较少。在深度学习中需要解决的最大问题是鞍点。
实际中,会存在特殊的点——鞍点:此处梯度=0
一维空间中,走到这已经无法迭代了。
鞍点:高维空间中,从一个切面看是最小值,从另一个切面看是最大值。
指数加权均值方法
能够将cost function 波动的曲线变圆滑
如果cost function 曲线出现下降又上升,说明训练发散了,本次训练是有问题的,最有可能原因是学习率取得太大。
随机梯度下降法SGD
stochastic gradient descent
实际在深度学习中,使用随机梯度下降法。在深度神经网络中被证明此方法是有效的。
数学分析
cost function中包含N个数据,我从这N个数据中随机选择一个。
权重更新公式发生变化:用单个样本的损失函数对权重求导进行更新
用该方法的原因
原本用包含N个数据的cost function陷入了鞍点,无法继续更新w。现在使用一个样本作为w更新公式,这是因为实际拿到的数据基本都是有噪声的,引入了随机噪声,那么我们陷入鞍点时,可能会继续推动w的更新。
引入了随机性,将来有可能跨越这个鞍点,向最优值前进。
代码解析
计算损失函数
计算梯度
对每一个样本的梯度进行了更新。(嗯其实这里并没有体现出随机性,后文自己写的代码做了修改,用了random.randint函数
Mini-Batch
在实际的深度学习中,会遇到问题:
使用梯度下降法时,计算xi和xi+1 的函数值时没有相互依赖关系。所以这些运算可以并行。效率高
个人理解,w计算时是前后相互依赖的,但每个点的梯度是固定的,这些计算可以并行
使用随机梯度下降法时,权重的更新有依赖,无法并行化。性能好
所以在深度学习中会用一种折中的方式
批量的随机梯度下降 称为Batch
小批量的随机梯度下降 Mini-Batch,由于目前该方法是主流,直接把前缀省略了,可以直接叫Batch
梯度下降法代码
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 能取到。
这里是为啥?还没想清楚...
随机梯度下降法代码
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)的写法改了一下,跑的结果不错。