梯度下降实现python - 等高线
Posted
技术标签:
【中文标题】梯度下降实现python - 等高线【英文标题】:Gradient descent impementation python - contour lines 【发布时间】:2018-11-16 07:38:31 【问题描述】:作为一项自学练习,我试图从头开始对线性回归问题实施梯度下降,并将结果迭代绘制在等高线图上。
我的梯度下降实现给出了正确的结果(用 Sklearn 测试)但是梯度下降图似乎并不垂直到等高线。这是预期的还是我的代码/理解有问题?
算法
成本函数和梯度下降
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def costfunction(X,y,theta):
m = np.size(y)
#Cost function in vectorized form
h = X @ theta
J = float((1./(2*m)) * (h - y).T @ (h - y));
return J;
def gradient_descent(X,y,theta,alpha = 0.0005,num_iters=1000):
#Initialisation of useful values
m = np.size(y)
J_history = np.zeros(num_iters)
theta_0_hist, theta_1_hist = [], [] #For plotting afterwards
for i in range(num_iters):
#Grad function in vectorized form
h = X @ theta
theta = theta - alpha * (1/m)* (X.T @ (h-y))
#Cost and intermediate values for each iteration
J_history[i] = costfunction(X,y,theta)
theta_0_hist.append(theta[0,0])
theta_1_hist.append(theta[1,0])
return theta,J_history, theta_0_hist, theta_1_hist
情节
#Creating the dataset (as previously)
x = np.linspace(0,1,40)
noise = 1*np.random.uniform( size = 40)
y = np.sin(x * 1.5 * np.pi )
y_noise = (y + noise).reshape(-1,1)
X = np.vstack((np.ones(len(x)),x)).T
#Setup of meshgrid of theta values
T0, T1 = np.meshgrid(np.linspace(-1,3,100),np.linspace(-6,2,100))
#Computing the cost function for each theta combination
zs = np.array( [costfunction(X, y_noise.reshape(-1,1),np.array([t0,t1]).reshape(-1,1))
for t0, t1 in zip(np.ravel(T0), np.ravel(T1)) ] )
#Reshaping the cost values
Z = zs.reshape(T0.shape)
#Computing the gradient descent
theta_result,J_history, theta_0, theta_1 = gradient_descent(X,y_noise,np.array([0,-6]).reshape(-1,1),alpha = 0.3,num_iters=1000)
#Angles needed for quiver plot
anglesx = np.array(theta_0)[1:] - np.array(theta_0)[:-1]
anglesy = np.array(theta_1)[1:] - np.array(theta_1)[:-1]
%matplotlib inline
fig = plt.figure(figsize = (16,8))
#Surface plot
ax = fig.add_subplot(1, 2, 1, projection='3d')
ax.plot_surface(T0, T1, Z, rstride = 5, cstride = 5, cmap = 'jet', alpha=0.5)
ax.plot(theta_0,theta_1,J_history, marker = '*', color = 'r', alpha = .4, label = 'Gradient descent')
ax.set_xlabel('theta 0')
ax.set_ylabel('theta 1')
ax.set_zlabel('Cost function')
ax.set_title('Gradient descent: Root at '.format(theta_result.ravel()))
ax.view_init(45, 45)
#Contour plot
ax = fig.add_subplot(1, 2, 2)
ax.contour(T0, T1, Z, 70, cmap = 'jet')
ax.quiver(theta_0[:-1], theta_1[:-1], anglesx, anglesy, scale_units = 'xy', angles = 'xy', scale = 1, color = 'r', alpha = .9)
plt.show()
曲面和等高线图
评论
我的理解是梯度下降垂直跟随等高线。不是这样吗?谢谢
【问题讨论】:
梯度下降中的每一步都会减少总拟合误差,确实如此,但不能保证直接达到最小值。考虑一下你身体盘旋下山的情况——每一步都会让你下山,但不是直接下山。如果误差空间是“凹凸不平的”,那么梯度下降也可能会陷入局部误差空间的最小值,也就是说,梯度下降的步骤朝向较低的误差,但不一定朝向最低误差。 很公平,但是这个函数是平滑的二次函数,没有颠簸,也没有局部最小值…… 你是对的,每一步都会减少错误,但方向并不总是直接朝着最小值,只是朝着较低的错误。所以有“下降”,但并不总是在一条直线上。 同意,我的问题更多是关于为什么下降不垂直于轮廓。它与轮廓线成一定角度 梯度 w.r.t 总误差是为每个参数单独确定的,但在每个步骤中,参数都是同时更改的,并且不单独更改。正如您在此处看到的那样,这种组合变化可能不垂直于等高线。 【参考方案1】:等高图的问题是theta0和theta1的尺度不同。只需将“plt.axis('equal')”添加到等高线图指令中,您就会看到梯度下降实际上垂直于等高线。
Contour graph with same scales in both axis
【讨论】:
【参考方案2】:一般来说,梯度下降不遵循等高线。
只有当梯度向量的分量完全相同(绝对值)时,以下等高线才成立,这意味着评估点处函数的陡度在每个维度上都相同。
所以,在你的情况下,只有当等高线的曲线是同心圆而不是椭圆时。
【讨论】:
以上是关于梯度下降实现python - 等高线的主要内容,如果未能解决你的问题,请参考以下文章