赞
踩
以线性方程为例,设有线性方程:
y t r u e = θ 0 + θ 1 x 1 + θ 2 x 2 … + θ n x n y_{true} = \theta_0 + \theta_1x_1 + \theta_2x_2…+ \theta_nx_n ytrue=θ0+θ1x1+θ2x2…+θnxn
如果现在我们手头上已经有了N
组数据,其中第
i
i
i组数据为
[
x
i
,
1
x
i
,
2
x
i
,
3
…
x
i
,
n
]
[x_{i,1} x_{i,2} x_{i,3}…x_{i,n}]
[xi,1xi,2xi,3…xi,n]和其对应的
y
i
,
t
r
u
e
y_{i,true}
yi,true。
我们想要通过这N
组数据,估计出上述方程中的
θ
0
\theta_0
θ0到
θ
n
\theta_n
θn。
现在问题转化为:
我们想求出一组
θ
^
\hat{\theta}
θ^,使得这组
θ
^
\hat{\theta}
θ^无限逼近上述方程中的
θ
\theta
θ,又因为真实的
θ
\theta
θ是未知的,我们无法直接比较两者的误差关系,所以我们引入Lose Function
即误差函数来描述我们求得的
θ
^
\hat{\theta}
θ^到底准确与否。
有:
L o s e = J = 1 N ∑ i = 1 N ( y i , t u r e − y i ^ ) 2 Lose = J = \frac{1}{N}\sum^{N}_{i = 1}(y_{i, ture} - \hat{y_i})^2 Lose=J=N1i=1∑N(yi,ture−yi^)2
又因为,若设 x 0 = 1 x_0 = 1 x0=1有:
y ^ = θ 0 ^ x 0 + θ 1 ^ x 1 + θ 2 ^ x 2 … + θ n ^ x n \hat{y} = \hat{\theta_0}x_0 + \hat{\theta_1}x_1 + \hat{\theta_2}x_2 … + \hat{\theta_n}x_n y^=θ0^x0+θ1^x1+θ2^x2…+θn^xn
则 L o s e F u n c t i o n Lose Function LoseFunction可改写为:
J = 1 N ∑ i = 1 N ( y i , t u r e − θ 0 ^ x 0 − θ 1 ^ x 1 − θ 2 ^ x 2 … − θ n ^ x n ) 2 J = \frac{1}{N}\sum^{N}_{i = 1}(y_{i, ture} - \hat{\theta_0}x_0 - \hat{\theta_1}x_1 - \hat{\theta_2}x_2 … - \hat{\theta_n}x_n)^2 J=N1i=1∑N(yi,ture−θ0^x0−θ1^x1−θ2^x2…−θn^xn)2
可知上述误差函数 J J J有极小值,且使得 J J J最小的那一组 θ ^ \hat{\theta} θ^最接近真实的 θ \theta θ。
我们把问题简化一下若要求的线性方程为:
y = θ x y = \theta x y=θx
则根据上述
L
o
s
e
F
u
n
c
t
i
o
n
Lose Function
LoseFunction可得出以下关系:
要想让误差值即
J
J
J的值最小,目前估计的点P就需要朝着蓝色箭头的方向移动,直到找到这个二次曲线的极小值即最小值点。在程序中,若想让P向目标点移动,需要加上
−
η
d
J
d
θ
,
θ
=
θ
p
-\eta\frac{dJ}{d\theta}, \theta = \theta_p
−ηdθdJ,θ=θp。这里的
η
\eta
η就是学习率。
通过不断的移动P点,使得该次计算的 J J J值与上一次计算的 J J J值只差小于一个阀值,我们就认为找到了这个极小值点,且当前的 θ ^ \hat{\theta} θ^接近真实的 θ \theta θ。
而这个过程就是对 L o s e F u n c t i o n Lose Function LoseFunction优化的过程。
回到之前我们讨论的线性方程:
y t r u e = θ 0 + θ 1 x 1 + θ 2 x 2 … + θ n x n y_{true} = \theta_0 + \theta_1x_1 + \theta_2x_2…+ \theta_nx_n ytrue=θ0+θ1x1+θ2x2…+θnxn
对于多元线性方程的优化过程,由于参数由一个变成多个,所以这里的导数也上升为梯度,即 J J J在其所在点要对当前组中 θ 0 \theta_0 θ0到 θ n \theta_n θn均求偏导,而这样一组求偏导结果构成该点的梯度。
我们令 x 0 = 1 x_0 = 1 x0=1,则原方程可以改写为:
y t r u e = θ 0 x 0 + θ 1 x 1 + θ 2 x 2 … + θ n x n y_{true} = \theta_0x_0 + \theta_1x_1 + \theta_2x_2…+ \theta_nx_n ytrue=θ0x0+θ1x1+θ2x2…+θnxn
有 L o s e F u n c t i o n Lose Function LoseFunction为:
J = 1 N ∑ i = 1 N ( y i , t u r e − θ 0 ^ x 0 − θ 1 ^ x 1 − θ 2 ^ x 2 … − θ n ^ x n ) 2 J = \frac{1}{N}\sum^{N}_{i = 1}(y_{i, ture} - \hat{\theta_0}x_0 - \hat{\theta_1}x_1 - \hat{\theta_2}x_2 … - \hat{\theta_n}x_n)^2 J=N1i=1∑N(yi,ture−θ0^x0−θ1^x1−θ2^x2…−θn^xn)2
上式 J J J对 θ 0 \theta _0 θ0求偏导的结果为:
∂ J ∂ θ 0 = 2 N ∑ i = 1 N ( y i , t r u e − θ 0 ^ x 0 − θ 1 ^ x 1 − θ 2 ^ x 2 … − θ n ^ x n ) ( − x 0 ) \frac{\partial J}{\partial \theta_0} = \frac{2}{N}\sum^{N}_{i = 1}(y_{i, true} - \hat{\theta_0}x_0 - \hat{\theta_1}x_1 - \hat{\theta_2}x_2 … - \hat{\theta_n}x_n)(-x_0) ∂θ0∂J=N2i=1∑N(yi,true−θ0^x0−θ1^x1−θ2^x2…−θn^xn)(−x0)
即:
∂ J ∂ θ 0 = 2 N ∑ i = 1 N ( y i , t r u e − θ ^ x ) ( − x 0 ) \frac{\partial J}{\partial \theta_0} = \frac{2}{N}\sum^{N}_{i = 1}(y_{i, true} - \hat{\theta}x)(-x_0) ∂θ0∂J=N2i=1∑N(yi,true−θ^x)(−x0)
=> ∂ J ∂ θ 0 = 2 N ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 0 ) \frac{\partial J}{\partial \theta_0} = \frac{2}{N}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_0) ∂θ0∂J=N2∑i=1N(θ^x−yi,true)(x0),左式中 θ ^ \hat{\theta} θ^为行向量, x x x为列向量。
则 J J J对 θ i \theta _i θi求偏导的结果为:
∂ J ∂ θ 0 = 2 N ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x i ) \frac{\partial J}{\partial \theta_0} = \frac{2}{N}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_i) ∂θ0∂J=N2i=1∑N(θ^x−yi,true)(xi)
这样求完所有 θ \theta θ的偏导,构成该点的梯度:
∇ J ∇ θ = [ ∂ J ∂ θ 0 = 2 N ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 0 ) ∂ J ∂ θ 1 = 2 N ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 1 ) ∂ J ∂ θ 2 = 2 N ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 2 ) … … ∂ J ∂ θ n = 2 N ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x n ) ] \frac{\nabla J}{\nabla \theta} =\left[ \begin {matrix}\frac{\partial J}{\partial \theta_0} = \frac{2}{N}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_0) \\ \frac{\partial J}{\partial \theta_1} = \frac{2}{N}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_1) \\ \frac{\partial J}{\partial \theta_2} = \frac{2}{N}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_2) \\ … \\ … \\ \frac{\partial J}{\partial \theta_n} = \frac{2}{N}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_n)\end {matrix} \right] ∇θ∇J=⎣⎢⎢⎢⎢⎢⎢⎢⎡∂θ0∂J=N2∑i=1N(θ^x−yi,true)(x0)∂θ1∂J=N2∑i=1N(θ^x−yi,true)(x1)∂θ2∂J=N2∑i=1N(θ^x−yi,true)(x2)……∂θn∂J=N2∑i=1N(θ^x−yi,true)(xn)⎦⎥⎥⎥⎥⎥⎥⎥⎤
若此时估计的 θ \theta θ为:
θ ^ n o w = [ θ 0 ^ θ 1 ^ . . . θ n ^ ] \hat{\theta }_{now} = \left[ \begin {matrix} \hat{\theta_0} \\ \hat{\theta_1} \\ . \\ . \\ . \\\hat{\theta_n}\end {matrix}\right] θ^now=⎣⎢⎢⎢⎢⎢⎢⎡θ0^θ1^...θn^⎦⎥⎥⎥⎥⎥⎥⎤
若学习率为 η \eta η,则下一次迭代的 θ ^ n e x t \hat{\theta}_{next} θ^next为:
θ ^ n e x t = θ ^ n o w − η ∇ J ∇ θ = [ θ 0 ^ θ 1 ^ θ 2 ^ . . θ n ^ ] − 2 η N [ ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 0 ) ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 1 ) ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x 2 ) … … ∑ i = 1 N ( θ ^ x − y i , t r u e ) ( x n ) ] \hat{\theta}_{next} = \hat{\theta }_{now} - \eta\frac{\nabla J}{\nabla \theta} = \left[ \begin {matrix} \hat{\theta_0} \\ \hat{\theta_1} \\ \hat{\theta_2} \\ . \\ . \\\hat{\theta_n}\end {matrix}\right] - \frac{2\eta}{N}\left[ \begin {matrix}\sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_0) \\ \sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_1) \\ \sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_2) \\ … \\ … \\ \sum^{N}_{i = 1}(\hat{\theta}x - y_{i, true} )(x_n)\end {matrix} \right] θ^next=θ^now−η∇θ∇J=⎣⎢⎢⎢⎢⎢⎢⎡θ0^θ1^θ2^..θn^⎦⎥⎥⎥⎥⎥⎥⎤−N2η⎣⎢⎢⎢⎢⎢⎢⎢⎡∑i=1N(θ^x−yi,true)(x0)∑i=1N(θ^x−yi,true)(x1)∑i=1N(θ^x−yi,true)(x2)……∑i=1N(θ^x−yi,true)(xn)⎦⎥⎥⎥⎥⎥⎥⎥⎤
有的地方将除以 N N N凑成除以 2 N 2N 2N这样后边的因数化简为 − η N -\frac{\eta}{N} −Nη。
以上便是梯度下降解决线性回归的原理,大家可以自行对公式进行推导加深理解,附上Python仿真代码。
import matplotlib.pyplot as plt import numpy as np # 根据当前的theta求Y的估计值 # 传入的data_x的最左侧列为全1,即设X_0 = 1 def return_Y_estimate(theta_now, data_x): # 确保theta_now为列向量 theta_now = theta_now.reshape(-1, 1) _Y_estimate = np.dot(data_x, theta_now) return _Y_estimate # 求当前theta的梯度 # 传入的data_x的最左侧列为全1,即设X_0 = 1 def return_dJ(theta_now, data_x, y_true): y_estimate = return_Y_estimate(theta_now, data_x) # 共有_N组数据 _N = data_x.shape[0] # 求解的theta个数 _num_of_features = data_x.shape[1] # 构建 _dJ = np.zeros([_num_of_features, 1]) for i in range(_num_of_features): _dJ[i, 0] = 2 * np.dot((y_estimate - y_true).T, data_x[:, i]) / _N return _dJ # 计算J的值 # 传入的data_x的最左侧列为全1,即设X_0 = 1 def return_J(theta_now, data_x, y_true): # 共有N组数据 N = data_x.shape[0] temp = y_true - np.dot(data_x, theta_now) _J = np.dot(temp.T, temp) / N return _J # 梯度下降法求解线性回归 # data_x的一行为一组数据 # data_y为列向量,每一行对应data_x一行的计算结果 # 学习率默认为0.3 # 误差默认为1e-8 # 默认最大迭代次数为1e4 def gradient_descent(data_x, data_y, Learning_rate = 0.01, ER = 1e-10, MAX_LOOP = 1e5): # 样本个数为 _num_of_samples = data_x.shape[0] # 在data_x的最左侧拼接全1列 X_0 = np.ones([_num_of_samples, 1]) new_x = np.column_stack((X_0, data_x)) # 确保data_y为列向量 new_y = data_y.reshape(-1, 1) # 求解的未知元个数为 _num_of_features = new_x.shape[1] # 初始化theta向量 theta = np.zeros([_num_of_features, 1]) * 0.3 flag = 0 # 定义跳出标志位 last_J = 0 # 用来存放上一次的Lose Function的值 ct = 0 # 用来计算迭代次数 while flag == 0 and ct < MAX_LOOP: last_theta = theta # 更新theta gradient = return_dJ(theta, new_x, new_y) theta = theta - Learning_rate * gradient er = abs(return_J(last_theta, new_x, new_y) - return_J(theta, new_x, new_y)) # 误差达到阀值则刷新跳出标志位 if er < ER : flag = 1 # 叠加迭代次数 ct += 1 return theta def main(): # =================== 样本数据生成 ======================= # 生成数据以1元为例,要估计的theta数为2个 num_of_features = 1 num_of_samples = 2000 # 设置噪声系数 rate = 0 X = [] for i in range(num_of_features): X.append(np.random.random([1, num_of_samples]) * 10) X = np.array(X).reshape(num_of_samples, num_of_features) print("X的数据规模为 : ", X.shape) # 利用方程生成X对应的Y Y = [] for i in range(num_of_samples): Y.append(3 + 3.27 * X[i][0] + np.random.rand() * rate) Y = np.array(Y).reshape(-1, 1) print("Y的数据规模为 : ", Y.shape) # ====================================================== # 计算并打印结果 print(gradient_descent(X, Y)) if __name__ == '__main__': main()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。