赞
踩
在深度学习中,梯度下降算法发挥着重要作用。由于深度学习模型通常具有大量的参数,因此需要一个高效的优化算法来更新这些参数。梯度下降算法通过计算损失函数关于每个参数的梯度,沿着梯度的反方向更新参数,从而实现对模型的训练。
这个步骤可以通过调用已封装好的模块自动实现,但是为了加深对于模型原理的理解,本期我们以线性拟合为例介绍梯度下降算法的数学原理和代码实现。
在回归问题中,我们想利用已知的自变量
X
X
X建立回归模型,
来推测因变量
Y
Y
Y的值:
Y = b 1 X 1 + b 2 X 2 + ⋯ + b n X n + b 0 Y=b_{1}X_{1}+b_{2}X_{2}+\cdots+b_{n}X_{n}+b_{0} Y=b1X1+b2X2+⋯+bnXn+b0
可以发现,其中关键问题就在于各个系数
B
=
[
b
0
,
b
1
,
b
2
,
…
,
b
n
]
T
B=[b_{0},b_{1},b_{2},\ldots,b_{n}]^{T}
B=[b0,b1,b2,…,bn]T的求解,于是我们进行了大量的观测,并得到了n组实验数据
{ y 1 = b 0 + b 1 x 11 + ⋯ + b p x 1 p + ε , ⋮ y i = b 0 + b 1 x i 1 + ⋯ + b p x i p + ε , ⋮ y n = b 0 + b 1 x n 1 + ⋯ + b p x n p + ε . {y1=b0+b1x11+⋯+bpx1p+ε,⋮yi=b0+b1xi1+⋯+bpxip+ε,⋮yn=b0+b1xn1+⋯+bpxnp+ε. ⎩ ⎨ ⎧y1=b0+b1x11+⋯+bpx1p+ε,⋮yi=b0+b1xi1+⋯+bpxip+ε,⋮yn=b0+b1xn1+⋯+bpxnp+ε.
其中 ε \varepsilon ε表示每一次观测时产生的随机误差,这一点可以联系误差理论与测量平差去理解,因此实际上我们给出的是考虑平差后的观测方程。写成线性代数的形式就是
Y = X B + E Y=XB+\mathcal{E} Y=XB+E
E ∼ N ( 0 , Σ ) \\\mathcal{E}{\sim}N(0,\Sigma) E∼N(0,Σ)
为了求解
B
B
B,我们常采用两用算法,一种是最小二乘法(这个方法咱们以后讲),还有便是梯度下降算法。
梯度下降算法的主要思路是这样的:
在线性回归中,我们常用**均方误差(MSE)**作为损失函数,其公式为:
J ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 . J(\theta)=\frac{1}{2m}\sum_{i=1}^{m}(h_{\theta}\big(x^{(i)}\big)-y^{(i)})^{2}. J(θ)=2m1i=1∑m(hθ(x(i))−y(i))2.
其中
h θ ( x ( i ) ) = b 1 x 1 + b 2 x 2 + ⋯ + b n x n + b 0 h_{\theta}(x^{(i)})=b_{1}x_{1}+b_{2}x_{2}+\cdots+b_{n}x_{n}+b_{0} hθ(x(i))=b1x1+b2x2+⋯+bnxn+b0
耐心观察可以发现,MSE的实质就是对预测值和真值之间的误差求平均。
因此为了找到最合适的系数
B
B
B,我们要让损失函数的值最小。在第一步我们预设了系数的初始值,求出损失后需要对初始值进行修正,怎么实现呢?
在这里损失函数实质上是一个
(
n
+
1
)
(n+1)
(n+1)元的函数,在高等数学中我们知道函数中一点沿梯度方向存在上升/下降的最大速率,我们可以求出当前值的梯度,从而对每一个参数进行更新使得最后的总体损失逐渐下降。
梯度下降算法的关键在于其更新过程,公式表达如下:
θ j : = θ j − α ∂ ∂ θ j J ( θ ) . \theta_{j}:=\theta_{j}-\alpha\frac{\partial}{\partial\theta_{j}}J(\theta). θj:=θj−α∂θj∂J(θ).
其中
α
\alpha
α控制梯度下降算法的速率(也就是深度学习中的学习率),该算法是一个非常直观的算法,即每一次
θ
\theta
θ值的更新都沿着
J
J
J减小最快的方向。
当然,这里有一个必要的注意点:保证梯度下降算法达到全局最优解的条件是
J
(
θ
)
J(\theta)
J(θ)必须是凹函数。
下面求解每一步
θ
\theta
θ的改正值:
∂ ∂ θ j J ( θ ) = ∂ ∂ θ j 1 2 m ( h θ ( x ) − y ) 2 = 1 m ( h θ ( x ) − y ) ∂ ∂ θ j ( h θ ( x ) − y ) = 1 m ( h θ ( x ) − y ) ∂ ∂ θ j ( ∑ i = 0 n θ i x i − y ) = 1 m ( h θ ( x ) − y ) x j ∂∂θjJ(θ)=∂∂θj12m(hθ(x)−y)2=1m(hθ(x)−y)∂∂θj(hθ(x)−y)=1m(hθ(x)−y)∂∂θj(n∑i=0θixi−y)=1m(hθ(x)−y)xj ∂θj∂J(θ)=∂θj∂2m1(hθ(x)−y)2=m1(hθ(x)−y)∂θj∂(hθ(x)−y)=m1(hθ(x)−y)∂θj∂(i=0∑nθixi−y)=m1(hθ(x)−y)xj
所以梯度下降算法的更新准则是:
θ j : = θ j − α m ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) . \theta_j:=\theta_j-\frac{\alpha}{m}(h_\theta\big(x^{(i)}\big)-y^{(i)})x_j^{(i)}. θj:=θj−mα(hθ(x(i))−y(i))xj(i).
其中
m
m
m表示观测方程个数。
以上就是全部理论推导,我们只需利用更新准则不断对参数进行调整最终求得最优解。
在写代码时我们需要注意循环终止条件的设置,可以采取人为规定循环次数的方式(相当于深度学习中epoch)来终止循环。
下面是Python代码展示,此处我们只设置了
b
0
b_0
b0和
b
1
b_1
b1作为演示
import numpy as np import pandas as pd from tqdm import tqdm import matplotlib.pyplot as plt def DataLoader(path): # 加载数据 df = pd.read_csv(path, header=None) x = df.iloc[:, 0].values y = df.iloc[:, 1].values return x, y def get_J(x, y, b1, b0): # 计算损失函数 h = b1 * x + b0 delta2 = np.square(y - h) J = np.mean(delta2) / 2 return J def get_gradients(x, y, b1, b0): # 计算梯度 m = len(x) h = b1 * x + b0 grad_k = np.dot(h - y, x) / m grad_b = np.mean(h - y) return grad_k, grad_b def update(x, y, b1, b0, alpha): # 更新参数 grad_k, grad_b = get_gradients(x, y, b1, b0) b1 -= alpha * grad_k b0 -= alpha * grad_b return b1, b0 def main(): # 超参设置 alpha = 0.0008 epoch = 4000 path = './Data_Test2/Data/data.csv' x, y = DataLoader(path) # 初始化参数 b1 = 1 b0 = 0.3 # 列表存放每轮的损失,以便绘图 l = [] e = [] loss = get_J(x,y,b1,b0) l.append(loss) ep = 0 e.append(ep) # 梯度下降 for i in tqdm(range(epoch)): e.append(i+1) b1, b0 = update(x, y, b1, b0, alpha) loss = get_J(x, y, b1, b0) l.append(loss) plt.plot(e, l) plt.title('Loss vs. Epoch') plt.xlabel('Epoch') plt.ylabel('Loss') plt.show() if __name__ == '__main__': main()
运行结果展示:
可以发现该模型于500轮左右便已经收敛,因此可以适当减少训练轮数。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。