• Pytorch 分类网络训练方法(Resnet152为例)


    Pytorch resnet 分类网络训练方法

    conda环境安装与配置

    新建conda环境并激活

    conda create --name pytorch170_py3_7 python=3.7
    conda activate pytorch170_py3_7
    
    • 1
    • 2

    配置

    官网上面找与本机cuda对应的版本安装

    1. 选择合适的版本安装
    # CUDA 10.1
    conda install pytorch==1.7.0 torchvision==0.8.0 torchaudio==0.7.0 cudatoolkit=10.1 -c pytorch
    
    # CPU Only
    conda install pytorch==1.7.0 torchvision==0.8.0 cpuonly -c pytorch
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 检测环境是否成功
    python  
    import torch  
    print(torch.__version__)            //查看pytorch版本
    print(torch.version.cuda)           //查看cuda版本
    print(torch.cuda.is_available())    //验证cuda是否可用
    
    • 1
    • 2
    • 3
    • 4
    • 5

    准备数据集

    1. 在训练数据目录下新建 train 和 val 两个文件夹

    2. 在train文件夹下新建 各个分类文件夹。如:class1,class2,class3,class4

    3. 在val文件夹下同样如此

    4. 将不同分类的图片放到个子文件夹里面

    #最终文件结构为
    -数据集根目录:
    ----------------train:
    ----------------------class1
    ----------------------class2
    ----------------------class3
    ----------------------class4
    ----------------val:
    ----------------------class1
    ----------------------class2
    ----------------------class3
    ----------------------class4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    训练

    修改训练脚本

    from __future__ import print_function 
    from __future__ import division
    import torch
    import torch.nn as nn
    import torch.optim as optim
    import numpy as np
    import torchvision
    from torchvision import datasets, models, transforms
    import matplotlib.pyplot as plt
    import time
    import os
    import copy
    
    #训练数据目录
    data_dir = "./DataSets"
    
    # 选择训练网络 [resnet, alexnet, vgg, squeezenet, densenet, inception]
    model_name = "resnet"
    
    #权重文件输出目录及名称
    output_path="./resnet152.pth"
    
    #学习率
    lr_rate=0.001
    
    # 种类数目
    num_classes = 4
    
    # Batch Size取决你电脑内存大小
    batch_size = 8
    
    # 训练次数 
    num_epochs = 500
    
    # False时候更新所有参数,True时候只更新最后一层的参数
    feature_extract = False
    
    
    def train_model(model, dataloaders, criterion, optimizer, num_epochs=25, is_inception=False):
        since = time.time()
    
        val_acc_history = []
        val_loss_history=[]
        
        train_acc_history = []
        train_loss_history=[]
        
        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)
    
            # Each epoch has a training and validation phase
            for phase in ['train', 'val']:
                if phase == 'train':
                    model.train()  # Set model to training mode
                else:
                    model.eval()   # Set model to evaluate mode
    
                running_loss = 0.0
                running_corrects = 0
    
                # Iterate over data.
                for inputs, labels in dataloaders[phase]:
                    inputs = inputs.to(device)
                    labels = labels.to(device)
                    
                    # zero the parameter gradients
                    optimizer.zero_grad()
    
                    # forward
                    # track history if only in train
                    with torch.set_grad_enabled(phase == 'train'):
                        # Get model outputs and calculate loss
                        # Special case for inception because in training it has an auxiliary output. In train
                        #   mode we calculate the loss by summing the final output and the auxiliary output
                        #   but in testing we only consider the final output.
                        if is_inception and phase == 'train':
                            # From https://discuss.pytorch.org/t/how-to-optimize-inception-model-with-auxiliary-classifiers/7958
                            outputs, aux_outputs = model(inputs)
                            loss1 = criterion(outputs, labels)
                            loss2 = criterion(aux_outputs, labels)
                            loss = loss1 + 0.4*loss2
                        else:
                            outputs = model(inputs)
                            loss = criterion(outputs, labels)
    
                        _, preds = torch.max(outputs, 1)
    
                        # backward + optimize only if in training phase
                        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 / len(dataloaders[phase].dataset)
                epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
    
                print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
    
                # deep copy the model
                if phase == 'val' and epoch_acc > best_acc:
                    best_acc = epoch_acc
                    best_model_wts = copy.deepcopy(model.state_dict())
                    
                if phase == 'train':
                    train_acc_history.append(epoch_acc)
                    train_loss_history.append(epoch_loss) 
                else:
                    val_acc_history.append(epoch_acc)
                    val_loss_history.append(epoch_loss)          
    
            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))
    
        # load best model weights
        model.load_state_dict(best_model_wts)
        return model, train_acc_history,train_loss_history,val_acc_history,val_loss_history
    
    
    
    def set_parameter_requires_grad(model, feature_extracting):
        if feature_extracting:
            for param in model.parameters():
                param.requires_grad = False
    
    
    
    def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):
        # Initialize these variables which will be set in this if statement. Each of these
        #   variables is model specific.
        model_ft = None
        input_size = 0
    
        if model_name == "resnet":
            """ Resnet152
            """
            model_ft = models.resnet152(pretrained=use_pretrained)
            set_parameter_requires_grad(model_ft, feature_extract)
            num_ftrs = model_ft.fc.in_features
            model_ft.fc = nn.Linear(num_ftrs, num_classes)
            input_size = 480 #224
    
        elif model_name == "alexnet":
            """ Alexnet
            """
            model_ft = models.alexnet(pretrained=use_pretrained)
            set_parameter_requires_grad(model_ft, feature_extract)
            num_ftrs = model_ft.classifier[6].in_features
            model_ft.classifier[6] = nn.Linear(num_ftrs,num_classes)
            input_size = 224
    
        elif model_name == "vgg":
            """ VGG11_bn
            """
            model_ft = models.vgg11_bn(pretrained=use_pretrained)
            set_parameter_requires_grad(model_ft, feature_extract)
            num_ftrs = model_ft.classifier[6].in_features
            model_ft.classifier[6] = nn.Linear(num_ftrs,num_classes)
            input_size = 224
    
        elif model_name == "squeezenet":
            """ Squeezenet
            """
            model_ft = models.squeezenet1_0(pretrained=use_pretrained)
            set_parameter_requires_grad(model_ft, feature_extract)
            model_ft.classifier[1] = nn.Conv2d(512, num_classes, kernel_size=(1,1), stride=(1,1))
            model_ft.num_classes = num_classes
            input_size = 224
    
        elif model_name == "densenet":
            """ Densenet
            """
            model_ft = models.densenet121(pretrained=use_pretrained)
            set_parameter_requires_grad(model_ft, feature_extract)
            num_ftrs = model_ft.classifier.in_features
            model_ft.classifier = nn.Linear(num_ftrs, num_classes) 
            input_size = 224
    
        elif model_name == "inception":
            """ Inception v3 
            Be careful, expects (299,299) sized images and has auxiliary output
            """
            model_ft = models.inception_v3(pretrained=use_pretrained)
            set_parameter_requires_grad(model_ft, feature_extract)
            # Handle the auxilary net
            num_ftrs = model_ft.AuxLogits.fc.in_features
            model_ft.AuxLogits.fc = nn.Linear(num_ftrs, num_classes)
            # Handle the primary net
            num_ftrs = model_ft.fc.in_features
            model_ft.fc = nn.Linear(num_ftrs,num_classes)
            input_size = 299
    
        else:
            print("Invalid model name, exiting...")
            exit()
        
        return model_ft, input_size
    
    
    
    if __name__ == '__main__':
    
        print("PyTorch Version: ",torch.__version__)
        print("Torchvision Version: ",torchvision.__version__)
        # Initialize the model for this run
        model_ft, input_size = initialize_model(model_name, num_classes, feature_extract, use_pretrained=True)
        
        # Print the model we just instantiated
        print(model_ft) 
        
        data_transforms = {
            'train': transforms.Compose([
                transforms.RandomResizedCrop(input_size),
                transforms.RandomHorizontalFlip(),
                transforms.ToTensor(),
                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
            ]),
            'val': transforms.Compose([
                transforms.Resize(input_size),
                transforms.CenterCrop(input_size),
                transforms.ToTensor(),
                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
            ]),
        }
        
        print("Initializing Datasets and Dataloaders...")
        
        # Create training and validation datasets
        image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']}
    
        # Create training and validation dataloaders
        dataloaders_dict = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True, num_workers=4) for x in ['train', 'val']}
        
        # Detect if we have a GPU available
        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        
        
        # Send the model to GPU
        model_ft = model_ft.to(device)
        params_to_update = model_ft.parameters()
        print("Params to learn:")
        if feature_extract:
            params_to_update = []
            for name,param in model_ft.named_parameters():
                if param.requires_grad == True:
                    params_to_update.append(param)
                    print("\t",name)
        else:
            for name,param in model_ft.named_parameters():
                if param.requires_grad == True:
                    print("\t",name)
        
        # Observe that all parameters are being optimized
        optimizer_ft = optim.SGD(params_to_update, lr=lr_rate, momentum=0.9)
        
        # Setup the loss fxn
        criterion = nn.CrossEntropyLoss()
        
        # Train and evaluate
        model_ft, trainacc,trainloss,valacc,valloss = train_model(model_ft, dataloaders_dict, criterion, optimizer_ft, num_epochs=num_epochs, is_inception=(model_name=="inception"))
        torch.save(model_ft.state_dict(), output_path)
    
        plt.title("Acc&Loss")
        plt.xlabel("Training Epochs")
        plt.ylabel("Value")
        plt.plot(range(1,num_epochs+1),trainacc,label="TrainAcc")
        plt.plot(range(1,num_epochs+1),trainloss,label="TrainLoss")
        plt.plot(range(1,num_epochs+1),valacc,label="ValAcc")
        plt.plot(range(1,num_epochs+1),valloss,label="ValLoss")
        
        plt.ylim((0,1.))
        plt.xticks(np.arange(1, num_epochs+1, 1.0))
        plt.legend()
        plt.show()
    
    
    • 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
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284

    执行脚本训练

    python finetuning_torchvision_models_tutorial.py
    
    • 1

    测试效果

    # -*- coding: utf-8 -*-
    #!/usr/bin/python
    # -*- coding: UTF-8 -*-
    
    import torchvision as tv
    import torchvision.transforms as transforms
    import torch
    from PIL import Image
    import torch.nn as nn
    
    input_size = 480
    names = ['class1', 'class2','class3','class4']
    def pridict():
    
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        model=tv.models.resnet152()
        num_ftrs = model.fc.in_features
        model.fc = nn.Linear(num_ftrs, 4)  # 分类数量
        model.load_state_dict(torch.load("resnet152.pth"))
        model = model.to(device)
        model.eval()  # 预测模式
    
        # 获取测试图片,并行相应的处理
        img = Image.open('4.jpg')
        transform = transforms.Compose([
                transforms.Resize(input_size),
                transforms.CenterCrop(input_size),
                transforms.ToTensor(),
                transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
            ])
        
    
        img = transform(img)
        img = img.unsqueeze(0)
        img = img.to(device)
    
    
        with torch.no_grad():
            py = model(img)
        _, predicted = torch.max(py, 1)  # 获取分类结果
        classIndex_ = predicted[0]
    
        print('预测结果', names[classIndex_])
    
    
    if __name__ == '__main__':
        pridict()
    
    
    • 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

    转换模型

    将模型转换为c++可用的模型

    import torch
    import torchvision
    import torch.nn as nn
    #model = torchvision.models.resnet50(pretrained=True)
    model=torchvision.models.resnet152()
    num_ftrs = model.fc.in_features
    model.fc = nn.Linear(num_ftrs, 4)  # make the change
    model.load_state_dict(torch.load("resnet152.pth"))
    
    model.eval()
    example = torch.rand(1, 3, 480, 480)
    traced_script_module = torch.jit.trace(model, example)
    traced_script_module.save("resnet152.pt")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    操作系统复习
    C++引用内联auto关键字等介绍
    [山东科技大学OJ]1169 Problem I: 统计单词数
    JAVA电商平台免费搭建 B2B2C商城系统 多用户商城系统 直播带货 新零售商城 o2o商城 电子商务 拼团商城 分销商城
    HTTP 之 options预请求 nginx 解决跨域 postman调试跨域问题
    【JAVAEE框架】Mybatis常用操作(CRUD)
    代码随想录动态规划——不同的子序列
    堆(二叉堆)-优先队列-数据结构和算法(Java)
    如何通过 wireshark 捕获 C# 上传的图片
    Selenium安装报错:No matching distribution found for selenium。经个人尝试,问题已得到解决
  • 原文地址:https://blog.csdn.net/liang_baikai/article/details/127927218