思路
梯度下降需要定义的
- costFunction J
- 对J不同变量的偏导数的数组
过程:
- 设置步长
- 每次求的偏导数
- 使用步长更新变量
- 计算J
- 判断是否已经满足精度,如果满足退出本次步长的迭代
代码
def dJ(x):
return 2 * (x - 2.5)
# 定义一个求函数值的函数J
def J(x):
try:
return (x - 2.5) ** 2 + 3
except:
return float('inf')
def GetMinByGradient(rho):
"""
:param rho: 步长
:return:
"""
x = 0.0
epsilon = 1e-8 # 精度
history_x = [x] # 下降时走过的X坐标
cnt = 0 # 下降走过的步数
min_x = 0
while True:
gradient = dJ(x) # 梯度(倒数)
last_x = x # 先记录上一次的值在更新
x = x - rho * gradient
history_x.append(x)
cnt += 1
if (abs(J(last_x)) - J(x) < epsilon): # 判断是否符合精度要求
min_x = x
break
return min_x, history_x, cnt
if __name__ == '__main__':
X = np.linspace(-1, 6, 150) # -1 到160之间等距离生成150个数字
Y = (X - 2.5) ** 2 + 3 # 计算实际的y
plt.scatter(X, Y)
plt.show()
min_x, history_x, cnt = GetMinByGradient(0.1)
plt.plot(X, Y)
plt.plot(np.array(history_x), J(np.array(history_x)), color='r', marker='*')
plt.show()
print('min_x =', (min_x))
print('min_y =', (J(min_x))) # 打印到达最低点时y的值
print('count =', (cnt))
# 计算梯度下降与步长之间的联系
sum_rhp = []
times = []
for i in range(1, 10, 1):
rho = i * 0.1
min_x, history_x, cnt = GetMinByGradient(rho)
sum_rhp.append(rho)
times.append(cnt) # 记录学习率从0.1到0.9,达到最小值时所迭代的次数
plt.scatter(sum_rhp, times, c = 'r') # 散点图
plt.plot(sum_rhp, times, c = 'r') # 线图
plt.title("the relation of rho and cnt")
plt.xlabel("rho")
plt.ylabel("cnt")
plt.show()
time_dict = dict(zip(sum_rhp, times))
print(time_dict)
运行结果如下
图一展示了梯度下降的过程,图二展示了不同步长与梯度下降收敛所需步数的关系。
解释
costFunction : J
对costFunction对不同的J进行求偏导数,dJ
最后得到的让J最小的min_x就是所求的参数
对应的最小的min_y就是对应着的最小的代价。