6梯度下降
1.概念
引入梯度下降的原因:1.并不是所有的机器学习都是凸函数,并且可能存在多个极值,不能确定唯一解;2.特征和数据量较多时,矩阵计算量太大(逆矩阵运算的时间复杂度是(
$$
O(n^3)
$$
))
梯度下降:梯度表示损失函数对于模型参数的偏导数。对于每个可训练的参数,梯度告诉我们在当前参数下,沿着每个参数方向变化时,损失函数的变化率。通过计算损失函数对参数的梯度,算法可以根据梯度信息来调整参数从而沿着减少损失的方向更新模型进行调优。
在
$$
\bar e={\frac{1}{n}}\sum_{i=1}^{n}x_{i}^{2}w^{2}-{\frac{2}{n}}\sum_{i=1}^{n} x_{i}y_{i}w+{\frac{1}{n}}\sum_{i=1}^{n} y_{i}^{2}
$$
中损失函数对于参数w的梯度就是此时w的切线斜率。
梯度下降法是通过不断地优化从而得到最优解。(优化算法都是期望以最快的速度把模型参数w求解出来)
2.步骤
①.Random随机生成初始w,随机生成一组正态分布的数值
$$
w_0,w_1,w_2....w_n
$$
②.求梯度g,即损失函数在此w点上的切线斜率(求导)
③.g<0,表示切线斜率为负数,表示在导数为0的w值的左边,那么就应该把w往右调大不断逼近导数为0的w值;g>0,表示切线斜率为正,表示在导数为0的w值的右边,将w往左调小不断逼近导数为0的w值
④.判断是否收敛,如果收敛就跳出迭代,否则重复②-④。判断收敛的标准是:随着迭代看loss的值变化多少,如果很小甚至不再变化,则认为达到迭代。(迭代次数可以固定)
3.公式
$$
w^{n+1}=w^n-α*gradient
$$
$$
新值=旧值-学习率*导数
$$
学习率:学习率很小可以保证收敛,但是会增加计算;学习率较大,训练会震荡收敛;学习率过大,系统会来回震荡无法收敛
一般将学习率设置成一个小数,0.1,0.01,0.001,0.0001等,可以根据情况进行调整。一般学习率在整体迭代过程中不变,也可以设置成随着迭代次数增多学习率逐渐变小以更精准地得到最优解。
按照步骤来计算w的值
假设要求的损失函数的抛物线公式为:
$$
\bar e=10w^{2}-15.9w+6.5
$$
那么切线公式为:
$$
e'=20w-15.9
$$
w0=0.2,假设学习率为0.01(w0表示第0次w的值)
w1=w0-0.01*e'(w0)=0.2-0.01 *(20 * 0.2-15.9)=0.319
w2=w1-0.01 * e'(w1)=0.319-0.01 * (20 * 0.319-15.9)=0.4142
以此类推
w在最低点的左边还是右边:导数为负值,则w在最低值的左边,应该往右移动(减去一个负数=加上一个正数=往右移动);导数为正值,则w在最低值的右边,应该往左移动(加上一个负数=往左移动)
4.代码实现梯度下降
①.损失函数为一个特征的抛物线:
$$
loss(w_1)=(w_1-3.5)^2-4.5w_1+10
$$
#自己实现一维梯度下降算法(一个w)
import numpy as np
import matplotlib.pyplot as plt
w=np.linspace(-10,10,100)
#print(w)
def loss(w):return (w-3.5)**2-4.5*w+10
def dloss(w):return 2*(w-3.5)-4.5
#print(loss)
plt.plot(w,loss(w))
plt.show()
#梯度下降
#学习率
learning_rate=0.1
#初始化一个w值
np.random.seed(1)
w=np.random.randint(-10,20)#随机给一个w值:-5
print(w)
e=loss(w)#初始化的w为-5时的loss值
x=[w]
y=[e]
#第1次梯度下降
w=w-learning_rate*dloss(w)
e=loss(w)
x.append(w)
y.append(e)
#第2次梯度下降
w=w-learning_rate*dloss(w)
e=loss(w)
x.append(w)
y.append(e)
#第3次梯度下降
w=w-learning_rate*dloss(w)
e=loss(w)
x.append(w)
y.append(e)
plt.scatter(x,y)#画点
plt.show()
#自己实现一维梯度下降算法(一个w)-循环
import numpy as np
import matplotlib.pyplot as plt
#假设有一个函数是y=wx 通过损失函数的思路已经得出了损失函数
def loss(w):return (w-3.5)**2-4.5*w+10
#得出导函数
def dloss(w):return x*(w-3.5)-4.5
def train():#初始化随机给一个w值w=-10#np.random.randint(-10,20)#初始化学习率lr=0.1#更新次数epoch=1000#梯度下降更新wt0,t1=1,100for i in range(0,epoch):#print(i)lr=t0/(t1+i)w=w-lr*dloss(w)print(f"第{i}次w更新后的值:{w},更新后损失函数的值{loss(w)}")
train()
②.损失函数为两个特征的抛物线:
$$
loss(w_1,w_2)=(w_1-3.5)^2+(w_2-2)^2+3w_1w_2-4.5w_1+2w_2+20
$$
分别对w1,w2求导
$$
对w_1求导,就是把w_2看成一个常数: loss(w1)’=2(w_1-3.5)+0+3w_2-4.5=2w_1+3w_2-11.5
$$
$$
对w_2求导,就是把w_1看成一个常数: loss(w2)’=0+2(w_2-2)+3w_1+2=2w_2+3w_1-2
$$
参照一维求梯度下降的算法:
#自己实现二维梯度下降算法(两个w)
import numpy as np
#假设有一个函数是y=wx 通过损失函数的思路已经得出了损失函数
def loss(w1,w2):return (w1-3.5)**2+(w2-2)**2+3*w1*w2-4.5*w1+2*w2+20
#得出导函数
def dloss_w1(w1,w2):return 2*(w1-3.5)+3*w2-4.5
def dloss_w1(w1,w2):return 2*(w2-2)+3*w1+2
#梯度下降算法
def train():#初始化随机给一个w1,w2值w1=10#np.random.randint(-10,20)w2=10#初始化学习率lr=0.1#更新次数epoch=1000#梯度下降更新wt0,t1=1,100for i in range(0,epoch):#更新w1,w2lr=t0/(t1+i)w1_=w1w2_=w2w1=w1-lr*dloss(w1_,w2_)w2=w2-lr*dloss(w1_,w2_)print(i,w1,w2,loss(w1_,w2_))#print(f"第{i}次w更新后的值:{w1,w2},更新后损失函数的值{loss(w)}")
train()