前言
线性回归算法是我们学习的第一个监督学习算法,我们将从最简单的单变量线性回归开始学习。主要内容:
一、代价函数(Cost Function)
二、梯度下降(Gradience Descent)
单变量线性回归(Linear Regression with One Variable)
(一)模型表示(Model Representation)
首先,同样是先从房价预测的例子开始,我们将已有的数据表示在坐标轴上,横坐标表示房子面积(平方英尺),纵坐标表示房价(千美元),如图
上次我们曾说过这是一个监督学习中的回归问题,还有另外一种叫做分类问题,两种问题的共同点是拥有一个数据集,我们称之为训练集(Training Set),以房价预测模型为例,训练集可以是这样的
为了方便以后讨论,我们定义如下变量:
m m m 代表训练集中实例的数量
x x x 代表特征/输入变量
y y y 代表目标变量/输出变量
( x , y ) \left( x,y \right) (x,y) 代表训练集中的实例
( x ( i ) , y ( i ) ) ({{x}^{(i)}},{{y}^{(i)}}) (x(i),y(i)) 代表第 i i i 个观察实例
h h h 代表学习算法的解决方案或函数也称为假设(hypothesis)
例如,在上面给出的训练集中,m=4,
(
x
(
1
)
,
y
(
1
)
)
({{x}^{(1)}},{{y}^{(1)}})
(x(1),y(1))=(2104,460),下面一道题目
需要特别说明的是假设函数
h
h
h
如图,假设函数
h
h
h可以帮助我们实现预测功能,当学习算法根据所给的训练集训练学习之后,会产生相应的假设函数
h
h
h,这时候,当我们输入房子的大小之后,预测的房价就会输出,也就是说,假设函数
h
h
h就是一个输入变量
x
x
x到输出变量
y
y
y的函数映射。对于不同的学习算法会有不同的假设函数
h
h
h,而对于单变量线性回归算法,我们的假设函数
h
h
h可以直接表示为
h
θ
(
x
)
=
θ
0
+
θ
1
x
h_\theta \left( x \right)=\theta_{0} + \theta_{1}x
hθ(x)=θ0+θ1x,这就是单变量线性回归问题的模型。因为只含有一个特征/输入变量,且图像是一条直线,即线性的,所以我们称之为单变量线性回归问题。
(二)代价函数(Cost Function)
- 利用代价函数对数据进行最合适的拟合
现在我们已经知道了模型是
h
θ
(
x
)
=
θ
0
+
θ
1
x
h_\theta \left( x \right)=\theta_{0} + \theta_{1}x
hθ(x)=θ0+θ1x,结合上面给出的训练集,我们如何选取一条直线能够最完美的拟合出这些数据是我们最关心的,最完美的拟合其实就是指实际值与模型预测出的值直接的误差和最小。简而言之,就是确定
θ
0
,
θ
1
\theta_0, \theta_1
θ0,θ1的值,使得直线能够满足误差和最小的条件。借助代价函数可以实现这一点。首先,直接给出单变量线性回归问题的代价函数:
J
(
θ
0
,
θ
1
)
=
1
2
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
J \left( \theta_0, \theta_1 \right) = \frac{1}{2m}\sum\limits_{i=1}^m\left(h_{\theta}(x^{(i)})-y^{(i)} \right)^{2}
J(θ0,θ1)=2m1i=1∑m(hθ(x(i))−y(i))2
有时,我们也称它为平方误差函数。我们逐一分析,
h
θ
(
x
(
i
)
)
h_{\theta}(x^{(i)})
hθ(x(i))代表学习算法预测出的结果,
y
(
i
)
y^{(i)}
y(i)代表实际结果,两者之差代表实际值与预测值直接的误差,在图像上,假设我们拟合出如图所示的一条直线,直线上对应的值就是我们的预测值。我们的目的就是不断改变
θ
0
,
θ
1
\theta_0, \theta_1
θ0,θ1的值,使得代价函数
J
(
θ
0
,
θ
1
)
J \left( \theta_0, \theta_1 \right)
J(θ0,θ1)的值最小。
这里说明一下为什么选择误差的平方而不是绝对值,且为什么在均值前加上
1
2
\frac{1}{2}
21,原因如下:
绝对值具有一些不利于最小化的特性:
- 梯度不是连续的,因为绝对值函数在其最小值处是不可微的
- 它不强调大错误的纠正
- abs()函数在数学上也不是很有效
但是,平方误差成本函数具有一些非常理想的特性:
- 可以非常有效地计算成本
- 它的偏导数很容易计算
- 它的偏导数是连续的
1 2 \frac{1}{2} 21部分是微积分技巧,当我们计算偏导数时,它将以分子中出现的“ 2”来抵消节省了成本函数的计算。
总结一下
现在,让我们进一步去感受一下代价函数的意义。
为了更好的理解,我们将模型
h
θ
(
x
)
=
θ
0
+
θ
1
x
h_\theta \left( x \right)=\theta_{0} + \theta_{1}x
hθ(x)=θ0+θ1x进行简化成模型是
h
θ
(
x
)
=
θ
1
x
h_\theta \left( x \right)= \theta_{1}x
hθ(x)=θ1x,即令
θ
0
\theta_{0}
θ0=0,将简化后的与原有的作对比:
假设给出的训练集如图,模型为
h
θ
(
x
)
=
θ
1
x
h_\theta \left( x \right)= \theta_{1}x
hθ(x)=θ1x
我们将
θ
1
\theta_{1}
θ1设置为不同的值时可以分别计算出相应的代价函数
J
(
θ
1
)
J \left( \theta_1 \right)
J(θ1)的值,并将其标注在
J
(
θ
1
)
J \left( \theta_1 \right)
J(θ1)的图像上,我们分别令
θ
1
\theta_{1}
θ1取0.5,1等不同的值,画出
J
(
θ
1
)
J \left(\theta_1 \right)
J(θ1)的图像
由图像不难看出当
θ
1
\theta_{1}
θ1取1的时候,代价函数最小,为0,说明此时拟合的最为准确,没有误差,事实也确实如此。
在此基础上,我们将
θ
0
\theta_{0}
θ0加上,当我们为
θ
0
,
θ
1
\theta_0, \theta_1
θ0,θ1改变值的时候画出相应的代价函数的图像,依据图像找出取得最小值的时候
θ
0
,
θ
1
\theta_0, \theta_1
θ0,θ1的值,例如取
θ
0
\theta_0
θ0为50,
θ
1
\theta_1
θ1为0.06时,画出直线,求出代价函数的值
不断改变
θ
0
,
θ
1
\theta_0, \theta_1
θ0,θ1的值,画出代价函数
J
(
θ
0
,
θ
1
)
J \left( \theta_0, \theta_1 \right)
J(θ0,θ1)的图像,每个点对应的高度就是其代价函数的值。
这里,我们再介绍一种图像,轮廓图(Contour Figures),类似于等高线图,将立体图形中高度相同的点连成线表示出来。当我们取轮廓图最外围的点时,其高度最大,即代价函数的值最大,拟合效果最差,由此向内,高度不断减小,即代价函数不断减小,直至到达最中心的点的时候,其高度最小,对应的直线也是拟合的最好的。
事实上,我们不可能每次编个程序把这些点画出来,然后人工的方法来读出这些点的数值,这很明显不是一个好办法。我们会遇到更复杂、更高维度、更多参数的情况,而这些情况是很难画出图的,因此更无法将其可视化,因此我们真正需要的是编写程序来找出这些最小化代价函数的
θ
0
\theta_{0}
θ0和
θ
1
\theta_{1}
θ1的值,这就需要梯度下降。
(三)梯度下降(Gradient Descent)
- 梯度下降:自动求出代价函数取最小值时模型参数的值
- 思想:开始时随机赋值给参数
(
θ
0
,
θ
1
,
.
.
.
.
.
.
,
θ
n
)
\left( {\theta_{0}},{\theta_{1}},......,{\theta_{n}} \right)
(θ0,θ1,......,θn),计算代价函数,然后寻找下一个能让代价函数值下降最多的参数组合,持续这么做直到找到一个局部最小值(local minimum)
例如,代价函数如图所示,为模型参数赋初值,假设起点分别位于两个地方,我们选择能使代价函数下降最快的方向,也就是所在点的切线方向下降,不断重复,直至到达局部最低点,此时梯度为0,不再下降。可以看出,选择的起点不同,最后得到的最小值也可能不同,但是对于单变量线性回归来说,可以证明,只存在全局最优(global minimum),所以我们不用担心得到的点是否为最优解。说明一下,梯度下降不仅适用于单变量线性回归问题,后面许多算法都会用到,形式稍有不同。
下面给出模型参数 θ 0 , θ 1 \theta_0, \theta_1 θ0,θ1具体变化的公式:
式子中的 a a a是我们称之为学习率(learning rate),是一个较小的正数,控制每次下降的速度;式子中的偏导数项 ∂ ∂ θ 0 J ( θ 0 , θ 1 ) \frac{\partial }{\partial {{\theta }{0}}}J({{\theta }{0}},{{\theta }{1}}) ∂θ0∂J(θ0,θ1), ∂ ∂ θ 1 J ( θ 0 , θ 1 ) \frac{\partial }{\partial {{\theta }{1}}}J({{\theta }{0}},{{\theta }{1}}) ∂θ1∂J(θ0,θ1)控制下降的方向,偏导方向即切线方向,等于该点的斜率;注意,模型参数 θ 0 , θ 1 \theta_0, \theta_1 θ0,θ1需要同时更新,不能一前一后,如图,左边的是正确的过程,右边的是错误的过程,在之前给出的代价函数的图像中,我们也能感受到每下降一次, θ 0 , θ 1 \theta_0, \theta_1 θ0,θ1确实是同时更新的。有时不同时更新也能计算出不错的结果,但这不是我们讲的梯度下降算法。
下面这个例题可以加深对同步更新的理解
现在,我们深入地去了解上面给出的公式是如何帮助我们实现找出最优值的。同样,为了简化,我们假设只有一个参数 θ 1 \theta_1 θ1,即 θ 0 \theta_0 θ0为0,假设代价函数如图
当 θ 1 \theta_1 θ1的初始值在1这个点的时候,进行梯度下降,根据公式,更新后的 θ 1 \theta_1 θ1是 θ 1 {\theta_{1}} θ1减去一个正数乘以 a a a,此时 θ 1 {\theta_{1}} θ1的值会减少,即向左边靠近,依次类推,不断左移,直至到达中心最小值,此时偏导为0, θ 1 {\theta_{1}} θ1不再更新;同理,假设初始值在2这个点,更新后的 θ 1 \theta_1 θ1是 θ 1 {\theta_{1}} θ1减去一个负数乘以 a a a,此时 θ 1 {\theta_{1}} θ1的值会增大,即向右边靠近,也能找到最小值。
这就是梯度下降的实现原理,补充两点:
- 学习率
a
a
a的选择很重要。选择的过小,每次更新的幅度会很小,导致更新很长的时间也不能找出最小值;选择的过大,会使得参数来回震荡,不仅不会减少代价函数的值,反而可能不断增大,如图
- 我们不用担心更新过程中需不需要改变 a a a的值(当然可以改变),因为在更新过程中,不断接近最低点的时候我们会发现偏导数的值也会逐渐减小,这会导致每次更新的幅度会不断减小,直到最后移动幅度特别小,我们会发现已经收敛到了最小值。总之,梯度下降会自动采取较小的幅度,没有必要改变 a a a的值。
以下是通过tensorflow代码体会更新的过程:
import tensorflow as tf
w = tf.Variable(tf.constant(5, dtype=tf.float32))
lr = 0.2
epoch = 40
for epoch in range(epoch):
with tf.GradientTape() as tape:
loss = tf.square(w + 1)
grads = tape.gradient(loss, w)
w.assign_sub(lr * grads)
print("After %s epoch,w is %f,loss is %f" % (epoch, w.numpy(), loss))
运行结果如下,确实找到了最小值
我们尝试将学习率改为很小(0.01)和很大(1)的值,确实出现了运行过慢和来回震荡的情况,运行结果如下:
(四)梯度下降的线性回归
以上,我们讨论了代价函数和梯度下降,它们不仅应用于线性回归算法中。现在,我们将它们应用到单变量线性回归问题中,实现我们一开始想要的自主找到最优解。梯度下降和代价函数如图所示。
想要实现梯度下降,就必须知道偏导数项
∂
∂
θ
0
J
(
θ
0
,
θ
1
)
\frac{\partial }{\partial {{\theta }{0}}}J({{\theta }{0}},{{\theta }{1}})
∂θ0∂J(θ0,θ1),
∂
∂
θ
1
J
(
θ
0
,
θ
1
)
\frac{\partial }{\partial {{\theta }{1}}}J({{\theta }{0}},{{\theta }{1}})
∂θ1∂J(θ0,θ1)的值,利用高等数学的知识可以求得:
∂
∂
θ
j
J
(
θ
0
,
θ
1
)
=
∂
∂
θ
j
1
2
m
∑
i
=
1
m
(
h
θ
(
x
(
i
)
)
−
y
(
i
)
)
2
\frac{\partial }{\partial {{\theta }{j}}}J({{\theta }{0}},{{\theta }{1}})=\frac{\partial }{\partial {{\theta }{j}}}\frac{1}{2m}{{\sum\limits_{i=1}^{m}{\left( {{h}_{\theta }}({{x}^{(i)}})-{{y}^{(i)}} \right)}}^{2}}
∂θj∂J(θ0,θ1)=∂θj∂2m1i=1∑m(hθ(x(i))−y(i))2
j = 0 j=0 j=0 时: ∂ ∂ θ 0 J ( θ 0 , θ 1 ) = 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) \frac{\partial }{\partial {{\theta }{0}}}J({{\theta }{0}},{{\theta }{1}})=\frac{1}{m}{{\sum\limits{i=1}^{m}{\left( {{h}_{\theta }}({{x}^{(i)}})-{{y}^{(i)}} \right)}}} ∂θ0∂J(θ0,θ1)=m1∑i=1m(hθ(x(i))−y(i))
j = 1 j=1 j=1 时: ∂ ∂ θ 1 J ( θ 0 , θ 1 ) = 1 m ∑ i = 1 m ( ( h θ ( x ( i ) ) − y ( i ) ) ⋅ x ( i ) ) \frac{\partial }{\partial {{\theta }{1}}}J({{\theta }{0}},{{\theta }{1}})=\frac{1}{m}\sum\limits{i=1}^{m}{\left( \left( {{h}_{\theta }}({{x}^{(i)}})-{{y}^{(i)}} \right)\cdot {{x}^{(i)}} \right)} ∂θ1∂J(θ0,θ1)=m1∑i=1m((hθ(x(i))−y(i))⋅x(i))
这时候,算法可以改写成
Repeat {
θ 0 : = θ 0 − a 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) {\theta_{0}}:={\theta_{0}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{ \left({{h}_{\theta }}({{x}^{(i)}})-{{y}^{(i)}} \right)} θ0:=θ0−am1i=1∑m(hθ(x(i))−y(i))
θ 1 : = θ 1 − a 1 m ∑ i = 1 m ( ( h θ ( x ( i ) ) − y ( i ) ) ⋅ x ( i ) ) {\theta_{1}}:={\theta_{1}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{\left( \left({{h}_{\theta }}({{x}^{(i)}})-{{y}^{(i)}} \right)\cdot {{x}^{(i)}} \right)} θ1:=θ1−am1i=1∑m((hθ(x(i))−y(i))⋅x(i))
}
线性回归算法的梯度下降实现过程。就是这种算法,有时我们也叫“批量梯度下降”,原因在于每实现一次梯度下降,都是以遍历整个训练集(从1到m)为代价的。当然,有时也有其他类型的梯度下降法,不是这种"批量"型的,不考虑整个的训练集,而是每次只关注训练集中的一些小的子集。
总结一下,单变量线性回归就是这样的:首先,我们有一个数据集,想用曲线去拟合这些数据点,我们首先想到的是用直线进行拟合。那么,怎么衡量拟合出的直线是好还是坏,我们用代价函数(平方误差函数只是代价函数的一种)来衡量,代价函数越小,说明拟合效果越好。但是代价函数有时过于复杂,人工无法观察出何时代价函数最小,所以我们又想到用梯度下降的方法实现这一点,这就是过程。