GD(梯度下降)
一.梯度下降分类
1.批量梯度下降(Batch Gradient Descent)——BGD
2.随机梯度下降(Stochastic Gradient Descent)——SGD
3.小批量梯度下降(Mini-Batch Gradient Descent)——MBGD
下面以线性回归算法来对三种不同梯度下降法进行理解:
假设线性回归函数(前向传播):
对应的损失函数(均方误差):
二.批量梯度下降(BGD)
思想:每一次的参数更新都用到了所有的训练样本数据;
1.损失函数对求偏导,求梯度loss.backward():
2.对参数进行更新(以下缺少lr),opt.step():
3.以epoch的次数按以上步骤进行迭代,参数更新次数为epoch次;
4.BGD伪代码:
优点:
由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,BGD一定能够得到全局最优。
缺点:
当样本数目m 很大时,每迭代更新参数都需要对所有样本计算,训练过程会很慢。
批量梯度下降的梯度变化趋势
批量梯度下降的收敛图
import numpy as np
#批量梯度下降(BGD)
def BatchGradientDescent(x, label, w):
for epoch in range(5000):
y = np.dot(x, w) #前向传播,[10,]
MSEloss = (1 / 2) * np.mean((y - label) ** 2) #MSEloss:均方误差,[10,]
print("MSEloss=",MSEloss)
loss = y - label #注意这里有10个样本的平均误差, [10,] ,下面更新10个都用到
gradient = np.dot(loss, x) / x.shape[0] #对所有的样本(10个样本)求梯度并相加,再除10(10个样本平均梯度),[3,]
w = w - 0.1 * gradient #更新参数w,[3,]
# dw1 = np.dot(loss,x[:,0])/ x.shape[0]
# dw2 = np.dot(loss, x[:, 1]) / x.shape[0]
# dw3 = np.dot(loss, x[:, 2]) / x.shape[0]
# w = w - 0.1*np.array([dw1,dw2,dw3])
return w
#前向传播(测试用)
def predict(x, w):
y = np.dot(x, w)
return y
if __name__ == '__main__':
#训练全部数据和标签(10个样本和10个标签)
train_x = np.array([[1.1,1.5,1],[1.3,1.9,1],[1.5,2.3,1],[1.7,2.7,1],[1.9,3.1,1],[2.1,3.5,1],[2.3,3.9,1],[2.5,4.3,1],[2.7,4.7,1],[2.9,5.1,1]])
train_y = np.array([2.5,3.2,3.9,4.6,5.3,6,6.7,7.4,8.1,8.8])
#随机初始化权重w
ran = np.random.RandomState(0)
w = ran.randn(train_x.shape[1])
#调用批量梯度下降,返回更新的参数w
w = BatchGradientDescent(train_x, train_y, w)
print ("w = ",w)
#测试数据和测试
test_x = np.array([[3.1, 5.5,1], [3.3, 5.9,1], [3.5, 6.3,1], [3.7, 6.7,1], [3.9, 7.1,1]])
print (predict(test_x, w))
三.随机梯度下降(SGD)
思想:每一次的参数更新都用到了一个样本数据;
1.损失函数对求偏导,求梯度loss.backward():
2.对参数进行更新(以下缺少lr),opt.step():
3.SGD伪代码:
优点:
随机梯度下降在每次更新的时候,只考虑了一个样本点,这样会大大加快训练数据。
缺点:
开始容易陷入局部最优解,并震荡大跳出局部最优解,但由于更新次数多,整体方向还是一直朝这全局最优解方向走,SGD特点:每一次进行更新的过程中,就不一定是朝着极小值方向更新(盲目搜索过程)。
随机梯度下降的梯度变化趋势
随机梯度下降的收敛图
import numpy as np
#随机梯度下降(SGD)
def StochasticGradientDescent(x, label, w):
# 选取一个样本来更新权重w
for epoch in range(1000):
for data in range(10):
y = np.dot(x, w) #前向传播,[10,]
MSEloss = (1 / 2) * np.mean((y - label) ** 2) # MSEloss:均方误差,[10,]
print("MSEloss=", MSEloss)
loss = y - label #注意这里有10个样本的平均误差, [10,] ,取一个样本进行更新即可
gradient = loss[data]*x[data] #只取这一个样本进行更新计算梯度,[3,]
w = w - 0.1 * gradient #更新参数w,[3,]
return w
#前向传播(测试用)
def predict(x, w):
y = np.dot(x, w)
return y
if __name__ == '__main__':
# 训练全部数据和标签(10个样本和10个标签)
train_x = np.array(
[[1.1, 1.5, 1], [1.3, 1.9, 1], [1.5, 2.3, 1], [1.7, 2.7, 1], [1.9, 3.1, 1], [2.1, 3.5, 1], [2.3, 3.9, 1],
[2.5, 4.3, 1], [2.7, 4.7, 1], [2.9, 5.1, 1]])
train_y = np.array([2.5, 3.2, 3.9, 4.6, 5.3, 6, 6.7, 7.4, 8.1, 8.8])
# 随机初始化权重w
ran = np.random.RandomState(0)
w = ran.randn(train_x.shape[1])
# 调用随机梯度下降,返回更新的参数w
w = StochasticGradientDescent(train_x, train_y, w)
print("w = ", w)
# 测试数据和测试
test_x = np.array([[3.1, 5.5, 1], [3.3, 5.9, 1], [3.5, 6.3, 1], [3.7, 6.7, 1], [3.9, 7.1, 1]])
print(predict(test_x, w))
四.小批量梯度下降(MBGD)
思想:每一次的参数更新都用到了bitch_size个样本数据,假如以bitch_size=10为列,样本数m=1000;
1.MBGD过程:
2.MBGD伪代码:
3.优点:结合了BGD和SGD两者的优点,相比BGD算法的训练过程比较快,而且相比SGD也要保证最终参数训练的准确率;
import numpy as np
#批量梯度下降(MBGD)
def MiniBatchGradientDescent(x, label, w):
# 选取一个batch_size来更新权重w
for epoch in range(2000):
batch_size=5
for data in range(10//batch_size):
y = np.dot(x, w) #前向传播,[10,]
MSEloss = (1 / 2) * np.mean((y - label) ** 2) # MSEloss:均方误差,[10,]
print("MSEloss=", MSEloss)
loss = y - label #注意这里有10个样本的误差, [10,] ,取bitch_size样本进行更新即可
gradient = np.dot(loss[5*data:5*(data+1)],x[5*data:5*(data+1)]) #只取bitcg_size样本进行更新计算梯度,[3,]
w = w - 0.01 * gradient #更新参数w,[3,]
return w
#前向传播(测试用)
def predict(x, w):
y = np.dot(x, w)
return y
if __name__ == '__main__':
# 训练全部数据和标签(10个样本和10个标签)
train_x = np.array(
[[1.1, 1.5, 1], [1.3, 1.9, 1], [1.5, 2.3, 1], [1.7, 2.7, 1], [1.9, 3.1, 1], [2.1, 3.5, 1],
[2.3, 3.9, 1],[2.5, 4.3, 1], [2.7, 4.7, 1], [2.9, 5.1, 1]])
train_y = np.array([2.5, 3.2, 3.9, 4.6, 5.3, 6, 6.7, 7.4, 8.1, 8.8])
# 随机初始化权重w
ran = np.random.RandomState(0)
w = ran.randn(train_x.shape[1])
# 调用随机梯度下降,返回更新的参数w
w = MiniBatchGradientDescent(train_x, train_y, w)
print("w = ", w)
# 测试数据和测试
test_x = np.array([[3.1, 5.5, 1], [3.3, 5.9, 1], [3.5, 6.3, 1], [3.7, 6.7, 1], [3.9, 7.1, 1]])
print(predict(test_x, w))