pytorch学习:梯度下降代码

本文通过实验对比不同批量大小对神经网络训练的影响,展示了如何使用随机梯度下降(SGD)优化器来提高手写数字识别模型的训练效率。
# -*- coding: utf-8 -*-
"""
Created on Sun Sep  2 15:54:06 2018

@author: www
"""

import numpy as np
import torch
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader
from torch import nn
from torch.autograd import Variable
import time
import matplotlib.pyplot as plt

def get_data(x):
     x = np.array(x, dtype='float32')/255
     x = (x-0.5) / 0.5  #标准化
     x = x.reshape((-1,)) #拉平
     x = torch.from_numpy(x)
     return x

train_set = MNIST('./data', train=True, transform=get_data, download=True) # 载入数据集,申明定义的数据变换
test_set = MNIST('./data', train=False, transform=get_data, download=True)     

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

#自定义随机梯度下降
def sgd_update(parameters, lr):
     for param in parameters:
          param.data = param.data - lr * param.grad.data
          
#现将batch_size设置为1.看看有什么效果
train_data = DataLoader(train_set, batch_size=1, shuffle=True)
#使用Sequential定义神经网络
net = nn.Sequential(
     nn.Linear(784,200),
     nn.ReLU(),
     nn.Linear(200, 10),
)
#开始训练
losses1 = []
idx = 0
start = time.time()
for e in range(5):
     train_loss = 0
     for im, label in train_data:
          im = Variable(im)
          label = Variable(label)
          #前向传播
          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:
               losses1.append(loss.item())
          idx += 1
     print('epoch:{},Train Loss:{}'.format(e, train_loss/len(train_data)))
end = time.time()
print('Time={}'.format(end - start))

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改成64
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),
)

# 开始训练
losses2 = []
idx = 0
start = time.time() # 记时开始
for e in range(5):
    train_loss = 0
    for im, label in train_data:
        im = Variable(im)
        label = Variable(label)
        # 前向传播
        out = net(im)
        loss = criterion(out, label)
        # 反向传播
        net.zero_grad()
        loss.backward()
        sgd_update(net.parameters(), 1e-2)
        # 记录误差
        train_loss += loss.data[0]
        if idx % 30 == 0:
            losses2.append(loss.data[0])
        idx += 1
    print('epoch: {}, Train Loss: {:.6f}'
          .format(e, train_loss / len(train_data)))
end = time.time() # 计时结束
print('使用时间: {:.5f} s'.format(end - start))      
          
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),
)

optimzier = torch.optim.SGD(net.parameters(), 1e-2)
# 开始训练

#下面我们来使用 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 = 0
    for im, label in train_data:
        im = Variable(im)
        label = Variable(label)
        # 前向传播
        out = net(im)
        loss = criterion(out, label)
        # 反向传播
        optimzier.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))



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值