Pytorch入门实战:ResNet18图像分类(Cifar10)

本节需要掌握的内容:

  1. 参数初始化
    torch.nn.init中提供了多种初始化方式,可以直接对tensor进行初始化,而网络的参数是tensor的子类,所以可以直接对某一层初始化。

    1
    2
    init.xavier_uniform(self.conv1.weight) 
    init.constant(self.conv1.bias, 0.1)

    对整个网络初始化如下:

    1
    2
    3
    4
    5
    6
    def weights_init(m):
    if isinstance(m, nn.Conv2d):
    xavier(m.weight.data)
    xavier(m.bias.data)
    net = Net()
    net.apply(weights_init)
  2. 权重衰减设置

    1
    2
    3
    if epoch > 0 and epoch % 10 == 0:
    for param_group in optimizer.param_groups:
    param_group['lr'] = param_group['lr'] * lr_decay

导入需要的包

1
2
3
4
5
6
7
import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
import torchvision.transforms as transforms
import torch.optim as optim
import time

构建Residual块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1, **kwargs):
super().__init__(**kwargs)
self.residual = nn.Sequential(
nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=3, stride=stride, padding=1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(),
nn.Conv2d(in_channels=out_channels, out_channels=out_channels, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(out_channels),
)

self.identity = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.identity = nn.Sequential(
nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=stride)
)

def forward(self, x):
out = self.residual(x)
out += self.identity(x)
out = F.relu(out)
return out
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ResNet18(nn.Module):
def __init__(self, num_class=10):
super().__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(3, 64, 3, 1, 1),
nn.BatchNorm2d(64),
nn.ReLU(),
)
self.layer1 = self._make_layer(64, 64, 2)
self.layer2 = self._make_layer(64, 128, 2, 2)
self.layer3 = self._make_layer(128, 256, 2, 2)
self.layer4 = self._make_layer(256, 512, 2, 2)
self.avg_pool = nn.AvgPool2d(4)
self.linear = nn.Linear(512, num_class)

def _make_layer(self, in_channel, out_channel, bloch_num, stride=1):
blocks = []
blocks.append(ResidualBlock(in_channel, out_channel, stride))
for i in range(1, bloch_num):
blocks.append(ResidualBlock(out_channel, out_channel))
return nn.Sequential(*blocks)

def forward(self, x):
x = self.conv1(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avg_pool(x)
x = x.view(x.shape[0], -1)
return x

超参数设置,gpu or cpu

1
2
3
4
5
6
7
8
batch_size = 128
lr = 0.1
epoch_nums = 30
lr_decay = 0.5

# gpu or cpu
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type='cuda')

准备数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
transform = transforms.Compose([
transforms.Resize(40),
transforms.RandomResizedCrop(32, scale=(0.64, 1.0)),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
])

train_set = torchvision.datasets.CIFAR10(
root='./data/',
train=True,
transform=transform,
)
train_loader = torch.utils.data.DataLoader(
dataset=train_set,
batch_size=batch_size,
shuffle=True,
)

test_set = torchvision.datasets.CIFAR10(
root='./data/',
train=False,
transform=transform,
)
test_loader = torch.utils.data.DataLoader(
dataset=test_set,
batch_size=batch_size,
shuffle=False,
)

实例化网络、优化器、评估方法

1
2
3
net = ResNet18(num_class=10).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(net.parameters(), lr=lr, momentum=0.9)

开始训练

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
for epoch in range(epoch_nums):
# 每10个epoch就decay一下学习率
if epoch > 0 and epoch % 10 == 0:
for param_group in optimizer.param_groups:
param_group['lr'] = param_group['lr'] * lr_decay

loss_sum = 0
start_time = time.time()
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
loss_sum += loss.item()

with torch.no_grad():
test_acc = 0.0
total = 0

for x, y in test_loader:
x, y = x.to(device), y.to(device)
outputs = net(x)
_, predicted = torch.max(outputs.data, 1)
total += y.shape[0]
test_acc += (predicted == y).sum()

print('epoch: %d, train loss: %.03f, test acc: %.03f, time cost: %.1f sec' % (epoch + 1, loss_sum / len(train_loader), test_acc.item() / total, time.time() - start_time))
epoch: 1, train loss: 1.697, test acc: 0.504, time cost: 38.9 sec
epoch: 2, train loss: 1.198, test acc: 0.627, time cost: 39.4 sec
epoch: 3, train loss: 0.907, test acc: 0.708, time cost: 40.2 sec
epoch: 4, train loss: 0.731, test acc: 0.754, time cost: 39.3 sec
epoch: 5, train loss: 0.632, test acc: 0.781, time cost: 39.4 sec
epoch: 6, train loss: 0.562, test acc: 0.782, time cost: 39.8 sec
epoch: 7, train loss: 0.508, test acc: 0.812, time cost: 39.9 sec
epoch: 8, train loss: 0.463, test acc: 0.813, time cost: 39.9 sec
epoch: 9, train loss: 0.432, test acc: 0.831, time cost: 40.2 sec
epoch: 10, train loss: 0.396, test acc: 0.843, time cost: 40.6 sec
epoch: 11, train loss: 0.312, test acc: 0.860, time cost: 40.7 sec
epoch: 12, train loss: 0.283, test acc: 0.866, time cost: 40.8 sec
epoch: 13, train loss: 0.267, test acc: 0.870, time cost: 41.1 sec
epoch: 14, train loss: 0.252, test acc: 0.866, time cost: 41.6 sec
epoch: 15, train loss: 0.243, test acc: 0.870, time cost: 41.5 sec
epoch: 16, train loss: 0.232, test acc: 0.874, time cost: 41.2 sec
epoch: 17, train loss: 0.218, test acc: 0.876, time cost: 41.4 sec
epoch: 18, train loss: 0.206, test acc: 0.874, time cost: 40.8 sec
epoch: 19, train loss: 0.197, test acc: 0.874, time cost: 41.3 sec
epoch: 20, train loss: 0.189, test acc: 0.878, time cost: 40.9 sec
epoch: 21, train loss: 0.148, test acc: 0.892, time cost: 41.1 sec
epoch: 22, train loss: 0.130, test acc: 0.888, time cost: 41.5 sec
epoch: 23, train loss: 0.120, test acc: 0.892, time cost: 40.3 sec
epoch: 24, train loss: 0.117, test acc: 0.895, time cost: 41.5 sec
epoch: 25, train loss: 0.115, test acc: 0.893, time cost: 41.7 sec
epoch: 26, train loss: 0.109, test acc: 0.888, time cost: 41.6 sec
epoch: 27, train loss: 0.103, test acc: 0.888, time cost: 41.9 sec
epoch: 28, train loss: 0.098, test acc: 0.890, time cost: 42.6 sec
epoch: 29, train loss: 0.098, test acc: 0.891, time cost: 42.2 sec
epoch: 30, train loss: 0.094, test acc: 0.894, time cost: 40.7 sec
持续技术分享,您的支持将鼓励我继续创作!