机器学习里面,梯度下降法可以说是随处可见,虽然它不是什么高大上的机器学习算法,但是它却是用来解决机器学习算法的良药。我们经常会用到梯度下降法来对机器学习算法进行训练。
BGD,SGD,MBGD。也就是批量梯度下降法BGD,随机梯度下降法SGD,小批量梯度下降法MBGD。
下面这篇文章对这三个概念讲解的很到位:
http://www.cnblogs.com/maybe2030/p/5089753.html#_label0
总结一下:
1、批量梯度下降每次更新使用了所有的训练数据,最小化损失函数,如果只有一个极小值,那么批量梯度下降是考虑了训练集所有的数据,是朝着最小值迭代运动的,但是缺点是如果样本值很大的话,更新速度会很慢。
2、随机梯度下降在每次更新的时候,只考虑一个样本点,这样会大大加快训练数据,也恰好是批量梯度下降的缺点,但是有可能由于训练数据的噪声点较多,那么每一次利用噪声点进行更新的过程中,就不一定是朝着极小值方向更新,但是由于更新多轮,整体方向还是朝着极小值方向更新,又提高了速度。
3、小批量梯度下降法是为了解决批量梯度下降的训练速度慢,以及随机梯度下降法的准确性综合而来,但是这里注意,不同问题的batch是不一样的,要通过实验结果来进行超参数的调整。
参考python代码:
# coding=utf-8
import numpy as np
import matplotlib.pyplot as plt
# 构造数据
def get_data(sample_num=1000):
"""
拟合函数为
y = 5*x1 + 7*x2
:return:
构造1000组数据集(x1,x2,y)
"""
'''生成具有sample_num=1000个等间隔元素的范围是[0,9]的一个数列'''
x1 = np.linspace(0, 9, sample_num)
x2 = np.linspace(4, 13, sample_num)
'''将x1,x2合并成2*sample_num的矩阵并转置,最终是sample_num*2的矩阵'''
x = np.concatenate(([x1], [x2]), axis=0).T
'''x.dot(y) 等价于 np.dot(x,y) 两个矩阵相乘'''
y = np.dot(x, np.array([5, 7]).T)
return x, y
# 梯度下降法
def SGD(samples, y, step_size=0.1, max_iter_count=2000):
"""
:param samples: 样本
:param y: 结果value
:param step_size: 每一接迭代的步长
:param max_iter_count: 最大的迭代次数
:param batch_size: 随机选取的相对于总样本的大小
:return:
"""
# 确定样本数量以及变量的个数初始化theta值
m, var = samples.shape # m=1000是行,var=2是列
theta = np.zeros(2)
'''flatten,把y降到一维,默认是按横的方向降。y.flatten('F')按竖的方向降。
此处就是将y进行转置
'''
y = y.flatten()
# 进入循环内
loss = 1
iter_count = 0
iter_list = []
loss_list = []
theta1 = []
theta2 = []
# 当损失精度大于0.01且迭代此时小于最大迭代次数时,进行
while loss > 0.01 and iter_count < max_iter_count:
loss = 0
# 梯度计算
theta1.append(theta[0])
theta2.append(theta[1])
# 样本维数下标
rand1 = np.random.randint(0, m, 1) # 生成大小在范围[0,m]内的一个随机数
h = np.dot(theta, samples[rand1].T) # samples[rand1]第rand1行
# 关键点,只需要一个样本点来更新权值
for i in range(len(theta)):
theta[i] = theta[i] - step_size * (1/m) * (h - y[rand1]) * samples[rand1, i]
"""
# batch_size = np.random.randint(0, m, 1)
batch_size = range(1, m)
batch_size = np.array(batch_size)
(si,) = batch_size.shape
dev = 0
for i in range(len(theta)):
for j in batch_size:
h = np.dot(theta, samples[j].T)
dev = dev + (1 / si) * (h - y[j]) * samples[j, i]
theta[i] = theta[i] - step_size * dev
"""
# 计算总体的损失精度,等于各个样本损失精度之和
for i in range(m):
h = np.dot(theta.T, samples[i])
# 每组样本点损失的精度
every_loss = (1 / (var * m)) * np.power((h - y[i]), 2)
loss = loss + every_loss
print("iter_count: ", iter_count, "the loss:", loss)
iter_list.append(iter_count)
loss_list.append(loss)
iter_count += 1
plt.plot(iter_list, loss_list)
plt.xlabel("iter")
plt.ylabel("loss")
plt.show()
return theta1, theta2, theta, loss_list
if __name__ == '__main__':
samples, y = get_data()
theta1, theta2, theta, loss_list = SGD(samples, y)
print(theta) # 会很接近[5, 7]