2.3 代价函数的直观理解I
让我们通过一些例子来获取一些直观的感受,看看代价函数到底是在干什么。
2.4 代价函数的直观理解II
代价函数的样子类似于等高线图,则可以看出在三维空间中存在一个J(θ0,θ1)使得最小的点。
通过这些图形,我希望你能更好地理解这些代价函数J所表达的值是什么样的,它们对应的假设是什么样的,以及什么样的假设对应的点,更接近于代价函数的最小值。
我们将介绍梯度,能够自动地找出能使代价函数最小化的参数和的值。
2.5 梯度下降
梯度下降是一个用来求函数最小值的算法,我们将使用梯度下降算法来求出代价函数J(θ0,θ1)的最小值。
梯度下降背后的思想是:开始时我们随机选择一个参数(θ0,θ1,~~~,θn)的组合,计算代价函数,然后我们寻找下一个能让代价函数值下降最多的参数组合。我们持续这么做直到到到一个局部最小值(local minimum),因为我们并没有尝试完所有的参数组合,所以不能确定我们得到的局部最小值是否便是全局最小值(global minimum),选择不同的初始参数组合,可能会找到不同的局部最小值。
想象一下你正站立在山的这一点上,站立在你想象的公园这座红色山上,在梯度下降算法中,我们要做的就是旋转360度,看看我们的周围,并问自己要在某个方向上,用小碎步尽快下山。这些小碎步需要朝什么方向?如果我们站在山坡上的这一点,你看一下周围,你会发现最佳的下山方向,你再看看周围,然后再一次想想,我应该从什么方向迈着小碎步下山?然后你按照自己的判断又迈出一步,重复上面的步骤,从这个新的点,你环顾四周,并决定从什么方向将会最快下山,然后又迈进了一小步,并依此类推,直到你接近局部最低点的位置。
批量梯度下降(batch gradient descent)算法的公式为:
其中是学习率(learning rate),它决定了我们沿着能让代价函数下降程度最大的方向向下迈出的步子有多大,在批量梯度下降中,我们每一次都同时让所有的参数减去学习速率乘以代价函数的导数。
在梯度下降算法中,还有一个更微妙的问题,梯度下降中,我们要更新和 θ0,θ1,当j=0和j=1时,会产生更新,所以你将更新j(θ0)和J(θ1)。实现梯度下降算法的微妙之处是,在这个表达式中,如果你要更新这个等式,你需要同时更新θ0和θ1,我的意思是在这个等式中,我们要这样更新:
θ0:=θ0 ,并更新θ1:= θ1。
实现方法是:你应该计算公式右边的部分,通过那一部分计算出和的值,然后同时更新θ0和θ1。
让我进一步阐述这个过程:
当人们谈到梯度下降时,他们的意思就是同步更新。
在接下来的视频中,我们要进入这个微分项的细节之中。我已经写了出来但没有真正定义,如果你已经修过微积分课程,如果你熟悉偏导数和导数,这其实就是这个微分项:
2.6 梯度下降的直观理解
梯度下降算法如下:
描述:对赋值,使得按梯度下降最快方向进行,一直迭代下去,最终得到局部最小值。其中是学习率(learning rate),它决定沿着能让代价函数下降程度最大的方向向下迈出的步子有多大。
对于这个问题,求导的目的,基本上可以说取这个红点的切线,就是这样一条红色的直线,刚好与函数相切于这一点,这条直线的斜率正好是这个三角形的高度除以这个水平长度,现在,这条线有一个正斜率,也就是说它有正导数,因此,我得到的新的θ1,θ1更新后等于θ1)减去一个正数乘以learning rate。
这就是梯度下降法的更新规则:
让我们来看看如果learning rate太小或太大会出现什么情况:
如果learning rate太小了,可能会很慢,因为它会一点点挪动,它会需要很多步才能到达全局最低点。
如果learning rate太大,那么梯度下降法可能会越过最低点,甚至可能无法收敛,下一次迭代又移动了一大步,越过一次,又越过一次,一次次越过最低点,直到你发现实际上离最低点越来越远,所以,如果太大,它会导致无法收敛,甚至发散。
因此,如果你的参数已经处于局部最低点,结果是局部最优点的导数将等于零,因为它是那条切线的斜率。那么梯度下降法更新其实什么都没做,它不会改变参数的值。它使得不再改变,也就是新的等于原来的,这也解释了为什么即使学习速率保持不变时,梯度下降也可以收敛到局部最低点。
我们来看一个例子,这是代价函数。
我想找到它的最小值,首先初始化我的梯度下降算法,在那个品红色的点初始化,如果我更新一步梯度下降,也许它会带我到这个点,因为这个点的导数是相当陡的。现在,在这个绿色的点,如果我再更新一步,你会发现我的导数,也即斜率,是没那么陡的。随着我接近最低点,我的导数越来越接近零,所以,梯度下降一步后,新的导数会变小一点点。然后我想再梯度下降一步,在这个绿点,我自然会用一个稍微跟刚才在那个品红点时比,再小一点的一步,到了新的红色点,更接近全局最低点了,因此这点的导数会比在绿点时更小。所以,我再进行一步梯度下降时,我的导数项是更小的,θ1更新的幅度就会更小。所以随着梯度下降法的运行,你移动的幅度会自动变得越来越小,直到最终移动幅度非常小,你会发现,已经收敛到局部极小值。
回顾一下,在梯度下降法中,当我们接近局部最低点时,梯度下降法会自动采取更小的幅度,这是因为当我们接近局部最低点时,很显然在局部最低时导数等于零,所以当我们接近局部最低时,导数值会自动变得越来越小,所以梯度下降将自动采取较小的幅度,这就是梯度下降的做法。所以实际上没有必要再另外减小。
2.7 梯度下降的线性回归
在以前的视频中我们谈到关于梯度下降算法,梯度下降是很常用的算法,它不仅被用在线性回归上和线性回归模型、平方误差代价函数。在这段视频中,我们要将梯度下降和代价函数结合。我们将用到此算法,并将其应用于具体的拟合直线的线性回归算法里。
梯度下降算法和线性回归算法比较如图:
对我们之前的线性回归问题运用梯度下降法,关键在于求出代价函数的导数,即:
则算法改写成:
我们刚刚使用的算法,有时也称为”批量梯度下降”,指的是在梯度下降的每一步中,我们都用到了所有的训练样本,在梯度下降中,在计算微分求导项时,我们需要进行求和运算,所以,在每一个单独的梯度下降中,我们最终都要计算这样一个东西,这个项需要对所有个训练样本求和。
批量梯度算法代码与设计:
import matplotlib.pyplot as pltx_data=[1.0,2.0,3.0]
y_data=[2.0,4.0,6.0]m=len(x_data)
# 默认w的权值,随着梯度下降而修正
w=1.0
#学习率
learning_rate=0.01def forward(x):return x*wdef cost(x_data,y_data):cost=0.0total_cost=0for x,y in zip(x_data,y_data):y_test=forward(x)cost=(y_test-y)*(y_test-y)total_cost=total_cost+costreturn total_cost/m# 计算新的w的修正
def gradiedent(x_data,y_data):grad=0.0for x,y in zip(x_data,y_data):grad=grad+2*x*(x*w-y)return grad
epoch_list=[]
cost_list=[]print("训练前",4,forward(4))
for epoch in range(100):y_cost=cost(x_data,y_data)# 在当前w权重下计算,w的修正值grad_val=gradiedent(x_data,y_data)w = w - learning_rate * grad_valprint("轮次:",epoch,"w=",w,"loss",y_cost)epoch_list.append(epoch)cost_list.append(y_cost)
print("训练后",4,forward(4))#绘制损失loss与权重w之间的函数图像
plt.plot(epoch_list,cost_list)
plt.ylabel('Loss')
plt.xlabel('w')
plt.show()
结果:
随机梯度算法代码与设计:
import matplotlib.pyplot as plt# 随机梯度下降法和梯度下降法的主要区别在于:
# 1、损失函数由cost()更改为loss()。cost是计算所有训练数据的损失,loss是计算一个训练函数的损失。
# 对应于源代码则是少了两个for循环。
# 2、梯度函数gradient()由计算所有训练数据的梯度更改为计算一个训练数据的梯度。
# 3、本算法中的随机梯度主要是指,每次拿一个训练数据来训练,然后更新梯度参数。
# 本算法中梯度总共更新100(epoch)x3 = 300次。梯度下降法中梯度总共更新100(epoch)次。x_data=[1.0,2.0,3.0]
y_data=[2.0,4.0,6.0]m=len(x_data)
# 默认w的权值,随着梯度下降而修正
w=1.0
#学习率
learning_rate=0.01def forward(x):return x * w# 随机梯度算法
def loss(x_val,y_val):y_cost= forward(x_val)return (y_cost-y_val)*(y_cost-y_val)def gradiedent(x,y):return 2 * x*(forward(x) - y)epoch_list=[]
loss_list=[]print("训练前",4,forward(4))for epoch in range(100):for x,y in zip(x_data,y_data):grad=gradiedent(x,y)w=w-learning_rate*gradprint("x:",x,"y",y,"grad",grad)l=loss(x,y)# 疑问此处仅选择最后一次并没有达到随机的效果????print( "loss", l)print("进程轮数:",epoch,"w=",w,"loss",l)epoch_list.append(epoch)loss_list.append(l)print("训练后",4,forward(4))
# 绘制epoch_list与loss_list的图像
plt.plot(epoch_list,loss_list)
plt.ylabel('Loss')
plt.xlabel('epoch_list')
plt.show()
结果: