一、引言
下山问题 如下图所示,假设我们位于黄山的某个山腰处,山势连绵不绝,不知道怎么下山。于是决定走一步算一步,也就是每次选个方向往山下走一步,这样一步一步走下去,一直走到觉得我们已经到了山脚。问题是当我以一定的步长下坡时,我可以选择的方向有很多,到底选哪个方向最好呢?经验告诉我们选最陡的方向走,因为这样可以快速下山。那具体的最陡的方向是哪个方向?答案是:梯度的负方向。本文的工作有1.阐述为什么下坡最陡的方向即对于凸函数而言值变小最快的方向是梯度的反方向。2.给出梯度下降法中的参数更新公式。3.解释为啥不直接求导而要用梯度下降法。4.给出梯度下降法代码示例。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191119171251396.png#pic_center)
二、梯度下降法
什么是梯度?通俗来说,梯度就是表示函数值变化最快的方向,即:
∇
f
(
θ
⃗
)
=
(
∂
f
∂
θ
1
,
∂
f
∂
θ
2
,
.
.
.
,
∂
f
∂
θ
n
)
,
其
中
θ
⃗
=
(
θ
1
,
θ
2
,
.
.
.
,
θ
n
)
\nabla f(\vec{\theta})=(\frac{\partial f}{\partial\theta_1},\frac{\partial f}{\partial\theta_2},...,\frac{\partial f}{\partial\theta_n}),其中\vec{\theta}=(\theta_1,\theta_2,...,\theta_n)
∇f(θ
)=(∂θ1∂f,∂θ2∂f,...,∂θn∂f),其中θ
=(θ1,θ2,...,θn) 如上图所示,红点为参数点,红色点对应的函数值为黑色点值,当红色点沿着某一方向移动时函数值将跟随变化。很明显参数更新公式就应当是
θ
⃗
c
u
r
=
θ
⃗
p
r
e
+
η
v
⃗
\vec \theta_{cur}=\vec \theta_{pre}+\eta \vec v
θ
cur=θ
pre+ηv
,其中
η
\eta
η是参数点移动的步长(各方向的合步长),
v
⃗
\vec v
v
是参数更新单位方向向量。根据图像我们发现只能沿着某些方向才能使得函数值往小了变化,例如与梯度方向呈钝角的所有方向都可以,进一步的我需要考虑的是哪个方向能使得函数值变小最快。 以一维函数为例说明函数变小最快的方向。如上图所示,凸函数
f
(
θ
)
f(θ)
f(θ)的某一小段[
θ
θ
θ,
θ
0
θ_0
θ0]由上图黑色曲线表示,可以利用线性近似的思想求出
f
(
θ
)
f(θ)
f(θ)的值即:当步长很小时,曲线近似于红色斜直线。红色直线的斜率等于
f
(
θ
)
f(θ)
f(θ)在
θ
0
θ_0
θ0处的导数。则根据直线方程,很容易得到
f
(
θ
)
f(θ)
f(θ)的近似表达式为:
f
(
θ
)
≈
f
(
θ
0
)
+
(
θ
−
θ
0
)
∇
f
(
θ
0
)
f(\theta)\approx f(\theta_0)+(\theta-\theta_0)\nabla f(\theta_0)
f(θ)≈f(θ0)+(θ−θ0)∇f(θ0) 这也是一阶泰勒展开式的推导过程,主要利用的数学思想就是曲线函数的线性拟合近似。 根据多维的参数更新公式这里的一维参数更新公式应当为:
θ
−
θ
0
=
η
v
⃗
\theta-\theta_0=\eta \vec v
θ−θ0=ηv
带入一阶泰勒展开式:
f
(
θ
)
≈
f
(
θ
0
)
+
η
v
⃗
∇
f
(
θ
0
)
f(\theta)\approx f(\theta_0)+\eta \vec v\nabla f(\theta_0)
f(θ)≈f(θ0)+ηv
∇f(θ0) 我们在凸函数上是希望通过逐步下降方式来求得最小值,故而希望,
f
(
θ
)
<
f
(
θ
0
)
f(\theta)}
for i in range(iteration_num):
grad, loss = self.forward(X,Y)
dw = grad['dw']
db = grad['db']
self.W = self.W - lambd * dw
self.b = self.b - lambd * db
if i % 10==0:
print('iter {0}, loss:{1}'.format(i, float(loss)))
params['W'] = self.W
params['b'] = self.b
return params
def predict(self, x):
Z = np.dot(self.W, X) + self.b
A = 1 / (1 + np.exp(-Z))
return A
lr = LogisticRegression(np.zeros((1,2)), 0)
X = np.array([[1.,2.,-1.],[3.,4.,-3.2]])
Y = np.array([[1,0,1]])
print(lr.fit(X, Y, 0.1, 1000))
参考:
|