赞
踩
f() 和 g()函数分别为求y值和求导数的函数。
目的:求该函数的最小值:
代码:
- import numpy as np
- import matplotlib.pyplot as plt
-
- f = lambda x : (x - 3.5) ** 2 - 4.5 * x + 10
- g = lambda x : 2 * (x - 3.5) - 4.5
-
- x = np.linspace(0, 11.5, 100)
- y = f(x)
-
- plt.plot(x, y)
在 0 - 12 中随机取一个值:10
- k = np.random.randint(0, 12)
- print('随机取到的值k:', k) # 10
查看此时的切线方程:
- k = 10
- g(x) = 8.5 # 斜率
- f(x) = 7.5 # y值
- # 该点的切线方程:y = 8.5 * x - 77.5
-
- plt.plot(x, y)
- plt.scatter(k, f(k), color = 'red', s = 30)
-
- # 生成x的范围
- x_values = np.linspace(8, 11.5, 100)
-
- # 计算对应的y值
- y_values = 8.5 * x_values - 77.5
- # 绘制直线
- plt.plot(x_values, y_values, color='blue', label='Line')
设置学习率为0.2,与初始点的梯度反向进行下降,如果在上一个点斜率为正,说明需要x需要向左移动才能接近最小值:next_k = k - 学习率*斜率
学习率可以改,设置值比较大移动比较快,设置比较小移动比较慢。
求到的第一个K:8.3
- learing_ratio = 0.2
- next_k = k - learing_ratio*g(k)
-
- plt.plot(x, y)
- plt.scatter(k, f(k), color = 'red', s = 30)
- plt.scatter(next_k, f(next_k), color = 'red', s = 30)
-
- print(next_k, f(next_k))
- # 8.3 -4.309999999999995
用上一次计算的 8.2 计算一个值:next_k2 = next_k - learing_ratio*g(next_k) 。
求到的第二个K:7.28
- learing_ratio = 0.2
- next_k2 = next_k - learing_ratio*g(next_k)
-
- plt.plot(x, y)
- plt.scatter(k, f(k), color = 'red', s = 30)
- plt.scatter(next_k, f(next_k), color = 'red', s = 30)
- plt.scatter(next_k2, f(next_k2), color = 'red', s = 30)
- print(next_k2, f(next_k2))
- # 7.28 -8.471599999999995
查看两次迭代过程中 y值的变化率分别为:-11.559999999999995 -4.1616
- plt.plot(x, y)
- plt.scatter([k, next_k, next_k2], [f(k), f(next_k), f(next_k2)],
- color = 'red', s = 30)
-
- # 绘制直线
- plt.plot(x, [f(k)] * len(x), label='y=5', color='blue', linestyle='--')
- plt.plot(x, [f(next_k)] * len(x), label='y=5', color='green', linestyle='--')
- plt.plot(x, [f(next_k2)] * len(x), label='y=5', color='red', linestyle='--')
-
- print(f(next_k) - f(k), f(next_k2) - f(next_k)) # -11.5599999999-4.1616
注意:截止条件设置的变化率是x 的变化率,就是当 斜率的变化值足够小 的时候截止,其实也是y值的变化率乘学习率后的变化值 !!
k = k - learing_ratio*g(k)
设置截止循环条件:precision = 0.0001
- learing_ratio = 0.2
- last_k = k + 0.1
- # 精确度
- precision = 0.0001
-
- k_ = [k]
- count = 0 # 记录迭代次数
-
- while True:
- if np.abs(k - last_k) < precision:
- break
- last_k = k
- count += 1
- k = k - learing_ratio*g(k) # 迭代
- k_.append(k)
- print(f'-> 迭代次数cnt:{count:2},更新后的x:{k:0.7f}, 实时的y:{f(k):0.7f}')
-
- print(f'梯度下降的次数:{count}')
- plt.plot(x, y)
- print('最后的k值:', k) # 5.75009323204022
-
- # 散点图,转换为array数组可以用f(x)直接求列表的y值
- k_ = np.array(k_)
- plt.scatter(k_, f(k_), color = 'red', s = 30)

PS:最后的列表直接求y值是先转换为了 np.array数组!!!
实际值:5.75
循环21次,最后求到的k值:5.75009323204022
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。