请有人解释一下如何在没有成本函数的情况下进行梯度下降问题?我见过无数的教程都是用成本函数来解释梯度下降的,但我真的不明白它在更一般的意义上是如何工作的。
我给出了一个3D函数:
z = 3*((1-xx)2) * np.exp(-(xx2) – (yy+1)2) \- 10*(xx/5 – xx3 – yy5) * np.exp(-xx2 – yy2)- (1/3)* np.exp(-(xx+1)**2 – yy2)
我被要求:
编写一个简单的梯度算法。设置参数如下:
- 学习率 = 步长:0.1
- 最大迭代次数:20
- 停止标准:0.0001(当你的梯度小于阈值时,你的迭代应该停止)
然后从以下点开始你的算法:
- (x0 = 0.5, y0 = -0.5)
- (x0 = -0.3, y0 = -0.3)
我见过这段代码在讨论梯度下降的任何地方流传:
def update_weights(m, b, X, Y, learning_rate): m_deriv = 0 b_deriv = 0 N = len(X) for i in range(N): # 计算偏导数 # -2x(y - (mx + b)) m_deriv += -2*X[i] * (Y[i] - (m*X[i] + b)) # -2(y - (mx + b)) b_deriv += -2*(Y[i] - (m*X[i] + b)) # 我们减去因为导数指向最陡的上升方向 m -= (m_deriv / float(N)) * learning_rate b -= (b_deriv / float(N)) * learning_rate return m, b enter code here
但我不明白如何将它用于我的问题。我的函数如何适应其中?我应该调整什么而不是m和b?我非常非常困惑。
谢谢你。
回答:
梯度下降是一种用于寻找函数最小值的优化算法。
非常简化的观点
让我们从一个1D函数 y = f(x) 开始
让我们从一个任意的x值开始,找到f(x)的梯度(斜率)。
-
如果在x处的斜率是递减的,那么这意味着我们需要进一步向x的方向移动(在数轴的右侧)(为了达到最小值)
-
如果在x处的斜率是递增的,那么这意味着我们需要远离x(在数轴的左侧)
我们可以通过求函数的导数来获得斜率。导数是负的如果斜率是递减的,导数是正的如果斜率是递增的
所以我们可以从某个任意的x值开始,使用该x值的导数慢慢地向最小值移动。我们移动的速度有多慢取决于学习率或步长。所以我们有更新规则
x = x - df_dx*lr
我们可以看到,如果斜率是递减的,导数(df_dx)是负的,x在增加,所以x在向右进一步移动。另一方面,如果斜率是递增的,df_dx是正的,这会减少x,所以我们向左移动。
我们继续这样做,要么进行大量的迭代,要么直到导数非常小
多变量函数 z = f(x,y)
与上述相同的逻辑适用,只是现在我们取偏导数而不是导数。更新规则是
x = x - dpf_dx*lry = y - dpf_dy*lr
其中dpf_dx是f关于x的偏导数
上述算法被称为梯度下降算法。在机器学习中,f(x,y)是一个我们感兴趣其最小值的成本/损失函数。
示例
import numpy as npimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d.axes3d import Axes3Dfrom pylab import meshgridfrom scipy.optimize import fminimport mathdef z_func(a): x, y = a return ((x-1)**2+(y-2)**2) x = np.arange(-3.0,3.0,0.1)y = np.arange(-3.0,3.0,0.1)X,Y = meshgrid(x, y) # 点的网格Z = z_func((X, Y)) # 在网格上评估函数fig = plt.figure()ax = fig.gca(projection='3d')surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,linewidth=0, antialiased=False)plt.show()
z_func的最小值在(1,2)。这可以使用scipy的fmin函数验证
fmin(z_func,np.array([10,10]))
现在让我们编写我们自己的梯度下降算法来找到z_func的最小值
def gradient_decent(x,y,lr): while True: d_x = 2*(x-1) d_y = 2*(y-2) x -= d_x*lr y -= d_y*lr if d_x < 0.0001 and d_y < 0.0001: break return x,yprint (gradient_decent(10,10,0.1)
我们从一个任意的值x=10和y=10以及学习率0.1开始。上述代码打印1.000033672997724 2.0000299315535326
,这是正确的。
所以如果你有一个连续可微的凸函数,要找到它的最优值(对于凸函数是最小值),你所需要做的就是找到函数相对于每个变量的偏导数,并使用上述提到的更新规则。重复这些步骤直到梯度很小,这意味着我们已经达到了凸函数的最小值。
如果函数不是凸的,我们可能会陷入局部最优。