机器学习之python实现梯度下降
程序员文章站
2022-07-14 15:15:07
...
本文使用pytohn3,jupyter notebook
本文禁止转载!
一、一元函数的梯度下降
已知一个一元函数:
求f(x)最低点。
实际上用初中知识我们就可以求出最低点坐标,但是我们今天来使用梯度下降的方法。
1.什么是梯度下降
对于该函数,我们想求出最低点,但是我们不知道最低点在哪里,于是我们瞎蒙一个:x=5
求得f(5)=84。
但是我们不知道它是不是最低点,但是我们会求导:
很显然,x=5处不是最低点,而且此处导数为正,函数单调上升。
那么我们可以尝试把x变小一点,这样就会更接近最低点。
令x=4。
得f(4)=55,比刚刚更接近最低点,这样我们就可以不断接近最低点了。
但是为什么让x减小到4?减小到3可以吗?减小到4.5可以吗?
我们把x的变化称之为步长,那么这个步长应该怎么选取?
我们知道如果导数的绝对值越大,离极值点也就越远,那么我们应该把步子迈得大一些。而导数越接近于0,离极值点就越近,那么我们应该小心翼翼的前进。所以步长是与改点的导数成正相关。他们的比例系数我们称之为学习率。
如果学习率选取的不合理就会出现梯度消失和梯度爆炸。
梯度消失:
可以看到,步长如果比较大,就会在极值点附近来回震荡,而误差也减小得很慢。
梯度爆炸:
可以看到,步长非常大时,不仅没有靠近极值点,反而越来越远,我们称之为梯度爆炸
下面,我们来实现梯度下降的过程。
2.导入必要的包
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
3.画出函数图像
f = lambda x:3*x**2+2*x-1
x = np.linspace(-6,5,1000)
y = np.array(list(map(f, x)))
plt.plot(x,y)
4.求导
d = lambda x:6*x+2
5.梯度下降
# 设置学习率
learning_rate = 0.1
# 精确度
precision = 0.0001
# 随机生成一个初始x
min_x = random.random()*11-6
# 计数
count = 0
while True:
# 求出该点导数
dx = d(min_x)
print('count:{},x:{}'.format(count,min_x))
# 沿导数方向前进
min_x -= learning_rate * dx
count += 1
if abs(learning_rate * dx) < precision or count > 5000:
break
print('count:{},x:{}'.format(count,min_x))
6.画图
plt.figure(figsize=(12,7))
x = np.linspace(-6,5,1000)
y = np.array(list(map(f, x)))
plt.plot(x,y)
x = np.array(x_list)
y = np.array(list(map(f, x)))
plt.plot(x,y,color='red')
二、二元函数梯度下降
有二元函数:
求最低点。
1.导入必要的包
from matplotlib import pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
2.画出三维图像
fig = plt.figure(figsize=(12,7))
ax = Axes3D(fig)
X = np.linspace(-100, 100, 50)
Y = np.linspace(-100, 100, 50)
X, Y = np.meshgrid(X, Y)
# R = np.sqrt(X**2 + Y**2)
Z = X**2 + Y**2 + 2*X
ax.plot_surface(X, Y, Z,cmap='rainbow')
3.导函数
二元函数存在两个方向上的导数
dx = lambda x,y:2*x+2
dy = lambda x,y:2*y
4.梯度下降
# 设置学习率
learning_rate = 0.2
# 精确度
precision = 0.0001
# 随机生成一个初始x,y
min_x = random.random()*200-100
min_y = random.random()*200-100
# 计数
count = 0
# 记录过程
xy_list = []
while True:
xy_list.append([min_x,min_y])
# 求出该点导数
dx_ = dx(min_x,min_y)
dy_ = dy(min_x,min_y)
print('count:{},x:{},y:{}'.format(count,min_x,min_y))
# 沿导数方向前进
step_x = learning_rate * dx_
step_y = learning_rate * dy_
min_x -= step_x
min_y -= step_y
count += 1
if step_x**2+step_y**2 < precision**2 or count > 5000:
xy_list.append([min_x,min_y])
break
print('count:{},x:{},y:{}'.format(count,min_x,min_y))
5.画图
fig = plt.figure(figsize=(12,7))
ax = Axes3D(fig)
X = np.linspace(-100, 100, 50)
Y = np.linspace(-100, 100, 50)
X, Y = np.meshgrid(X, Y)
Z = X**2 + Y**2 + 2*X
ax.plot_surface(X, Y, Z,cmap='rainbow',alpha=0.3)
xy_np = np.array(xy_list)
X = xy_np[:,0].reshape([-1])
Y = xy_np[:,1].reshape([-1])
Z = X**2 + Y**2 + 2*X
ax.plot(X, Y, Z,color='red')
可以看到一条逐渐滑向谷底的线。
下一篇:纯python实现线性回归