• pytorch例子学习——TRANSFER LEARNING TUTORIAL


    参考:https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html

    以下是两种主要的迁移学习场景

    • 微调convnet : 与随机初始化不同,我们使用一个预训练的网络初始化网络,就像在imagenet 1000 dataset上训练的网络一样。其余的训练看起来和往常一样。
    • 将ConvNet作为固定的特征提取器 : 在这里,我们将冻结所有网络的权重,除了最后的全连接层。最后一个完全连接的层被替换为一个具有随机权重的新层,并且只训练这个层。

    一开始先导入需要的包:

    # License: BSD
    # Author: Sasank Chilamkurthy
    
    from __future__ import print_function, division
    
    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torch.optim import lr_scheduler
    import numpy as np
    import torchvision
    from torchvision import datasets, models, transforms
    import matplotlib.pyplot as plt
    import time
    import os
    import copy
    
    plt.ion()   # 交互模式

    1)下载数据

    将会使用torchvision和torch.utils.data包去下载数据

    今天我们 要解决的问题是建立一个模型去分类蚂蚁和蜜蜂。对于蚂蚁和蜜蜂,我们分别有大约120张训练图片。对于每个类有75张验证图像。通常,如果从零开始训练,这是一个非常小的数据集。由于使用了迁移学习,我们应该能够很好地概括。

    这个数据集是imagenet的一个非常小的子集。

     ⚠️从 here下载数据集,并将其从当前目录中抽取出来

    # 为训练对数据进行扩充和规范化,其实就是通过剪切,翻转等方法来扩充数据集的大小
    # 验证只进行规范化
    data_transforms = {
        'train': transforms.Compose([ #将多个transform组合起来使用
            transforms.RandomResizedCrop(224), #将给定的图片随机切,然后再resize成给定的size=224大小
            transforms.RandomHorizontalFlip(), #图片有一半概率进行翻转,另一半概率不翻转
            transforms.ToTensor(), #将图片的像素值[0,255]转成取值范围为[0,1]的tensor
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) #两个参数分别代表均值mean和方差std,有三个值是对应三类像素image=[R,G,B],Normalized_image=(image-mean)/std
        ]),
        'val': transforms.Compose([
            transforms.Resize(256), #改变大小
            transforms.CenterCrop(224), #进行中心切割,得到给定的size,切出来的图形形状是正方形的
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
    }
    
    data_dir = './data/hymenoptera_data'
    image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),data_transforms[x]) for x in ['train', 'val']}
    dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,shuffle=True, num_workers=4) for x in ['train', 'val']}
    dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'val']}
    class_names = image_datasets['train'].classes
    
    #如果有CUDA则使用它,否则使用CPU
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    2)可视化一些图像

    让我们可视化一些训练图像,以便理解数据扩充。

    def imshow(inp, title=None):
        """Imshow for Tensor."""
        inp = inp.numpy().transpose((1, 2, 0))
        mean = np.array([0.485, 0.456, 0.406])
        std = np.array([0.229, 0.224, 0.225])
        inp = std * inp + mean
        inp = np.clip(inp, 0, 1)
        plt.imshow(inp)
        if title is not None:
            plt.title(title)
        plt.pause(0.001)  # 暂停一下,以便更新绘图
    
    
    # 获得一批训练数据
    inputs, classes = next(iter(dataloaders['train']))
    
    # Make a grid from batch
    out = torchvision.utils.make_grid(inputs)
    
    imshow(out, title=[class_names[x] for x in classes])

    运行到这里的时候就会显示如下图所示的图像:

    3)训练模型

    现在,让我们编写一个通用函数来训练模型。在这里,我们将举例说明:

    • 调度学习比率
    • 保存最佳模型

    在下面,变量scheduler是一个来自torch.optim.lr_scheduler的LR调度对象,

    def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
        since = time.time()
    
        best_model_wts = copy.deepcopy(model.state_dict())
        best_acc = 0.0
    
        for epoch in range(num_epochs):
            print('Epoch {}/{}'.format(epoch, num_epochs - 1))
            print('-' * 10)
    
            # 每个周期都有一个训练和验证阶段
            for phase in ['train', 'val']:
                if phase == 'train':
                    scheduler.step()
                    model.train()  # 设置模型为训练模式
                else:
                    model.eval()   # 设置模型为评估模式
    
                running_loss = 0.0
                running_corrects = 0
    
                #迭代数据
                for inputs, labels in dataloaders[phase]:
                    inputs = inputs.to(device)
                    labels = labels.to(device)
    
                    # zero the parameter gradients
                    optimizer.zero_grad()
    
                    # forward
                    # 如果只是在训练要追踪历史
                    with torch.set_grad_enabled(phase == 'train'):
                        outputs = model(inputs)
                        _, preds = torch.max(outputs, 1)
                        loss = criterion(outputs, labels)
    
                        # backward + optimize ,仅在训练阶段
                        if phase == 'train':
                            loss.backward()
                            optimizer.step()
    
                    # statistics
                    running_loss += loss.item() * inputs.size(0)
                    running_corrects += torch.sum(preds == labels.data)
    
                epoch_loss = running_loss / dataset_sizes[phase]
                epoch_acc = running_corrects.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_model_wts = copy.deepcopy(model.state_dict())
    
            print()
    
        time_elapsed = time.time() - since
        print('Training complete in {:.0f}m {:.0f}s'.format(
            time_elapsed // 60, time_elapsed % 60))
        print('Best val Acc: {:4f}'.format(best_acc))
    
        # 下载最好的模型权重
        model.load_state_dict(best_model_wts)
        return model

    4)可视化模型预测

    泛型函数,显示对一些图像的预测

    def visualize_model(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(dataloaders['val']):
                inputs = inputs.to(device)
                labels = labels.to(device)
    
                outputs = model(inputs)
                _, preds = 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[preds[j]]))
                    imshow(inputs.cpu().data[j])
    
                    if images_so_far == num_images:
                        model.train(mode=was_training)
                        return
            model.train(mode=was_training)

    5)

    1》微调convent

    下载预训练模型并重新设置最后的全连接层

    model_ft = models.resnet18(pretrained=True)
    num_ftrs = model_ft.fc.in_features
    model_ft.fc = nn.Linear(num_ftrs, 2)
    
    model_ft = model_ft.to(device)
    
    criterion = nn.CrossEntropyLoss()
    
    # 观察到所有参数都被优化
    optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)
    
    # 每7个周期,LR衰减0.1倍
    exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

    2》训练和评估

    CPU可能会使用15-25分钟。如果使用的是GPU,将花费少于一分钟

    model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,
                           num_epochs=25)

    ⚠️使用的python2.7,如果使用的是python3则会报错:

    (deeplearning) userdeMBP:neural transfer user$ python neural_style_tutorial.py 
    2019-03-13 19:30:06.194 python[4926:206321] -[NSApplication _setup:]: unrecognized selector sent to instance 0x7f8eb4895080
    2019-03-13 19:30:06.199 python[4926:206321] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSApplication _setup:]: unrecognized selector sent to instance 0x7f8eb4895080'

    终端运行:(我是在CPU上运行的)

    (deeplearning2) userdeMBP:transfer learning user$ python transfer_learning_tutorial.py 
    Downloading: "https://download.pytorch.org/models/resnet18-5c106cde.pth" to /Users/user/.torch/models/resnet18-5c106cde.pth
    100.0%
    Epoch 0/24
    ----------
    train Loss: 0.5703 Acc: 0.7049
    val Loss: 0.2565 Acc: 0.9020
    
    Epoch 1/24
    ----------
    train Loss: 0.6009 Acc: 0.7951
    val Loss: 0.3604 Acc: 0.8627
    
    Epoch 2/24
    ----------
    train Loss: 0.5190 Acc: 0.7869
    val Loss: 0.4421 Acc: 0.8105
    
    Epoch 3/24
    ----------
    train Loss: 0.5072 Acc: 0.7910
    val Loss: 0.4037 Acc: 0.8431
    
    Epoch 4/24
    ----------
    train Loss: 0.6503 Acc: 0.7869
    val Loss: 0.2961 Acc: 0.9085
    
    Epoch 5/24
    ----------
    train Loss: 0.3840 Acc: 0.8730
    val Loss: 0.2648 Acc: 0.8954
    
    Epoch 6/24
    ----------
    train Loss: 0.6137 Acc: 0.7705
    val Loss: 0.6852 Acc: 0.8170
    
    Epoch 7/24
    ----------
    train Loss: 0.4130 Acc: 0.8279
    val Loss: 0.3730 Acc: 0.8954
    
    Epoch 8/24
    ----------
    train Loss: 0.3953 Acc: 0.8648
    val Loss: 0.3300 Acc: 0.9216
    
    Epoch 9/24
    ----------
    train Loss: 0.2753 Acc: 0.8934
    val Loss: 0.2949 Acc: 0.9020
    
    Epoch 10/24
    ----------
    train Loss: 0.3192 Acc: 0.8648
    val Loss: 0.2984 Acc: 0.9020
    
    Epoch 11/24
    ----------
    train Loss: 0.2942 Acc: 0.8852
    val Loss: 0.2624 Acc: 0.9150
    
    Epoch 12/24
    ----------
    train Loss: 0.2738 Acc: 0.8811
    val Loss: 0.2855 Acc: 0.9020
    
    Epoch 13/24
    ----------
    train Loss: 0.2697 Acc: 0.8648
    val Loss: 0.2675 Acc: 0.9020
    
    Epoch 14/24
    ----------
    train Loss: 0.2534 Acc: 0.9016
    val Loss: 0.2780 Acc: 0.9085
    
    Epoch 15/24
    ----------
    train Loss: 0.2514 Acc: 0.8811
    val Loss: 0.2873 Acc: 0.9020
    
    Epoch 16/24
    ----------
    train Loss: 0.2430 Acc: 0.9098
    val Loss: 0.2901 Acc: 0.9085
    
    Epoch 17/24
    ----------
    train Loss: 0.2970 Acc: 0.8402
    val Loss: 0.2570 Acc: 0.9150
    
    Epoch 18/24
    ----------
    train Loss: 0.2779 Acc: 0.8934
    val Loss: 0.2792 Acc: 0.9085
    
    Epoch 19/24
    ----------
    
    train Loss: 0.2271 Acc: 0.9262
    val Loss: 0.2655 Acc: 0.9150
    
    Epoch 20/24
    ----------
    train Loss: 0.2741 Acc: 0.8975
    val Loss: 0.2726 Acc: 0.9085
    
    Epoch 21/24
    ----------
    train Loss: 0.3221 Acc: 0.8320
    val Loss: 0.2738 Acc: 0.9150
    
    Epoch 22/24
    ----------
    train Loss: 0.2228 Acc: 0.9139
    val Loss: 0.2712 Acc: 0.9020
    
    Epoch 23/24
    ----------
    train Loss: 0.2881 Acc: 0.8975
    val Loss: 0.2565 Acc: 0.9150
    
    Epoch 24/24
    ----------
    train Loss: 0.3219 Acc: 0.8648
    val Loss: 0.2669 Acc: 0.9150
    
    Training complete in 16m 22s
    Best val Acc: 0.921569

    实现可视化:

    visualize_model(model_ft)

    第一次返回图像为:

    6)

    1》将ConvNet作为固定的特征提取器

    这里我们需要将除了最后一层的所有网络冻结。我们需要设置requires_grad == False去冻结参数以便梯度在backward()中不会被计算

    我们可以从here读取更详细的内容

    model_conv = torchvision.models.resnet18(pretrained=True)
    for param in model_conv.parameters():
        param.requires_grad = False
    
    # 最新构造函数的参数默认设置requires_grad=True
    num_ftrs = model_conv.fc.in_features
    model_conv.fc = nn.Linear(num_ftrs, 2)
    
    model_conv = model_conv.to(device)
    
    criterion = nn.CrossEntropyLoss()
    
    # 观察到与之前相比,只有最后一层的参数被优化
    optimizer_conv = optim.SGD(model_conv.fc.parameters(), lr=0.001, momentum=0.9)
    
    # 每7个周期,LR衰减0.1倍
    exp_lr_scheduler = lr_scheduler.StepLR(optimizer_conv, step_size=7, gamma=0.1)

    2》训练和评估

    在CPU上,与之前的场景相比,这将只花费大约其一半的时间。因为这预期了对于大部分网络梯度不需要计算。当然forward还是需要计算的

    model_conv = train_model(model_conv, criterion, optimizer_conv,
                             exp_lr_scheduler, num_epochs=25)

    接下来继续训练:(我是在CPU上运行的)

    Epoch 0/24
    ----------
    train Loss: 0.6719 Acc: 0.6516
    val Loss: 0.2252 Acc: 0.9281
    
    Epoch 1/24
    ----------
    train Loss: 0.6582 Acc: 0.7254
    val Loss: 0.4919 Acc: 0.7778
    
    Epoch 2/24
    ----------
    train Loss: 0.5313 Acc: 0.8115
    val Loss: 0.2488 Acc: 0.9085
    
    Epoch 3/24
    ----------
    train Loss: 0.5134 Acc: 0.7623
    val Loss: 0.1881 Acc: 0.9412
    
    Epoch 4/24
    ----------
    train Loss: 0.3834 Acc: 0.8525
    val Loss: 0.2220 Acc: 0.9085
    
    Epoch 5/24
    ----------
    train Loss: 0.5442 Acc: 0.7910
    val Loss: 0.2865 Acc: 0.8954
    
    Epoch 6/24
    ----------
    train Loss: 0.6136 Acc: 0.7213
    val Loss: 0.2915 Acc: 0.9085
    
    Epoch 7/24
    ----------
    train Loss: 0.3393 Acc: 0.8730
    val Loss: 0.1839 Acc: 0.9542
    
    Epoch 8/24
    ----------
    train Loss: 0.3616 Acc: 0.8156
    val Loss: 0.1967 Acc: 0.9346
    
    Epoch 9/24
    ----------
    train Loss: 0.3798 Acc: 0.8402
    val Loss: 0.1903 Acc: 0.9542
    
    Epoch 10/24
    ----------
    train Loss: 0.3918 Acc: 0.8320
    val Loss: 0.1860 Acc: 0.9477
    
    Epoch 11/24
    ----------
    train Loss: 0.3950 Acc: 0.8115
    val Loss: 0.1803 Acc: 0.9542
    
    Epoch 12/24
    ----------
    train Loss: 0.3094 Acc: 0.8566
    val Loss: 0.1978 Acc: 0.9542
    
    Epoch 13/24
    ----------
    train Loss: 0.2791 Acc: 0.8811
    val Loss: 0.1932 Acc: 0.9542
    
    Epoch 14/24
    ----------
    train Loss: 0.3797 Acc: 0.8484
    val Loss: 0.2318 Acc: 0.9346
    
    Epoch 15/24
    ----------
    train Loss: 0.3456 Acc: 0.8689
    val Loss: 0.1965 Acc: 0.9412
    
    Epoch 16/24
    ----------
    train Loss: 0.4585 Acc: 0.7910
    val Loss: 0.2264 Acc: 0.9346
    
    Epoch 17/24
    ----------
    train Loss: 0.3889 Acc: 0.8566
    val Loss: 0.1847 Acc: 0.9477
    
    Epoch 18/24
    ----------
    train Loss: 0.3636 Acc: 0.8361
    val Loss: 0.2680 Acc: 0.9346
    
    Epoch 19/24
    ----------
    train Loss: 0.2616 Acc: 0.8730
    val Loss: 0.1892 Acc: 0.9477
    
    Epoch 20/24
    ----------
    train Loss: 0.3114 Acc: 0.8648
    val Loss: 0.2295 Acc: 0.9346
    
    Epoch 21/24
    ----------
    train Loss: 0.3597 Acc: 0.8443
    val Loss: 0.1857 Acc: 0.9477
    
    Epoch 22/24
    ----------
    train Loss: 0.3794 Acc: 0.8402
    val Loss: 0.1822 Acc: 0.9477
    
    Epoch 23/24
    ----------
    train Loss: 0.3553 Acc: 0.8279
    val Loss: 0.1992 Acc: 0.9608
    
    Epoch 24/24
    ----------
    train Loss: 0.3514 Acc: 0.8238
    val Loss: 0.2144 Acc: 0.9346
    
    Training complete in 13m 33s
    Best val Acc: 0.960784

    实现可视化:

    visualize_model(model_conv)
    
    plt.ioff()
    plt.show()

    返回图像为:

  • 相关阅读:
    你的课程
    asp.net的ajax以及json
    asp.net自带的异步刷新控件使用
    基于.net mvc的校友录(源程序)
    基于.net mvc的校友录(七、文件上传以及多对多关系表的LINQ查询实现)
    基于.net mvc的校友录(六、codefirst的使用以及班级模块的关键部分实现)
    逻辑回归实例
    层次聚类
    k均值聚类
    数据处理与转换
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/10544682.html
Copyright © 2020-2023  润新知