什么是梯度下降,举个栗子,(假设地面无障碍物)我们在山顶丢一个网球,啪,一下就越过这个坡了,然后在另一个沟里来回跳动,一直到达最低点。那么问题来了,这这里在跳跃的过程中,直接越过第一个坡度。这样的结果就是使得我们的小球无法到达最低点,对应到程序上就是我们在梯度下降的时候无法找到最优值。
梯度下降,就是是在不断就是出于最高点,先下走一个步长,不断的走,或回撤步长的过程。使得我们找到目标的最优值。那么有个问题就是步长(也称为学习率)取值为多少才适合? 过大的步长容易使得跳过最优值,过小的步长使得梯度下降的效率过低。
梯度下降的过程,其实就是迭代求解的过程.
在公式推导之前,我们先引入预测值函数
hθ(x) :预测值 θ1 :权重 θ0 :偏置
还有,损失函数(也叫代价函数)
该损失函数是由高斯分布的预测误差求取对数拟然函数,结果的被减项得出的.原结果1/2并不是1/2m,这里分母加了m,是为了去除样本对损失函数的影响,是的减少样本数对损失函数的影响. (这里如果为加1/m,结果将是样本次数越多,损失函数越大,样本对损失函数的影响非常大.)
根据损失函数,我们接下来对 权重θ1 与 偏置 θ0 ,求取对应的偏导数.
上面的 α 就是我们设置的学习率.
接下来我们将使用高尔夫球的案例来写梯度下降的算法.
链接:https://pan.baidu.com/s/1GJ20Kha2AMF5Qw0hRUarVQ
提取码:0fjw
数据集我保存到云盘,需要的可以自己下载一下
#梯度下降
import pandas
import matplotlib.pyplot as plt
# 高尔夫球数据集
pga = pandas.read_csv("pga.csv")
# 数据标准化
pga.distance = (pga.distance - pga.distance.mean()) / pga.distance.std()
pga.accuracy = (pga.accuracy - pga.accuracy.mean()) / pga.accuracy.std()
print(pga.head())
plt.scatter(pga.distance, pga.accuracy)
plt.xlabel('normalized distance')
plt.ylabel('normalized accuracy')
plt.show()
##distance: 挥杆之后的距离
## accuracy : 精度
# accuracyi=θ1distancei+θ0+ϵ
from sklearn.linear_model import LinearRegression
import numpy as np
# We can add a dimension to an array by using np.newaxis
print("Shape of the series:", pga.distance.shape)
print("Shape with newaxis:", pga.distance[:, np.newaxis].shape)
# fit()中的X变量必须是二维的
lm = LinearRegression()
lm.fit(pga.distance[:, np.newaxis], pga.accuracy)
theta1 = lm.coef_[0]
print (theta1)
# 单变量线性模型的成本函数
# hθ(x) = θ1X + θ0
#计算损失函数,J(θ0,θ1) = 1/2m *累加 (hθ(Xi)-Yi)**2
def cost(theta0, theta1, x, y):
# 初始化成本
J = 0
# 观测次数
m = len(x)
# 遍历每个观测值
for i in range(m):
# 计算假设
h = theta1 * x[i] + theta0
# 累加成本
J += (h - y[i])**2
# 平均和规范成本
J /= (2*m)
return J
# 损失函数 theta0=0 and theta1=1
print(cost(0, 1, pga.distance, pga.accuracy))
theta0 = 100
theta1s = np.linspace(-3,2,100)
costs = []
for theta1 in theta1s:
costs.append(cost(theta0, theta1, pga.distance, pga.accuracy))
plt.plot(theta1s, costs)
plt.show()
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
# 使用Matplotlib的地表绘图示例
# 创建x和y变量
x = np.linspace(-10,10,100)
y = np.linspace(-10,10,100)
# 我们必须创建变量来表示x和y中每一对可能的点
# ie. (-10, 10), (-10, -9.8), ... (0, 0), ... ,(10, 9.8), (10,9.8)
# x和y需要转换成100x100矩阵来表示这些坐标
# np.meshgrid will build a coordinate matrices of x and y
X, Y = np.meshgrid(x,y)
#print(X[:5,:5],"\n",Y[:5,:5])
# 计算一个三维抛物线
Z = X**2 + Y**2
# 打开一个画布
fig = plt.figure()
# I初始化3 d图
ax = fig.gca(projection='3d')
# 绘制图像
ax.plot_surface(X=X,Y=Y,Z=Z)
plt.show()
theta0s = np.linspace(-2,2,100)
theta1s = np.linspace(-2,2, 100)
COST = np.empty(shape=(100,100))
# Meshgrid为参数
T0S, T1S = np.meshgrid(theta0s, theta1s)
# 累计每个参数组合计算成本
for i in range(100):
for j in range(100):
COST[i,j] = cost(T0S[0,i], T1S[j,0], pga.distance, pga.accuracy)
# 绘制3d图
fig2 = plt.figure()
ax = fig2.gca(projection='3d')
ax.plot_surface(X=T0S,Y=T1S,Z=COST)
plt.show()
#假设函数的权重求导
def partial_cost_theta1(theta0, theta1, x, y):
# 假设函数
h = theta0 + theta1*x
# 对θ1求导后的公式进行计算,θ1的偏导数
diff = (h - y) * x
# 累加偏导数和,除于样本个数
partial = diff.sum() / (x.shape[0])
return partial
partial1 = partial_cost_theta1(0, 5, pga.distance, pga.accuracy)
print("partial1 =", partial1)
#假设函数的偏置求导
def partial_cost_theta0(theta0, theta1, x, y):
# 假设函数
h = theta0 + theta1*x
# 对θ0求导后的公式进行计算,θ1的偏导数
diff = (h - y)
# 累加偏导数和,除于样本个数
partial = diff.sum() / (x.shape[0])
return partial
partial0 = partial_cost_theta0(1, 1, pga.distance, pga.accuracy)
# x是特征向量 -- distance
# y 是目标标签 -- accuracy
# alpha 是学习率
# theta0 是偏置
# theta1 是权重
def gradient_descent(x, y, alpha=0.1, theta0=0, theta1=0):
max_epochs = 1000 # 最大迭代次数
counter = 0 # 计数器
c = cost(theta1, theta0, pga.distance, pga.accuracy) ## 损失函数
costs = [c] # 储存损失函数
# 设置收敛阈值,找出代价函数在何处最小
# 以前成本与当前成本之差,小于这个值我们就说参数收敛了,即已经快找点目标了
convergence_thres = 0.000001 #收敛的阈值
cprev = c + 10 #这里加10是为了设置一个起始值,要计算起始值与损失函数的距离
theta0s = [theta0]
theta1s = [theta1]
# 当成本收敛或我们遇到大量迭代时,我们将停止更新
while (np.abs(cprev - c) > convergence_thres) and (counter < max_epochs):
cprev = c #这里把损失函数的值赋给了起始值,使得范围进一步缩小
# 学习率乘与对θ求导
update0 = alpha * partial_cost_theta0(theta0, theta1, x, y)
update1 = alpha * partial_cost_theta1(theta0, theta1, x, y)
# 同时更新theta0和theta1
# 我们想要在同一组假设参数下计算斜率,所有要求出偏导后再更新
theta0 -= update0
theta1 -= update1
# 保存 thetas
theta0s.append(theta0)
theta1s.append(theta1)
# 计算新损失函数
c = cost(theta0, theta1, pga.distance, pga.accuracy)
# 保存更新
costs.append(c)
counter += 1 # Count
return {'theta0': theta0, 'theta1': theta1, "costs": costs}
print("Theta1 =", gradient_descent(pga.distance, pga.accuracy)['theta1'])#输出权重
descend = gradient_descent(pga.distance, pga.accuracy, alpha=.01)
plt.scatter(range(len(descend["costs"])), descend["costs"])
plt.show()