所学习的B站视频链接 2 梯度下降算法
目录
- 0 复习
- 1 模型原理
- 1.1 分治思路
- 1.2 梯度下降算法
- 1.3 梯度下降算法的数学模型推导
- 2 代码编撰
0 复习
上一次课堂中我们采用了最简单的线性模型进行了尝试,当时我们的输入维度和输出的维度均是一维的。
我们随机猜测我们的权重,看看什么样子的权重是可以让我们的损失函数\(MSE\)达到最小,采用的是一个暴力枚举法,来得到咱们的曲线。
但是这仅仅只是单一权重的方法,一旦咱们的权重组合多了,这个时候咱们的程序便非常的难以运行,这个时候需要采用其他的方法和思路进行处理。
1 模型原理
1.1 分治思路
假设有\(W_1和W_2\)这两个权重需要寻找,在进行搜索的时候先进行一些稀疏的计算,找到可能的最小区块,然后在那个区块里面进行搜索,不断重复几轮即可。
但是这个东西也不一定,因为实际上咱们的真实函数长得是非常的抽象的,而非普通的凸函数。上面的那个方法仅仅对比较好的凸函数才是可以使用的。对于下面这种函数而言,采用分治法很有可能会错过一些优秀点。
因此需要其他的方法进行使用。这种问题就是优化问题罢了。
1.2 梯度下降算法
仔细看上面这个图片,咱们的红点是所需要进行下降的点,我们需要寻找使得这个点下降的方向,向左还是向右。
对函数的自变量求偏导,得到的方向是函数上升的方向,因此我们需要取导数的一个负方向进行下降,即,
\[w = w - \alpha\frac{\partial cost}{\partial w}\]
可以看出他一直向着下降速度最快的方向进行跑动-贪心,但是这个不一定能找到最优解,只能找到一定区间内的局部最优点。例如下面这个函数
存在很多的局部最优点,这个时候采用咱们的梯度下降算法的时候是只能找到局部最优点,不能找到全局最优点。
但是实际使用的过程中,咱们在进行深度学习的过程中,局部最优点是比较少的,因此大量的使用梯度下降算法。
但是会存在鞍点也就是所谓的\(f'=0\)的点
对于这个位置一旦到达时刻,便会停止迭代,此时会陷入到鞍点无法进行运动。毕竟导数为零了,学习率不论是多少都已经没有用了。
\[w = w - \alpha\frac{\partial cost}{\partial w}=w - 0\alpha\]
可见最大的问题就是鞍点的问题了,我们要尽可能的避免鞍点。
1.3 梯度下降算法的数学模型推导
首先先给出上一次课程的损失函数,咱们用这个函数进行推导
\[\frac{1}{N}\sum_{n=1}^{N}(x_{n}\cdot\omega-y_{n})^{2}\]
对这个损失函数进行求导可以得到
\[\begin{aligned}\frac{\partial cost(\omega)}{\partial\omega}&=\frac{\partial}{\partial\omega}\frac{1}{N}\sum_{n=1}^{N}(x_{n}\cdot\omega-y_{n})^{2}\\&=\frac{1}{N}\sum_{n=1}^N\frac{\partial}{\partial\omega}(x_n\cdot\omega-y_n)^2\\&=\frac{1}{N}\sum_{n=1}^{N}2\cdot(x_{n}\cdot\omega-y_{n})\frac{\partial(x_{n}\cdot\omega-y_{n})}{\partial\omega}\\&=\frac{1}{N}\sum_{n=1}^{N}2\cdot x_{n}\cdot(x_{n}\cdot\omega-y_{n})\end{aligned}\]
最后可以求出来咱们的训练过程进行更新
\[\begin{aligned}\omega&=\omega-\alpha\frac{\partial cost}{\partial\omega}\\&=\omega-\alpha\frac{1}{N}\sum_{n=1}^{N}2\cdot x_{n}\cdot(x_{n}\cdot\omega-y_{n})\end{aligned}\]
这就是咱们的更新函数\(Update\)
2 代码编撰
2.1 分块解答
- import numpy as np
- import matplotlib.pyplot as plt
复制代码引入两个库函数
- x_data = [1.0 , 2.0 , 3.0]
- y_data = [2.0 , 4.0 , 6.0]
复制代码引入需要使用的训练集数据
定义一个猜测,初始化权重
- def forward(x):
- return x*w
复制代码定义 \(\hat{y}\) 的公式,令\(\hat{y}=\chi*\omega\)
- def cost(xs , ys):
- sum = 0
- for x , y in zip(x_data , y_data):
- sum += forward(x)**2
- return sum/len(xs)
复制代码定义这个平均损失函数\(MSE\),\(cost(\omega)=\frac{1}{N}\sum_{n=1}^N(\hat{y}_n-y_n)^2\)
- def grad(xs , ys):
- sum = 0
- for x , y in zip(xs , ys):
- sum += 2*x*(forward(x) - y)
- return sum/len(xs)
复制代码定义这个梯度函数\(Gradient\),\(\frac{\partial cost}{\partial\omega}=\frac{1}{N}\sum_{n=1}^N2\cdot x_n\cdot(x_n\cdot\omega-y_n)\)
- for epoch in range(100):
- cost_val = cost(x_data , y_data)
- grad_val = grad(x_data , y_data)
- w -= 0.01*grad_val
复制代码开始进行学习拟合处理,\(\omega=\omega-\alpha\frac{\partial cost}{\partial\omega}\)
训练更新的过程,这个\(0.001\)是学习率,这个是自己取得,凭感觉把。
不难看出这个玩意儿是收敛到\(w=2\)的。
只要是总体收敛便就可以了。
当然实际上可以采用指数均值的方式将这个图像变得更加的平滑。
如果你的训练图像,学着学着,成下面这个样子,那么你就训练失败了,可以适当降低学习率。
实际上我们梯度下降用的不多用的是随机梯度下降多一些。
- 更新函数
- \(Gradient Descent : \omega=\omega-\alpha\frac{\partial cost}{\partial\omega}\)
- $ Stochastic Gradient Descent : \omega=\omega-\alpha\frac{\partial loss}{\partial\omega}$
- 梯度求导
- \(Deribative of Cost Function : \frac{\partial cost}{\partial\omega}=\frac{1}{N}\sum_{n=1}^N2\cdot x_n\cdot(x_n\cdot\omega-y_n)\)
- \(Derivative of Loss Function : \frac{\partial loss_n}{\partial\omega}=2\cdot x_n\cdot(x_n\cdot\omega-y_n)\)
从里面随机选择一个就可以了,就直接拿上单个损失直接用,注意随机二字
这个有可能可以跨过去鞍点哈,也是有点运气成分的额。
看看相对于梯度下降而言,这个随机梯度下降的代码做了些修改- def loss(x , y):
- y_pred = forward()
- return (y_pred - y)**2
复制代码重新计算损失函数,\(loss=(\hat{y}-y)^{2}=(x*\omega-y)^{2}\)
- def grad(x , y)
- return 2 * x * (x*w - y)
复制代码重新计算梯度函数,\(\frac{\partial loss_n}{\partial\omega}=2\cdot x_n\cdot(x_n\cdot\omega-y_n)\)
- for epoch in range(100):
- for x,y in zip(x_data , y_data):
- gradient = grad(x , y)
- w = w - 0.001 * gradient
- print("\tgradient:" , x , y , gradient)
- l = loss(x , y)
复制代码重新进行学习更新
不过在真正的深度学习的过程中,梯度下降中每一个\(f(X_i)\)是相互独立的,是可以并行求解的。因此他的时间复杂度低,代码的效率高。但是由于计算量过大因此性能很低。
但是随机梯度下降中的\(w\)是从上一个哪来的,前后两个是由依赖的,算法的效率过低时间复杂度高,但是他的性能比较高
因此我们会使用\(Batch或是Mini-Batch\)进行两种算法的一个这种,一部分进行随机梯度下降,一部分进行梯度下降。分组进行使用。
2.2 代码综合
首先是最原始的梯度下降算法的代码
- '''@name: 梯度下降算法'''import numpy as np
- import matplotlib.pyplot as pltx_data = [1.0 , 2.0 , 3.0 , 4.0]y_data = [2.0 , 4.0 , 6.0 , 8.0]w = 1.0def forward(x):# 前馈相乘求假设 global w return x*wdef cost(xs , ys):# 计算平均误差和 res = 0 for x,y in zip(xs , ys): res += (x*w - y)**2 res = res /len(xs) return resdef gradient(xs , ys):# 求解相应的梯度 sum = 0 for x , y in zip(xs , ys): sum = 2*x*(x*w-y) sum = sum/len(xs) return sum epc_list = []cos_list = []for epoch in range(0 , 100 , 1):# 进行程序深度学习 epc_list.append(epoch) cost_val = cost(x_data , y_data) cos_list.append(cost_val) grad_val = gradient(x_data , y_data) w -= alpha * grad_valplt.plot(epc_list , cos_list , 'r')plt.xlabel('epoch')plt.ylabel('MSE')plt.show()
复制代码
其次是更新后的随机梯度下降算法的代码
- '''@name: 随机梯度下降算法'''import numpy as np
- import matplotlib.pyplot as pltdef forward(x):# 前馈相乘求假设 global w return x*wdef loss(x , y):# 计算平均误差和 return (forward(x) - y)**2def gradient(x , y):# 求解相应的梯度 return (2*x*(forward(x) - y))x_data = [1.0 , 2.0 , 3.0 , 4.0]y_data = [2.0 , 4.0 , 6.0 , 8.0]w = 1.0alpha = 0.01 # learning rateepc_list = []loss_list = []for epoch in range(0 , 100 , 1):# 进行程序深度学习 epc_list.append(epoch) n = 0.0 sum = 0.0 for x,y in zip(x_data , y_data): n+=1 grad = gradient(x , y) w = w - 0.01 * grad l = loss(x , y) sum += l sum =sum / n loss_list.append(sum)plt.plot(epc_list , loss_list , 'r')plt.xlabel('epoch')plt.ylabel('loss')plt.show()
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |