梯度下降的两个主要挑战:
梯度下降流程就是“猜”正确答案的过程:
import numpy as np
import matplotlib.pyplot as plt
f = lambda x : (x - 3.5)**2 -4.5*x + 10
d = lambda x :2*(x - 3.5) - 4.5 # 梯度 == 导数 ### 导函数
step = 0.1 # 梯度下降的步幅,比例,(学习率,幅度)
# 求解当x等于多少的时候,函数值最小。求解目标值:随机生成的
# 相等于:'瞎蒙' ----> 方法 ----> 优化
x = np.random.randint(0,12,size = 1)[0]
# 梯度下降,每下降一步,每走一步,目标值,都会更新。
# 更新的这个新值和上一步的值,差异,如果差异很小(万分之一)
# 梯度下降退出
last_x = x + 0.02 # 记录上一步的值,首先让last_x和x有一定的差异!!!
# 精确率,真实计算,都是有误差,自己定义
precision = 1e-4
print('+++++++++++++++++++++', x)
x_ = [x]
while True:
# 退出条件,精确度,满足了
if np.abs(x - last_x) < precision: # 计算数组各元素的绝对值
break
# 更新
last_x = x
x -= step*d(x) # 更新,减法:最小值 # 通过倒数计算下一个值
x_.append(x)
print('--------------------',x)
# 数据可视化
plt.rcParams['font.family'] = 'Kaiti SC'
plt.figure(figsize=(9,6))
x = np.linspace(5.75 - 5, 5.75 + 5, 100)
y = f(x)
plt.plot(x,y,color = 'green')
plt.title('梯度下降',size = 24,pad = 15)
x_ = np.array(x_)
y_ = f(x_)
plt.scatter(x_, y_,color = 'red') # 画变化的点
plt.savefig('./图片/5-梯度下降.jpg',dpi = 200)
三种梯度下降的不同,主要体现在第二步中:
三种梯度下降开始的方法是一样的,梯度下降步骤分一下四步:
小批量梯度下降,是对批量梯度下降以及随机梯度下降的一个折中办法。其思想是:每次迭代使用总样本中的一部分(batch_size)样本来对参数进行更新。这里我们假设 batch_size = 20,样本数 n = 1000 。实现了更新速度与更新次数之间的平衡。
相对于随机梯度下降算法,小批量梯度下降算法降低了收敛波动性, 即降低了参数更新的方差,使得更新更加稳定。相对于全量梯度下降,其提高了每次学习的速度。并且其不用担心内存瓶颈从而可以利用矩阵运算进行高效计算。
一般情况下,小批量梯度下降是梯度下降的推荐变体,特别是在深度学习中。每次随机选择2的幂数个样本来进行学习,例如:8、16、32、64、128、256。因为计算机的结构就是二进制的。但是也要根据具体问题而选择,实践中可以进行多次试验, 选择一个更新速度与更次次数都较适合的样本数。MBGD梯度下降迭代的收敛曲线更加温柔一些.
虽然梯度下降算法效果很好,并且广泛使用,但是不管用上面三种哪一种,都存在一些挑战与问题,我们可以从以下几点进行优化:
import numpy as np
# 1、创建数据集X,y
X = np.random.rand(100, 1)
w,b = np.random.randint(1,10,size = 2)
y = w * X + b + np.random.randn(100, 1)
# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X,np.ones((100, 1))]
# 3、创建超参数轮次
epoches = 10000
# 4、定义一个函数来调整学习率
t0, t1 = 5, 1000
def learning_rate_schedule(t):
return t0/(t+t1)
# 5、初始化 W0...Wn,标准正太分布创建W
θ = np.random.randn(2, 1)
# 6、判断是否收敛,一般不会去设定阈值,而是直接采用设置相对大的迭代次数保证可以收敛
for i in range(epoches):
# 根据公式计算梯度
g = X.T.dot(X.dot(θ) - y)
# 应用梯度下降的公式去调整 θ 值
learning_rate = learning_rate_schedule(i)
θ = θ - learning_rate * g
print('真实斜率和截距是:',w,b) # 原始值
print('梯度下降计算斜率和截距是:',θ)
import numpy as np
# 1、创建数据集X,y
X = 2*np.random.rand(100, 1)
w,b = np.random.randint(1,10,size = 2)
y = w * X + b + np.random.randn(100, 1)
# 2、使用偏置项x_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]
# 3、创建超参数轮次、样本数量
epochs = 10000
n = 100
# 4、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):
return t0/(t+t1)
# 5、初始化 W0...Wn,标准正太分布创建W
θ = np.random.randn(2, 1)
# 6、多次for循环实现梯度下降,最终结果收敛
for epoch in range(epochs):
# 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序
index = np.arange(n) # 0 ~99
np.random.shuffle(index)
X = X[index] # 打乱顺序
y = y[index]
for i in range(n):
X_i = X[[i]]
y_i = y[[i]]
g = X_i.T.dot(X_i.dot(θ)-y_i) # 回归公式
learning_rate = learning_rate_schedule(epoch*n + i)
θ = θ - learning_rate * g
print('真实斜率和截距是:',w,b)
print('梯度下降计算斜率和截距是:',θ)
import numpy as np
# 1、创建数据集X,y
X = np.random.rand(100, 3)
w = np.random.randint(1,10,size = (3,1))
b = np.random.randint(1,10,size = 1)
y = X.dot(w) + b + np.random.randn(100, 1)
# 2、使用偏置项 X_0 = 1,更新X
X = np.c_[X, np.ones((100, 1))]
# 3、定义一个函数来调整学习率
t0, t1 = 5, 500
def learning_rate_schedule(t):
return t0/(t+t1)
# 4、创建超参数轮次、样本数量、小批量数量
epochs = 10000
n = 100
batch_size = 16
num_batches = int(n / batch_size)
# 5、初始化 W0...Wn,标准正太分布创建W
θ = np.random.randn(4, 1)
# 6、多次for循环实现梯度下降,最终结果收敛
for epoch in range(epochs):
# 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序
index = np.arange(n)
np.random.shuffle(index)
X = X[index]
y = y[index]
for i in range(num_batches):
# 一次取一批数据16个样本
X_batch = X[i * batch_size : (i + 1)*batch_size]
y_batch = y[i * batch_size : (i + 1)*batch_size]
g = X_batch.T.dot(X_batch.dot(θ)-y_batch) # 回归
learning_rate = learning_rate_schedule(epoch * n + i)
θ = θ - learning_rate * g
print('真实斜率和截距是:',w,b)
print('梯度下降计算斜率和截距是:',θ)