Pytorch入门实战:迁移学习

本文将使用迁移学习训练一个分类网络。参考自pytorch tutorial。

迁移学习主要有两种方案:

  1. Finetuning the convent
    使用一个预训练的网络进行初始化(以前是随机初始化),如在imagenet上预训练的网络。

  2. ConvNet as fixed feature extractor
    将所有的卷积层参数固定,只训练后面的全连接层。

本文需要掌握的用法如下:

  1. 获取样本名称 dataset.classes

    1
    class_names = image_datasets['train'].classes
  2. torch.tensor.numpy()
    Returns self tensor as a NumPy ndarray. This tensor and the returned ndarray share the same underlying storage. Changes to self tensor will be reflected in the ndarray and vice versa.

    1
    2
    3
    4
    a = torch.tensor([1, 2])
    b = a.numpy()
    a[0] = 2
    b # [2, 2]
  3. img = np.clip(img, 0, 1) 将数据钳位

  4. tensor.double, tensor.float, tensor.int 返回转化到对应类型的tensor

  5. model.state_dict()
    Returns a dictionary containing a whole state of the module.
    Both parameters and persistent buffers (e.g. running averages) are
    included. Keys are corresponding parameter and buffer names.

  6. torch.optim.lr_scheduler
    提供了几种方法来根据epoches的数量调整学习率。包括LambdaLRStepLRMultiStepLRExponentialLRReduceLROnPlateau

    1
    2
    3
    4
    5
    scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
    for epoch in range(100):
    scheduler.step()
    train(...)
    validate(...)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import torch
import torchvision
import torchvision.transforms as transforms
import torchvision.models as models
import torch.optim as optim
import torch.nn as nn
import torchvision.datasets as datasets
import os
import torch.utils.data.dataloader as dataloader
import copy
import time
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline

plt.ion()
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
phases = ('train', 'val')

data_transforms = {
'train': transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}

data_dir = '/home/pengfei/sdb/Data/hymenoptera_data'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
data_transforms[x])
for x in phases}
image_loader = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
shuffle=True, num_workers=4)
for x in phases}
dataset_sizes = {x: len(image_datasets[x]) for x in phases}
class_names = image_datasets['train'].classes

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def imshow(img, title=None):
img = img.numpy().transpose((1, 2, 0))
mean = np.array([0.485, 0.456, 0.406])
std = np.array([0.229, 0.224, 0.225])
img = std * img + mean
img = np.clip(img, 0, 1)
plt.imshow(img)
if title is not None:
plt.title(title)
plt.pause(0.001)

inputs, classes = next(iter(image_loader['train']))
out = torchvision.utils.make_grid(inputs)
imshow(out, title=[class_names[x] for x in classes])

图片

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def train(model, optimizer, criterion, scheduler, epoch_num=20):
start_time = time.time()
best_moudle_param = copy.deepcopy(model.state_dict())
best_acc = 0.0

for epoch in range(epoch_num):
print('Epoch {}/{}'.format(epoch, epoch_num-1))
print('-' * 10)

for phase in phases:
if phase == 'train':
scheduler.step()
model.train()
else:
model.eval()

running_loss = 0.0
running_correct = 0

for inputs, targets in image_loader[phase]:
inputs, targets = inputs.to(device), targets.to(device)

optimizer.zero_grad()
with torch.set_grad_enabled(phase == 'train'):
outputs = model(inputs)
loss = criterion(outputs, targets)
_, predicted = torch.max(outputs, 1)

if phase == 'train':
loss.backward()
optimizer.step()

running_loss += loss.item() * inputs.shape[0]
running_correct += (predicted == targets).sum()

epoch_loss = running_loss / dataset_sizes[phase]
epoch_acc = running_correct.double() / dataset_sizes[phase]

print('{} Loss: {:.4f}, Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))

if phase == 'val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_moudle_param = copy.deepcopy(model.state_dict())

time_cost = time.time() - start_time
print('Traing complete in {:.0f}m {:.0f}s'.format(
time_cost // 60, time_cost % 60
))
print('Best val Acc: {:.4f}'.format(best_acc))

model.load_state_dict(best_moudle_param)
return model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def visualize_predict(model, num_images=6):
was_training = model.training
model.eval()
images_so_far = 0
fig = plt.figure()

with torch.no_grad():
for i, (inputs, labels) in enumerate(image_loader['val']):
inputs = inputs.to(device)
labels = labels.to(device)

outputs = model(inputs)
_, predicted = torch.max(outputs, 1)

for j in range(inputs.size()[0]):
images_so_far += 1
ax = plt.subplot(num_images // 2, 2, images_so_far)
ax.axis('off')
ax.set_title('predicted: {}'.format(class_names[predicted[j]]))
imshow(inputs.cpu().data[j])

if images_so_far == num_images:
model.train(mode=was_training)
return
1
2
3
4
5
6
model_ft = models.resnet18(pretrained=True)
model_ft.fc = nn.Linear(model_ft.fc.in_features, 2)
model_ft = model_ft.to(device)
criterion = nn.CrossEntropyLoss()
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
1
model_ft = train(model_ft, optimizer_ft, criterion, exp_lr_scheduler)
Epoch 0/19
----------
train Loss: 0.6718, Acc: 0.6762
val Loss: 0.2909, Acc: 0.8758
Epoch 1/19
----------
train Loss: 0.4903, Acc: 0.7664
val Loss: 0.2409, Acc: 0.8824
Epoch 2/19
----------
train Loss: 0.4883, Acc: 0.8074
val Loss: 0.4210, Acc: 0.8301
Epoch 3/19
----------
train Loss: 0.6792, Acc: 0.7008
val Loss: 0.3024, Acc: 0.8758
Epoch 4/19
----------
train Loss: 0.4854, Acc: 0.7951
val Loss: 0.5967, Acc: 0.8105
Epoch 5/19
----------
train Loss: 0.6275, Acc: 0.7951
val Loss: 0.2365, Acc: 0.9150
Epoch 6/19
----------
train Loss: 0.7099, Acc: 0.7582
val Loss: 0.4348, Acc: 0.8758
Epoch 7/19
----------
train Loss: 0.3858, Acc: 0.8730
val Loss: 0.2605, Acc: 0.9216
Epoch 8/19
----------
train Loss: 0.3358, Acc: 0.8607
val Loss: 0.2593, Acc: 0.9281
Epoch 9/19
----------
train Loss: 0.3761, Acc: 0.8361
val Loss: 0.2400, Acc: 0.9150
Epoch 10/19
----------
train Loss: 0.3718, Acc: 0.8525
val Loss: 0.2041, Acc: 0.9346
Epoch 11/19
----------
train Loss: 0.3000, Acc: 0.8811
val Loss: 0.1988, Acc: 0.9346
Epoch 12/19
----------
train Loss: 0.4123, Acc: 0.8484
val Loss: 0.2236, Acc: 0.9150
Epoch 13/19
----------
train Loss: 0.2699, Acc: 0.9057
val Loss: 0.1881, Acc: 0.9477
Epoch 14/19
----------
train Loss: 0.3591, Acc: 0.8648
val Loss: 0.1844, Acc: 0.9412
Epoch 15/19
----------
train Loss: 0.2312, Acc: 0.9180
val Loss: 0.2003, Acc: 0.9281
Epoch 16/19
----------
train Loss: 0.2395, Acc: 0.8852
val Loss: 0.3438, Acc: 0.8824
Epoch 17/19
----------
train Loss: 0.2238, Acc: 0.9139
val Loss: 0.2004, Acc: 0.9216
Epoch 18/19
----------
train Loss: 0.2948, Acc: 0.8730
val Loss: 0.1862, Acc: 0.9346
Epoch 19/19
----------
train Loss: 0.2991, Acc: 0.8648
val Loss: 0.2627, Acc: 0.9216
Traing complete in 0m 32s
Best val Acc: 0.9477
1
visualize_predict(model_ft)

图片

1
2
3
4
5
6
7
8
9
model_conv = torchvision.models.resnet18(pretrained=True)
for param in model_conv.parameters():
param.requires_grad = False

model_conv.fc = nn.Linear(model_conv.fc.in_features, 2)
model_conv = model_conv.to(device)
criterion = nn.CrossEntropyLoss()
optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.001, momentum=0.9)
exp_lr_scheduler = optim.lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)
1
model_conv = train(model_conv, optimizer_conv, criterion, exp_lr_scheduler)
Epoch 0/19
----------
train Loss: 0.7631, Acc: 0.5615
val Loss: 0.2695, Acc: 0.9020
Epoch 1/19
----------
train Loss: 0.7224, Acc: 0.7254
val Loss: 0.3596, Acc: 0.8758
Epoch 2/19
----------
train Loss: 0.3871, Acc: 0.8361
val Loss: 0.1821, Acc: 0.9346
Epoch 3/19
----------
train Loss: 0.3875, Acc: 0.8115
val Loss: 0.1709, Acc: 0.9542
Epoch 4/19
----------
train Loss: 0.4280, Acc: 0.7787
val Loss: 0.2612, Acc: 0.8954
Epoch 5/19
----------
train Loss: 0.3769, Acc: 0.8525
val Loss: 0.1932, Acc: 0.9477
Epoch 6/19
----------
train Loss: 0.5753, Acc: 0.7705
val Loss: 0.3275, Acc: 0.8889
Epoch 7/19
----------
train Loss: 0.3103, Acc: 0.8730
val Loss: 0.1959, Acc: 0.9346
Epoch 8/19
----------
train Loss: 0.3225, Acc: 0.8566
val Loss: 0.1967, Acc: 0.9477
Epoch 9/19
----------
train Loss: 0.4565, Acc: 0.7992
val Loss: 0.2357, Acc: 0.9216
Epoch 10/19
----------
train Loss: 0.3099, Acc: 0.8648
val Loss: 0.1959, Acc: 0.9477
Epoch 11/19
----------
train Loss: 0.3562, Acc: 0.8443
val Loss: 0.2094, Acc: 0.9216
Epoch 12/19
----------
train Loss: 0.3817, Acc: 0.8320
val Loss: 0.2029, Acc: 0.9216
Epoch 13/19
----------
train Loss: 0.2989, Acc: 0.8689
val Loss: 0.2207, Acc: 0.9216
Epoch 14/19
----------
train Loss: 0.3139, Acc: 0.8770
val Loss: 0.2097, Acc: 0.9412
Epoch 15/19
----------
train Loss: 0.3140, Acc: 0.8566
val Loss: 0.2014, Acc: 0.9281
Epoch 16/19
----------
train Loss: 0.3595, Acc: 0.8238
val Loss: 0.1981, Acc: 0.9346
Epoch 17/19
----------
train Loss: 0.3495, Acc: 0.8484
val Loss: 0.2064, Acc: 0.9150
Epoch 18/19
----------
train Loss: 0.3043, Acc: 0.8525
val Loss: 0.2191, Acc: 0.9216
Epoch 19/19
----------
train Loss: 0.3634, Acc: 0.8402
val Loss: 0.1821, Acc: 0.9477
Traing complete in 0m 22s
Best val Acc: 0.9542
1
2
3
visualize_predict(model_conv)
plt.ioff()
plt.show()

图片

持续技术分享,您的支持将鼓励我继续创作!