机器学习 梯度下降算法数学原理(以多元线性回归为例)及Python实现

1、参数说明

训练集中样本用 x ^ \hat{x} x^表示,每个样本可以多个特征,第i个样本的第j个特征记为xij 用向量形式表示,则为 x i ^ \hat{x_i} xi^=[xi1,xi2,xi3…xin]T
训练集每个样本的真实值用y表示,第i个样本的真实值为yi
特征与真实值是基于训练目的来定的。比如训练一个输入身高体重,输出年龄的模型,则特征就为身高体重,样本真实值就为年龄。
模型对每个样本的预测值记为 h θ h_\theta hθ( x ^ \hat{x} x^)= θ 0 \theta_0 θ0+ θ 1 x 1 \theta_1x_1 θ1x1+ θ 2 x 2 \theta_2x_2 θ2x2…+ θ n x n \theta_nx_n θnxn
其中, θ i \theta_i θi为样本 x ^ \hat{x} x^的第i个特征对应的权重,即预测值为样本所有特征值的线性加权求和(梯度下降考虑的是线性加权求和,在此不考虑非线性)
若记x0=1,则 h θ h_\theta hθ( x ^ \hat{x} x^)可写为 ∑ i = 0 n θ i x i \sum_{i=0}^n\theta_ix_i i=0nθixi
如果把权重也写成向量形式,即 θ ^ \hat{\theta} θ^=[ θ 1 \theta1 θ1, θ 2 \theta2 θ2, θ 3 \theta3 θ3 θ n \theta n θn]T,则预测值 h θ h_\theta hθ( x ^ \hat{x} x^)可写为 h θ h_\theta hθ( x ^ \hat{x} x^)=( θ ^ \hat{\theta} θ^)T x ^ \hat{x} x^。注意,真实值和预测值都是一个数值

2、梯度:

对一个多元函数F(x1,x2,…xn)来说,记每个分量xi方向上的单位矢量为 e i ^ \hat{e_i} ei^,则它的梯度 ▽ \triangledown F= ∂ F ∂ x 1 \frac{\partial F}{\partial x_1} x1F e 1 ^ \hat{e_1} e1^+ ∂ F ∂ x 2 \frac{\partial F}{\partial x_2} x2F e 2 ^ \hat{e_2} e2^+…+ ∂ F ∂ x n \frac{\partial F}{\partial x_n} xnF e n ^ \hat{e_n} en^。微积分告诉我们梯度在所有方向导数中增长最快,即在多元函数某一点,沿它的梯度方向增长是最快的。

3、批处理梯度下降

现在,假定有m个训练样本,初始的权重向量 θ ^ \hat{\theta} θ^=[ θ 1 \theta1 θ1, θ 2 \theta2 θ2, θ 3 \theta3 θ3 θ n \theta n θn]T,则损失函数可定义为J( θ \theta θ)= 1 2 m \frac{1}{2m} 2m1 ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)2,即每个样本的预测值减去真实值 的平方求和后乘 1 2 \frac{1}{2} 21.平方放大了较大的误差, 1 2 \frac{1}{2} 21在下面求偏导时会约去常数。
初始的权重向量下,损失函数可能会很大,梯度下降的目的就是为了降低损失函数。损失函数值小意味着模型预测值与真实值误差小。
把损失函数看成关于 θ i \theta_i θi的多元函数J( θ 1 \theta_1 θ1, θ 2 \theta_2 θ2 θ n \theta_n θn),对它求梯度,得到的方向就是损失函数增长最快的方向。因此,若把 θ ^ \hat{\theta} θ^沿梯度负方向前进一点的 θ ^ \hat{\theta} θ^代替原来的 θ ^ \hat{\theta} θ^,损失函数就以最快速度减小的一点。不断迭代该过程,最终损失函数就会趋向于落在极小值点(极小值点: lim ⁡ Δ θ → 0 J ( θ + Δ θ ) > J ( θ ) \lim_{\Delta\theta\rightarrow0}J(\theta+\Delta\theta)\gt J(\theta) limΔθ0J(θ+Δθ)>J(θ))
在每一次迭代中, θ ^ \hat{\theta} θ^k+1= θ ^ \hat{\theta} θ^k- α \alpha α ▽ \triangledown J( θ \theta θ),其中, α \alpha α为训练步长,即每次沿梯度方向前进多少。若 α \alpha α过小,则前进速度过慢可能导致运行时间极长;若 α \alpha α过大,则前进速度过快可能导致极小值点被跳过。因此,需要合理选择 α \alpha α值的大小
由于 ▽ \triangledown J( θ \theta θ)= 1 2 m \frac{1}{2m} 2m1 ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi) 2 ∂ ( h θ ( x i ) − y i ) ∂ θ \frac{\partial {(h_\theta(x_i)-y_i)}}{\partial \theta} θ(hθ(xi)yi)。yi θ \theta θ求偏导为0,而 h θ h_\theta hθ( x ^ \hat{x} x^)= θ 0 \theta_0 θ0+ θ 1 x 1 \theta_1x_1 θ1x1+ θ 2 x 2 \theta_2x_2 θ2x2…+ θ n x n \theta_nx_n θnxn= ∑ i = 0 n θ i x i \sum_{i=0}^n\theta_ix_i i=0nθixi,对 θ \theta θ求偏导后的向量为[xi0 θ 0 ^ ∣ θ ^ 0 ∣ \frac{\hat{\theta_0}}{|\hat\theta_0|} θ^0θ0^,xi1 θ 1 ^ ∣ θ ^ 1 ∣ \frac{\hat{\theta_1}}{|\hat\theta_1|} θ^1θ1^,xi2 θ 2 ^ ∣ θ ^ 2 ∣ \frac{\hat{\theta_2}}{|\hat\theta_2|} θ^2θ2^,…xin θ n ^ ∣ θ ^ n ∣ \frac{\hat{\theta_n}}{|\hat\theta_n|} θ^nθn^]T.
因此 ▽ \triangledown J( θ \theta θ) = 1 m \frac{1}{m} m1 ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)[x0 θ 0 ^ ∣ θ ^ 0 ∣ \frac{\hat{\theta_0}}{|\hat\theta_0|} θ^0θ0^, xi1 θ 1 ^ ∣ θ ^ 1 ∣ \frac{\hat{\theta_1}}{|\hat\theta_1|} θ^1θ1^,xi2 θ 2 ^ ∣ θ ^ 2 ∣ \frac{\hat{\theta_2}}{|\hat\theta_2|} θ^2θ2^,…xin θ n ^ ∣ θ ^ n ∣ \frac{\hat{\theta_n}}{|\hat\theta_n|} θ^nθn^]T =
1 m \frac{1}{m} m1[ ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xi0 θ 0 ^ ∣ θ ^ 0 ∣ \frac{\hat{\theta_0}}{|\hat\theta_0|} θ^0θ0^, ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xi1 θ 1 ^ ∣ θ ^ 1 ∣ \frac{\hat{\theta_1}}{|\hat\theta_1|} θ^1θ1^, ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xi2 θ 2 ^ ∣ θ ^ 2 ∣ \frac{\hat{\theta_2}}{|\hat\theta_2|} θ^2θ2^ ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xin θ n ^ ∣ θ ^ n ∣ \frac{\hat{\theta_n}}{|\hat\theta_n|} θ^nθn^]
因此上述方程的数学推导为:
θ ^ \hat{\theta} θ^k+1= θ ^ \hat{\theta} θ^k- α \alpha α ▽ \triangledown J( θ \theta θ)= θ ^ \hat{\theta} θ^k- α m \frac{\alpha}{m} mα
[ ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xi0 θ 0 ^ ∣ θ ^ 0 ∣ \frac{\hat{\theta_0}}{|\hat\theta_0|} θ^0θ0^, ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xi1 θ 1 ^ ∣ θ ^ 1 ∣ \frac{\hat{\theta_1}}{|\hat\theta_1|} θ^1θ1^, ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xi2 θ 2 ^ ∣ θ ^ 2 ∣ \frac{\hat{\theta_2}}{|\hat\theta_2|} θ^2θ2^ ∑ i = 1 m \sum_{i=1}^m i=1m( h θ h_\theta hθ(xi) - yi)xin θ n ^ ∣ θ ^ n ∣ \frac{\hat{\theta_n}}{|\hat\theta_n|} θ^nθn^],即 θ ^ \hat\theta θ^递减的每个分量为所有样本(m个)在相应下标特征(共n个特征)的加权累加。因此计算量极为巨大。
权重向量 θ ^ \hat\theta θ^的初始值可以为零向量,也可以为一个随机向量。理论上一个多元函数可以有多个极小值点,即梯度下降的结果可能不同,但实际中一般都只有一个极小值点。

4、随机梯度下降法

当样本数量极大时,批处理梯度下降由于要处理所有样本的所有特征,计算力会不够用,运行时间也会极长。因此,若在m个样本中随机挑选p个向量用来进行梯度下降,运算时间会大大减少,并且,计算损失函数时每次只使用一个样本,即:
J( θ \theta θ)= 1 2 m \frac{1}{2m} 2m1( h θ h_\theta hθ(xp)-yp)^2
这样每次迭代时,权重向量 θ ^ \hat{\theta} θ^k+1= θ ^ \hat{\theta} θ^k - α ▽ J ( θ ) \alpha\triangledown J(\theta) αJ(θ)= θ ^ \hat{\theta} θ^k - α m \frac{\alpha}{m} mα[( h θ [ x p ] − y p ) h_\theta[x_p]-y_p) hθ[xp]yp)xp0 θ 0 ^ ∣ θ ^ 0 ∣ \frac{\hat{\theta_0}}{|\hat\theta_0|} θ^0θ0^, ( h θ ( x p ) − y p ) h_\theta(x_p)-y_p) hθ(xp)yp)xp1 θ 1 ^ ∣ θ ^ 1 ∣ \frac{\hat{\theta_1}}{|\hat\theta_1|} θ^1θ1^, ( h θ ( x p ) − y p ) h_\theta(x_p)-y_p) hθ(xp)yp)xp2 θ 2 ^ ∣ θ ^ 2 ∣ \frac{\hat{\theta_2}}{|\hat\theta_2|} θ^2θ2^, ( h θ ( x p ) − y p ) h_\theta(x_p)-y_p) hθ(xp)yp)xpn θ n ^ ∣ θ ^ n ∣ \frac{\hat{\theta_n}}{|\hat\theta_n|} θ^nθn^ ]

5、算法收敛

一般由以下三种方法判断梯度下降结束。

1)预设循环次数,循环次数结束就结束

2)监测两次迭代间权重向量 θ ^ \hat\theta θ^的变化量,当变化量减小的预设阈值时停止

3)监测两次迭代间损失函数J( θ \theta θ),当损失函数减小的预设阈值时停止

6、两种梯度下降的比较

批处理梯度下降由于每次迭代时涉及所有样本,因此精确度较高,但运行时间较长。而随机梯度下降由于只选择少量样本,因此精确度略低,但运行时间较短。且由于每次迭代时使用的都是一个样本的数值而不是样本的和,因此随机梯度下降运行完后大量的训练集可以删除,因为需要的样本都可以在运算中找到。

7、批处理梯度下降法用Python实现

#批处理梯度下降
#y = o1x1+o2x2 定为y = 2*x1+3*x2
#input x1 : 1 2 3 4
#input x2 : 5 6 8 7
#output y : 17 22 30 29
input_x = [[1,5],[2,6],[3,8],[4,7]]
output_y = [17,22,30,29]
theta = [0,0]#theta向量初值定为零向量
loss = 1#损失的初值
step_size = 0.001#步长
finish_loss = 0.01#算法收敛条件,损失小于这个值就结束
iter_count = 0#迭代次数
max_iters = 1000#最大迭代次数
error_1 = [0,0,0,0]#求o1梯度的中间变量,四个输入损失函数求梯度后的第一维
error_2 = [0,0,0,0]#求o2梯度的中间变量,四个输入损失函数求梯度后的第二维
while(loss > finish_loss and iter_count<max_iters):
    loss = 0
    errorsum_axis0 = 0#第1维的损失之和
    errorsum_axis1 = 0#第2维的损失之和
    #计算每个样本在2个维度上的损失
    for i in range(0,4):
        pred_yi = theta[0]*input_x[i][0]+theta[1]*input_x[i][1]
        error_1[i] = (pred_yi-output_y[i])*input_x[i][0]
        errorsum_axis0 += error_1[i]
        error_2[i] = (pred_yi-output_y[i])*input_x[i][1]
        errorsum_axis1 += error_2[i]
    #沿梯度方向下降
    theta[0] -= step_size/4*errorsum_axis0
    theta[1] -= step_size/4*errorsum_axis1
    #计算迭代后的损失
    for i in range(0,4):
        pred_y = theta[0]*input_x[i][0]+theta[1]*input_x[i][1]
        error_i = (1/(2*4))*(pred_y-output_y[i])**2#第i个样本的损失
        loss += error_i#将各项样本的损失累加
    iter_count += 1
    print('current iter_count:',iter_count)
    print(iter_count,'times loss is',loss)
print('iter_count:',iter_count)
print('theta vector:',theta)
print('loss',loss)
if iter_count == max_iters:
    print('Reason of convergence is iter_count meets prevalue')
else :
    print('Reason of convergence is loss meets prevalue')
print('end')

运行结果:
在这里插入图片描述

8、随机梯度下降用Python实现

#随机梯度下降
#前面都与批处理一样
#y = o1x1+o2x2 定为y = 2*x1+3*x2
#input x1 : 1 2 3 4
#input x2 : 5 6 8 7
#output y : 17 22 30 29
import random
input_x = [[1,5],[2,6],[3,8],[4,7]]
output_y = [17,22,30,29]
theta = [0,0]#theta向量初值定为零向量
loss = 1#损失的初值
step_size = 0.01#步长
finish_loss = 0.01#算法收敛条件,损失小于这个值就结束
iter_count = 0#迭代次数
max_iters = 1000#最大迭代次数
#error_1 = [0,0,0,0]#求o1梯度的中间变量,四个输入损失函数求梯度后的第一维
#error_2 = [0,0,0,0]#求o2梯度的中间变量,四个输入损失函数求梯度后的第二维
while(iter_count<max_iters and loss > finish_loss):
    loss = 0 
    error_axis0 = 0#第1维的损失之和
    error_axis1 = 0#第2维的损失之和
    i = random.randint(0,3)#在0,1,2,3间返回一个随机数
    print((iter_count+1),'current random i is:',i)
    pred_yi = theta[0]*input_x[i][0]+theta[1]*input_x[i][1]
    error_axis0 = (pred_yi-output_y[i])*input_x[i][0]
    error_axis1 = (pred_yi-output_y[i])*input_x[i][1]
    theta[0] -= step_size*error_axis0
    theta[1] -= step_size*error_axis1
    for j in range(0,4):
        pred_y = theta[0]*input_x[j][0]+theta[1]*input_x[j][1]
        error_i = (1/(2*4))*(pred_y-output_y[j])**2#第i个样本的损失
        loss += error_i#将各项样本的损失累加
    iter_count += 1
    print('current iter_count:',iter_count)
    print('current loss:',loss)
print('iter_count:',iter_count)
print('theta vector:',theta)
print('loss',loss)
if iter_count == max_iters:
    print('Reason of convergence is iter_count meets prevalue')
else :
    print('Reason of convergence is loss meets prevalue')
print('end')

运行结果
在这里插入图片描述

2018.11.25

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值