基本思想:假设我们爬山,想要上山最快,我们应该从陡峭的地方上山,同样的,如果我们想要下山最快,也应当从陡峭的地方下山,这个下山的过程就是梯度下降。同样,如果从任意一点出发,需要最快搜索到函数最大值,那么我们也应该从函数变化最快的方向搜索。函数变化最快的方向就是函数的梯度,也就是函数的导数。
梯度下降法的步骤:函数
y
=
f
(
x
1
,
x
2
,
.
.
.
.
,
x
n
)
y=f(x1,x2,....,x_n)
y=f(x1,x2,....,xn) 1.确定参数
η
和
ε
\eta和\varepsilon
η和ε,
η
\eta
η为学习率。
η
\eta
η大小的选取要合适,太大了会错过极值,太小了迭代太慢。2.求当前位置的偏导数
f
′
(
x
m
0
)
=
∂
y
∂
x
m
f^\prime(x_{m0})=\frac{\partial y}{\partial x_m}
f′(xm0)=∂xm∂y3.修改当前函数的参数值
x
′
=
x
m
−
η
∗
∂
y
∂
x
m
(
x
m
0
)
x^\prime=x_m-\eta*\frac{\partial y}{\partial x_m}(x_{m0})
x′=xm−η∗∂xm∂y(xm0)4.判断参数变化小于
ε
\varepsilon
ε,则结束迭代,否则执行2,3两步不断迭代。
实例:任给一个初始出发点,设为
x
0
=
−
4
x_0=-4
x0=−4,利用梯度下降法求函数
y
=
x
2
2
−
2
x
y=\frac{x^2}{2}-2x
y=2x2−2x的极小值。
(1)首先给定两个参数:
η
=
0.9
,
ε
=
0.01
\eta=0.9,\varepsilon=0.01
η=0.9,ε=0.01
(2)计算导数:
d
y
d
x
=
x
−
2
\frac{dy}{dx}=x-2
dxdy=x−2
(3)计算当前导数值:
y
′
=
−
6
y^\prime=-6
y′=−6
(4)修改当前参数:
x
′
=
x
−
η
∗
d
y
d
x
=
1.4
x^\prime=x-\eta*\frac{dy}{dx}=1.4
x′=x−η∗dxdy=1.4
(5)不断执行(3)(4)直到满足终止条件。
代码实现:
x=-4
y=16
alpha=0.9
epsilon=0.01
lx=[]#存步长
while True:
xx=-1*alpha*(x-2)
x=x+xx
lx.append(xx)
if(xx<epsilon):
break
print("最小点为X={},Y={}".format(x,1/2*x**2-2*x))
print("x方向每次前进步长:")
print(lx)
梯度下降的特点:
梯度下降是求解无约束最优化问题最常用的一种迭代方法,以当前位置负梯度为方向下降,每一步的主要操作是求目标函数的梯度向量(导数值),越接近目标值,步长越小,下降速度越慢。
设预测函数
h
(
x
)
=
θ
0
+
θ
1
∗
x
h(x)=\theta_0+\theta_1*x
h(x)=θ0+θ1∗x定义损失函数(1)
J
(
θ
0
,
θ
1
)
=
1
2
m
∗
∑
i
=
1
m
(
h
θ
(
x
i
)
−
y
i
)
2
J(\theta_0,\theta_1)=\frac{1}{2m}*\sum_{i=1}^m(h_\theta(x^i)-y^i)^2
J(θ0,θ1)=2m1∗i=1∑m(hθ(xi)−yi)2(2)
∂
J
(
θ
0
,
θ
1
)
∂
θ
0
=
1
m
∗
∑
i
=
1
m
(
h
θ
(
x
i
)
−
y
i
)
\frac{\partial J(\theta_0,\theta_1)}{\partial \theta_0}=\frac{1}{m}*\sum_{i=1}^m(h_\theta(x^i)-y^i)
∂θ0∂J(θ0,θ1)=m1∗i=1∑m(hθ(xi)−yi)(3)
∂
J
(
θ
0
,
θ
1
)
∂
θ
1
=
1
m
∗
∑
i
=
1
m
(
h
θ
(
x
i
)
−
y
i
)
∗
x
i
\frac{\partial J(\theta_0,\theta_1)}{\partial \theta_1}=\frac{1}{m}*\sum_{i=1}^m(h_\theta(x^i)-y^i)*x^i
∂θ1∂J(θ0,θ1)=m1∗i=1∑m(hθ(xi)−yi)∗xi更新
θ
0
,
θ
1
\theta_0,\theta_1
θ0,θ1:
θ
0
=
θ
0
−
1
m
∗
∑
i
=
1
m
(
h
θ
(
x
i
)
−
y
i
)
\theta_0=\theta_0-\frac{1}{m}*\sum_{i=1}^m(h_\theta(x^i)-y^i)
θ0=θ0−m1∗i=1∑m(hθ(xi)−yi)
θ
1
=
θ
1
−
1
m
∗
∑
i
=
1
m
(
h
θ
(
x
i
)
−
y
i
)
∗
x
i
\theta_1=\theta_1-\frac{1}{m}*\sum_{i=1}^m(h_\theta(x^i)-y^i)*x^i
θ1=θ1−m1∗i=1∑m(hθ(xi)−yi)∗xi
手工推导过程:
批量梯度下降代码实现BGD:
#y=theta0+theta1*x
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
x=[1,3,6,7,12,13,14,15,16,17,20,23,24,]#面积
y=[5,7,9,11,17,19,23,25,27,32,36,37,40]#价格
print("原始数据:")
plt.scatter(x,y)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
m=len(x)
theta0=0
theta1=0
count=0
alpha=0.01
loss=[]
for time in range(1000):
temp0=0#对theta0的求导
temp1=0
count+=1
diss=0
for i in range(m):
temp0+=(theta0+theta1*x[i]-y[i])/m
temp1+=(theta0+theta1*x[i]-y[i])*x[i]/m
for i in range(m):
theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m)
theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]
# for i in range(m):
# diss+=0.5*((theta0+theta1*x[i]-y[i])**2)/m
loss.append(diss)
print("一次线性回归函数为y={}x+{}".format(theta1,theta0))
#print("损失函数变化:")
#plt.scatter(range(1000),loss)
#plt.xlabel("X")
#plt.ylabel("Y")
#plt.show()
lx=np.linspace(0,25)
ly=theta0+theta1*lx
plt.plot(lx,ly)
plt.scatter(x,y)
plt.xlabel("X")
plt.ylabel("Y")
plt.show()
除此之外还有随机梯度下降(SGD)小批量梯度下降(MBGD)
一般用到的是BGD🎄🌲🌳