CNN训练样例(单个batch)

2019-08-04  本文已影响0人  钢笔先生

Time: 2019-08-04
链接:https://youtu.be/0VCOG8IeVf8?list=PLZbbT5o_s2xrfNyHZsM6ufI0iZENK9xgG

训练神经网络的7个步骤

  1. 从训练集中获取batch
  2. 将batch传递到网络
  3. 计算损失函数(网络输出值与真实值之间差异) -- Loss
  4. 计算损失函数相对于权重的梯度 -- BP算法
  5. 使用梯度更新权重降低损失 -- Optimizer
  6. 重复1-5,直到该epoch完成
  7. 重复1-6,用尽可能多的epoch直到比较好的准确度达成

Epoch:一次完全遍历训练样本的过程。

完整的网络以及数据加载代码

import torch 
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

import torchvision
import torchvision.transforms as transforms

torch.set_printoptions(linewidth=120)
torch.set_grad_enabled(True) # 默认值,参数可更新

def get_num_correct(preds, labels):
  return preds.argmax(dim=1).eq(labels).sum()

# 构建网络
class Network(nn.Module):
    def __init__(self):
        super(Network, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)

        self.fc1 = nn.Linear(in_features=12*4*4, out_features=120)
        self.fc2 = nn.Linear(in_features=120, out_features=60)
        self.out = nn.Linear(in_features=60, out_features=10)
    
    def forward(self, t):
        t = F.relu(self.conv1(t))
        t = F.max_pool2d(t, kernel_size=2, stride=2)

        t = F.relu(self.conv2 (t))
        t = F.max_pool2d(t, kernel_size=2, stride=2)

        t = F.relu(self.fc1(t.reshape(-1, 12*4*4)))
        t = F.relu(self.fc2(t))
        t = self.out(t)

        return t

# 准备数据集
train_set = torchvision.datasets.FashionMNIST(
    root='./data/FashionMNIST',
    download=True,
    train=True,
    transform=transforms.Compose([
        transforms.ToTensor()
    ])
)

# 实例化网络
network = Network()

# 数据加载器,准备batch
train_data_loader = torch.utils.data.DataLoader(train_set, batch_size=100)
batch = next(iter(train_data_loader))
images, labels = batch

images.shape # torch.Size([100, 1, 28, 28])

计算损失函数,梯度,更新参数的过程

# Loss: 
preds = network(images)
loss = F.cross_entropy(preds, labels)

# Gradients
loss.backward() # 计算梯度

print(network.conv1.weight.grad) # 打印梯度
print(network.conv1.weight.grad.shape) # 梯度形状

# Optimizer用于更新参数,决定了更新的方式
optimizer = optim.Adam(network.parameters(), lr=0.01)
loss.item() # 2.308018684387207
# 更新参数
optimizer.step()
preds = network(images)
loss = F.cross_entropy(preds, labels)
loss.item() # 2.277029275894165

一个完整的batch训练样例

network = Network()

train_loader = torch.utils.data.DataLoader(train_set, batch_size=100)
optimizer = optim.Adam(network.parameters(), lr=0.01)

batch = next(iter(train_loader)) # 获取batch
images, labels = batch

preds = network(images) # 传入一个batch
loss = F.cross_entropy(preds, labels) # 计算损失函数

loss.backward() # 计算梯度
optimizer.step() # 一个批次更新参数

#------------------
print("loss1: ", loss.item()) # loss是个标量

preds = network(images) # 用新的参数再计算一下网络输出
loss = F.cross_entropy(preds, labels)

print("loss2: ", loss.item())

总结

PyTorch的流程设计是我用过的几个框架中最Pythonic的,也是最清晰,最好用的。

每个阶段要做的事情极为清晰,使得每个概念的落地也非常自然,多写几遍demo就能感受到整个深度学习流程。

torch.nntorch.nn.functional的分离,前者是用于设定可更新参数的函数,后者则是不含参数更新的功能性的函数,乍一看不是很清晰为啥还分了两个,用起来才发现,这个设计真的好极了。

优化器的设定中,第一个参数是网络的参数,这个很自然,因为优化的目标就是网络的可学习参数,其次还可以设定关于优化器的超参数,还有优化器本身就有很多类别,这是更高一层的超参数选择问题。

END.

上一篇下一篇

猜你喜欢

热点阅读