1 梯度下降法
1.1原理
J
(
θ
)
J(\theta)
J(θ)是模型的损失函数,我们设定初始参数
θ
\theta
θ,不断迭代,使得
J
(
θ
)
J(\theta)
J(θ)最小化:
θ
j
:
=
θ
j
−
α
∂
J
(
θ
)
∂
θ
\theta_j:=\theta_j-\alpha\frac{\partial{J(\theta)}}{\partial\theta}
θj:=θj−α∂θ∂J(θ)
这里 ∂ J ( θ ) ∂ θ \frac{\partial{J(\theta)}}{\partial\theta} ∂θ∂J(θ)体现的是损失函数减少方向, θ j \theta_j θj表示模型的参数, α \alpha α表示学习率,是我们梯度的步长参数。在线性回归中,这个 θ j \theta_j θj向量表示了自变量的系数和常数项。
- 迭代终点:当损失函数的导数为0时停止迭代,认为当前点是模型参数的最优点。
- 迭代缺点:在曲折的损失函数中,导数等于0可能表示局部最优解,并不是全局最优解。在实际运行中,尽可能的多次选择初始值并迭代。
- 迭代现象:导数越接近于0的时候, ∂ J ( θ ) ∂ θ \frac{\partial{J(\theta)}}{\partial\theta} ∂θ∂J(θ)的值会越小,意味着参数的值变化的频率会更快,所以在一个迭代进行中时我们并不需要调整 α \alpha α的值
- α \alpha α值的选择应谨慎, α \alpha α太大会导致结果不收敛,太小会增大计算量。
1.2 线性回归的梯度下降
线性回归函数:
f
(
x
)
=
θ
0
+
θ
1
x
1
+
θ
2
x
2
f(x)=\theta_0+\theta_1x_1+\theta_2x_2
f(x)=θ0+θ1x1+θ2x2
线性回归的损失函数:
J
(
θ
)
=
1
2
∑
j
=
1
n
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
J(\theta)=\frac{1}{2}\sum_{j=1}^{n}(h_{\theta}(x^{(i)})-y^{(i)})^2
J(θ)=21j=1∑n(hθ(x(i))−y(i))2
对损失函数求导:
∂
J
(
θ
)
∂
θ
=
∂
∂
θ
j
1
2
∑
i
=
1
n
(
f
θ
(
x
)
(
i
)
−
y
(
i
)
)
2
=
2
∗
1
2
∑
i
=
1
n
(
f
θ
(
x
)
(
i
)
−
y
(
i
)
)
∗
∂
∂
θ
j
(
f
θ
(
x
)
(
i
)
−
y
(
i
)
)
=
∑
i
=
1
n
(
f
θ
(
x
)
(
i
)
−
y
(
i
)
)
∗
∂
∂
θ
j
(
∑
j
=
0
d
θ
j
x
j
(
i
)
−
y
(
i
)
)
)
=
∑
i
=
1
n
(
f
θ
(
x
)
(
i
)
−
y
(
i
)
)
x
j
(
i
)
\begin{aligned} \frac{\partial J(\theta)}{\partial \theta} &=\frac{\partial}{\partial \theta_{j}} \frac{1}{2} \sum_{i=1}^{n}\left(f_{\theta}(x)^{(i)}-y^{(i)}\right)^{2} \\ &=2 * \frac{1}{2} \sum_{i=1}^{n}\left(f_{\theta}(x)^{(i)}-y^{(i)}\right) * \frac{\partial}{\partial \theta_{j}}\left(f_{\theta}(x)^{(i)}-y^{(i)}\right) \\ &\left.=\sum_{i=1}^{n}\left(f_{\theta}(x)^{(i)}-y^{(i)}\right) * \frac{\partial}{\partial \theta_{j}}\left(\sum_{j=0}^{d} \theta_{j} x_{j}^{(i)}-y^{(i)}\right)\right) \\ &=\sum_{i=1}^{n}\left(f_{\theta}(x)^{(i)}-y^{(i)}\right) x_{j}^{(i)} \end{aligned}
∂θ∂J(θ)=∂θj∂21i=1∑n(fθ(x)(i)−y(i))2=2∗21i=1∑n(fθ(x)(i)−y(i))∗∂θj∂(fθ(x)(i)−y(i))=i=1∑n(fθ(x)(i)−y(i))∗∂θj∂(j=0∑dθjxj(i)−y(i)))=i=1∑n(fθ(x)(i)−y(i))xj(i)
梯度方程为: θ j = θ j + α ∑ i = 1 n ( y ( i ) − f θ ( x ) ( i ) ) x j ( i ) \theta_j = \theta_j + \alpha\sum_{i=1}^{n}(y^{(i)}-f_\theta(x)^{(i)})x_j^{(i)} θj=θj+αi=1∑n(y(i)−fθ(x)(i))xj(i)
2 代码实现
def dJ(theta, X_b, y):
#损失函数倒数
res = np.empty(len(theta))
res[0] = np.sum(X_b.dot(theta) - y)
for i in range(1, len(theta)):
res[i] = (X_b.dot(theta) - y).dot(X_b[:,i])
return res * 2 / len(X_b)
def gradient_descent(X_b, y, initial_theta, eta, n_iters = 1e4, epsilon=1e-8):
#梯度下降法实现
theta = initial_theta
cur_iter = 0
while cur_iter < n_iters:
gradient = dJ(theta, X_b, y)
last_theta = theta
theta = theta - eta * gradient
if(abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
break
cur_iter += 1
return theta
测试结果:
这个梯度下降还没封装到类里,就是只实现了个函数