失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 深度学习(一)优化算法之随机梯度下降法(SGD)详解

深度学习(一)优化算法之随机梯度下降法(SGD)详解

时间:2020-03-25 15:13:19

相关推荐

深度学习(一)优化算法之随机梯度下降法(SGD)详解

优化算法

1.SGD

随机梯度下降法:

θi+1=θi−η∇L(θ)\theta_{i+1} = \theta_i - \eta \nabla L(\theta)θi+1​=θi​−η∇L(θ)

import numpy as npimport torchfrom torchvision.datasets import MNIST # 导入 pytorch 内置的 mnist 数据from torch.utils.data import DataLoaderfrom torch import nnimport timeimport matplotlib.pyplot as plt%matplotlib inline

def data_tf(x):x = np.array(x, dtype='float32') / 255 # 将数据变到 0 ~ 1 之间x = (x - 0.5) / 0.5 # 标准化,这个技巧之后会讲到x = x.reshape((-1,)) # 拉平x = torch.from_numpy(x)return xtrain_set = MNIST('./data', train=True, transform=data_tf) # 载入数据集,申明定义的数据变换test_set = MNIST('./data', train=False, transform=data_tf)

# 定义 loss 函数criterion = nn.CrossEntropyLoss()

def sgd_update(parameters, lr):for param in parameters:param.data = param.data - lr * param.grad.data

# batch size设为1train_data = DataLoader(train_set, batch_size=1, shuffle=True)# 使用 Sequential 定义 3 层神经网络net = nn.Sequential(nn.Linear(784, 200),nn.ReLU(),nn.Linear(200, 10),)# 开始训练losses1 = []idx = 0start = time.time() # 记时开始for e in range(5):train_loss = 0for im, label in train_data:# 前向传播out = net(im)loss = criterion(out, label)# 反向传播net.zero_grad()loss.backward()sgd_update(net.parameters(), 1e-2) # 使用 0.01 的学习率# 记录误差train_loss += loss.item()if idx % 30 == 0:losses1.append(loss.item())idx += 1print('epoch: {}, Train Loss: {:.6f}'.format(e, train_loss / len(train_data)))end = time.time() # 计时结束print('使用时间: {:.5f} s'.format(end - start))

epoch: 0, Train Loss: 0.346418epoch: 1, Train Loss: 0.208787epoch: 2, Train Loss: 0.177499epoch: 3, Train Loss: 0.151950epoch: 4, Train Loss: 0.142998使用时间: 193.61232 s

x_axis = np.linspace(0, 5, len(losses1), endpoint=True)plt.semilogy(x_axis, losses1, label='batch_size=1')plt.legend(loc='best')

可以看到,loss 在剧烈震荡,因为每次都是只对一个样本点做计算,每一层的梯度都具有很高的随机性,而且需要耗费了大量的时间

# batch size=64train_data = DataLoader(train_set, batch_size=64, shuffle=True)# 使用 Sequential 定义 3 层神经网络net = nn.Sequential(nn.Linear(784, 200),nn.ReLU(),nn.Linear(200, 10),)# 开始训练losses2 = []idx = 0start = time.time() # 记时开始for e in range(5):train_loss = 0for im, label in train_data:# 前向传播out = net(im)loss = criterion(out, label)# 反向传播net.zero_grad()loss.backward()sgd_update(net.parameters(), 1e-2)# 记录误差train_loss += loss.item()if idx % 30 == 0:losses2.append(loss.item())idx += 1print('epoch: {}, Train Loss: {:.6f}'.format(e, train_loss / len(train_data)))end = time.time() # 计时结束print('使用时间: {:.5f} s'.format(end - start))

epoch: 0, Train Loss: 0.736310epoch: 1, Train Loss: 0.365898epoch: 2, Train Loss: 0.321937epoch: 3, Train Loss: 0.295115epoch: 4, Train Loss: 0.273538使用时间: 19.59853 s

x_axis = np.linspace(0, 5, len(losses2), endpoint=True)plt.semilogy(x_axis, losses2, label='batch_size=64')plt.legend(loc='best')

通过上面的结果可以看到 loss 没有batch=1震荡那么距离,同时也可以降到一定的程度了,时间上也比之前快了非常多,因为按照 batch 的数据量计算上更快,同时梯度对比于 batch size = 1 的情况也跟接近真实的梯度,所以batch size 的值越大,梯度也就越稳定,而 batch size 越小,梯度具有越高的随机性,这里 batch size 为 64,可以看到 loss 仍然存在震荡,但这并没有关系,如果 batch size 太大,对于内存的需求就更高,同时也不利于网络跳出局部极小点,所以现在普遍使用基于 batch 的随机梯度下降法,而 batch 的多少基于实际情况进行考虑。

# 调大学习率train_data = DataLoader(train_set, batch_size=64, shuffle=True)# 使用 Sequential 定义 3 层神经网络net = nn.Sequential(nn.Linear(784, 200),nn.ReLU(),nn.Linear(200, 10),)# 开始训练losses3 = []idx = 0start = time.time() # 记时开始for e in range(5):train_loss = 0for im, label in train_data:# 前向传播out = net(im)loss = criterion(out, label)# 反向传播net.zero_grad()loss.backward()sgd_update(net.parameters(), 1) # 使用 1.0 的学习率# 记录误差train_loss += loss.item()if idx % 30 == 0:losses3.append(loss.item())idx += 1print('epoch: {}, Train Loss: {:.6f}'.format(e, train_loss / len(train_data)))end = time.time() # 计时结束print('使用时间: {:.5f} s'.format(end - start))

epoch: 0, Train Loss: 2.810962epoch: 1, Train Loss: 2.305458epoch: 2, Train Loss: 2.305121epoch: 3, Train Loss: 2.305018epoch: 4, Train Loss: 2.304572使用时间: 19.39814 s

x_axis = np.linspace(0, 5, len(losses3), endpoint=True)plt.semilogy(x_axis, losses3, label='lr = 1')#semilogy 将使用 y 轴的对数刻度绘制数据。plt.legend(loc='best')

可以看到,学习率太大会使得损失函数不断回跳,从而无法让损失函数较好降低,所以我们一般都是用一个比较小的学习率

使用pytorch自带的优化器

train_data = DataLoader(train_set, batch_size=64, shuffle=True)# 使用 Sequential 定义 3 层神经网络net = nn.Sequential(nn.Linear(784, 200),nn.ReLU(),nn.Linear(200, 10),)optimzier = torch.optim.SGD(net.parameters(), 1e-2)# 开始训练start = time.time() # 记时开始for e in range(5):train_loss = 0for im, label in train_data:# 前向传播out = net(im)loss = criterion(out, label)# 反向传播optimzier.zero_grad() # net.zero_grad() 具有相同的效果loss.backward()optimzier.step() #不需要自己定义梯度更新函数# 记录误差train_loss += loss.item()print('epoch: {}, Train Loss: {:.6f}'.format(e, train_loss / len(train_data)))end = time.time() # 计时结束print('使用时间: {:.5f} s'.format(end - start))

epoch: 0, Train Loss: 0.738046epoch: 1, Train Loss: 0.365909epoch: 2, Train Loss: 0.320864epoch: 3, Train Loss: 0.294309epoch: 4, Train Loss: 0.273063使用时间: 18.67952 s

参考:PyTorch中文手册

如果觉得《深度学习(一)优化算法之随机梯度下降法(SGD)详解》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。