梯度下降法的准确性与调试
对于梯度下降法的使用,一个非常重要的步骤是求解我们定义的损失函数(J)在某个点( heta)上的梯度值(dJ),我们也花了很长时间来推导此公式,但是对于一些复杂的函数如非线性函数,求解梯度并不容易,在这种情况下,为了保证求解的梯度表达式正确,发现求解过程中的错误,需要进行梯度下降法的调试
定义( heta=( heta_0, heta_1, heta_2, heta _0,..., heta _n)) ,对每一个( heta)求导:
[Lambda J = (frac{partial J}{partial heta _0},frac{partial J}{partial heta _1},frac{partial J}{partial heta _2},...,frac{partial J}{partial heta _n})
]
而其中:
[frac{partial J}{partial heta _i} = frac{J( heta_i^+ )-J( heta_i^-)}{2varepsilon } =frac{J( heta_i +varepsilon )-J( heta_i -varepsilon )}{2varepsilon }
]
调试的过程:
构造数据集
import numpy
import matplotlib.pyplot as plt
numpy.random.seed(666)
X = numpy.random.random(size=(1000,10))
true_theta = numpy.arange(1,12)
X_b = numpy.hstack([numpy.ones((len(X),1)),X])
y = X_b.dot(true_theta) + numpy.random.normal(size=1000)
定义损失函数和梯度下降方法:
def J(theta,X_b,y): #损失函数的表达式
return numpy.sum((y - X_b.dot(theta))**2)/len(X_b)
def dJ_math(theta,X_b,y):
return X_b.T.dot(X_b.dot(theta)-y)*2/len(X_b)
def dJ_Debug(theta,X_b,y,epsilon=0.01):
m = len(theta)
res = numpy.empty(m)
for i in range(m):
theta_1 = theta.copy()
theta_1[i] += epsilon
theta_2 = theta.copy()
theta_2[i] -= epsilon
res[i] = (J(theta_1,X_b,y)-J(theta_2,X_b,y))/(2*epsilon)
return res
定义梯度下降过程:
def gradient_descent(dJ,X_b,y,init_theta,eta,n_iters=1e4,espilon=1e-8):
theta = init_theta
i_iters = 0
# n_iters 表示梯度下降的次数,超过这个值,有可能算法不收敛,退出
while n_iters>i_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)) < espilon:
break
i_iters += 1
# 返回求出的theta值
return theta
init_theta = numpy.zeros(X_b.shape[1])
eta=0.01
使用调试的方法梯度下降,查看( heta)值和计算时间
%time theta = gradient_descent(dJ_Debug,X_b,y,init_theta,eta,n_iters=1e4,espilon=1e-8)
使用数学推导的方法梯度下降,查看( heta)值和计算时间
%time theta = gradient_descent(dJ_math,X_b,y,init_theta,eta,n_iters=1e4,espilon=1e-8)
通过结果比较,我们能确定数学推导的求梯度公式的正确性。