resnet ネットワーク アーキテクチャに基づくトレーニング画像分類モデル

データ前処理部分:

  • データ拡張: torchvision の変換モジュールには、より実用的な独自の関数があります。
  • データの前処理: torchvision の変換もそれを実現するのに役立ちます。直接呼び出すだけです。
  • DataLoader モジュールはバッチ データを直接読み取ります

ネットワークモジュールの設定:

  • 事前トレーニングされたモデルをロードします。torchvision には、呼び出すのに非常に便利な古典的なネットワーク アーキテクチャが多数あります。また、他の人がトレーニングした重みパラメータを使用してトレーニングを続けることもできます (いわゆる転移学習)。
  • 他の人がトレーニングしたタスクは私たちのタスクとまったく同じではないことに注意してください。最後のヘッド層 (通常は最後に完全に接続された層) を私たち自身のタスクに変更する必要があります。
  • 最初の数層はすべて特徴抽出に使用され、本質的なタスクの目標は同じであるため、トレーニング中に、最初からトレーニングをやり直すことも、タスクの最後の層だけをトレーニングすることもできます。

ネットワークモデルの保存とテスト

  • モデルは選択的に保存できます。たとえば、現在の効果が検証セットで良好であれば、それを保存します。
  • 実際のテスト用にモデルを読み取る
  • import os
    import matplotlib.pyplot as plt
    %matplotlib inline
    import numpy as np
    import torch
    from torch import nn
    import torch.optim as optim
    import torchvision
    #pip install torchvision
    from torchvision import transforms, models, datasets
    #https://pytorch.org/docs/stable/torchvision/index.html
    import imageio
    import time
    import warnings
    warnings.filterwarnings("ignore")
    import random
    import sys
    import copy
    import json
    from PIL import Image

    データの読み取りと前処理操作

    data_dir = './flower_data/'
    train_dir = data_dir + '/train'
    valid_dir = data_dir + '/valid'

    適切なデータソースを作成します。

  • すべての画像前処理操作は data_transforms で指定されます
  • ImageFolder は、すべてのファイルがフォルダーに保存され、同じカテゴリの画像が各フォルダーの下に保存され、フォルダーの名前がカテゴリの名前になることを前提としています。
    data_transforms = {
        'train': 
            transforms.Compose([
            transforms.Resize([96, 96]),
            transforms.RandomRotation(45),#随机旋转,-45到45度之间随机选
            transforms.CenterCrop(64),#从中心开始裁剪
            transforms.RandomHorizontalFlip(p=0.5),#随机水平翻转 选择一个概率概率
            transforms.RandomVerticalFlip(p=0.5),#随机垂直翻转
            transforms.ColorJitter(brightness=0.2, contrast=0.1, saturation=0.1, hue=0.1),#参数1为亮度,参数2为对比度,参数3为饱和度,参数4为色相
            transforms.RandomGrayscale(p=0.025),#概率转换成灰度率,3通道就是R=G=B
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])#均值,标准差
        ]),
        'valid': 
            transforms.Compose([
            transforms.Resize([64, 64]),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
        ]),
    }
    batch_size = 128
    
    image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'valid']}
    dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=True) for x in ['train', 'valid']}
    dataset_sizes = {x: len(image_datasets[x]) for x in ['train', 'valid']}
    class_names = image_datasets['train'].classes
    image_datasets
    {'train': Dataset ImageFolder
         データポイントの数: 6552
         ルートの場所: ./flower_data/train 
         StandardTransform 
     Transform: Compose( 
                    Resize(size=[96, 96], interpolation=bilinear, max_size=None, antialias=None) 
                    RandomRotation(degrees ) =[-45.0, 45.0]、interpolation=nearest、expand=False、fill=0) 
                    CenterCrop(size=(64, 64)) 
                    Randomhorizo​​ntalFlip(p=0.5) 
                    RandomVerticalFlip(p=0.5) 
                    ColorJitter(brightness=[0.8, 1.2 ]、コントラスト=[0.9, 1.1]、彩度=[0.9, 1.1]、色相=[-0.1, 0.1]) 
                    RandomGrayscale(p=0.025) 
                    ToTensor()
                    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ) 
                , 'valid': データセット ImageFolder
         データポイント数: 818
         ルートの場所: ./flower_data/valid 
         StandardTransform
     変換: Compose( 
                    Resize( size=[64, 64]、interpolation=bilinear、max_size=None、antialias=None) 
                    ToTensor() 
                    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ) 
                }
    dataloaders
    {'train': <torch.utils.data.dataloader.DataLoader 0x1e4c50b9400>, 
     'valid': <torch.utils.data.dataloader.DataLoader 0x1e4c51ad128>}
    dataset_sizes
    {'列車': 6552、'有効': 818}
  • タグに対応する実際の名前を読み取ります

    with open('cat_to_name.json', 'r') as f:
        cat_to_name = json.load(f)
    cat_to_name
    {'1': 'ピンクのサクラソウ'、
     '10': 'グローブ アザミ'、
     '100': 'ブランケットフラワー'、
     '101': 'ノウゼンカズラ'、
     '102': 'ブラックベリー ユリ'、
     '11': 'キンギョソウ'、
     '12': 'フクロタの足'、
     '13': 'キングプロテア'、
     '14': 'スピアザミ'、
     '15': 'イエローアイリス'、
     '16': 'グローブフラワー'、
     '17': 'パープルコーンフラワー'、
     '18': 'ペルーユリ'、
     '19': 'バルーンフラワー'、
     '2': '硬葉ポケットラン'、
     '20': 'ジャイアントホワイトアルムユリ'、
     「21」:「ファイアリリー」、
     「22」:「糸巻き花」、
     「23」:「ヒョウモン」、「
     24」:「レッドジンジャー」、
     「25」:「ブドウヒヤシンス」、
     「26」:「トウモロコシ」ポピー'、
     '27': 'プリンス・オブ・ウェールズの羽'、 
     '47 ': 'マリーゴールド'、
     「28」: 「茎のないリンドウ」、
     「29」: 「アーティチョーク」、
     「3」: 「カンタベリーベル」、
     「30」: 「スイートウィリアム」、
     「31」: 「カーネーション」、
     「32」: 「フロックス」 '、
     '33': '霧の中の愛'、
     '34': 'メキシカンアスター'、
     '35': 'アルペンシーヒイラギ'、
     '36': 'ルビーリップカトレア'、
     '37': 'ケープフラワー' '、
     '38': 'グレートマスターワート'、
     '39': 'サイアムチューリップ'、
     '4': 'スイートピー'、
     '40': 'レンテンローズ'、
     '41': 'バルベトンデイジー'、
     '42' :'水仙'、 
     '43': 'ソードリリー'、
     '44': 'ポインセチア'、
     '45': 'ボレロディープブルー'、
     '46': 'ウォールフラワー'、'48' 
     : 'キンポウゲ'、
     '49' : 'オセアオイ', 
     '5': 'イングリッシュマリーゴールド'、
     '50': 'タンポポ'、
     '51': 'ペチュニア'、
     '52': 'ワイルドパンジー'、
     '53': 'サクラソウ' 、
     「54」:「ひまわり」、
     「55」:「ペラルゴニウム」、
     「56」:「ランダフ司教」、
     「57」:「ガウラ」、
     「58」:「ゼラニウム」、
     「59」:「オレンジダリア」 '、
     '6': 'オニユリ'、
     '60': 'ピンクイエローダリア'、
     '61': 'カウトレヤ・スピカタ'、
     '62': 'ニホンイソギンチャク'、
     '63': 'クロアイドスーザン' 、
     「64」: 「シルバーブッシュ」、
     「65」: 「カリフォルニアポピー」、
     「66」: 「オステオスペルマム
     」、「67」: 「スプリングクロッカス」、
     「68」: 「ヒゲアイリス」、
     「69」: 「ウィンドフラワー」 、 
     '7': 'ムーンラン'、
     '70': '木ポピー'、 
     「71」:「ガザニア」、
     「72」:「ツツジ」、
     「73」:「スイレン」、
     「74」:「バラ」、
     「75」:「トゲリンゴ」 、
     「76」:「アサガオ」、
     「77」:「パッションフラワー」、
     「78」:「ハスハス」、
     「79」:「ヒキガエル」、
     「8」:「極楽鳥」、
     「80」 : 'アンスリウム'、
     '81': 'プルメリア'、
     '82': 'クレマチス'、
     '83': 'ハイビスカス'、
     '84': 'オダマキ'、
     '85': 'デザートローズ'、
     '86' :'アオイ科の植物'、 
     '87': 'モクレン'、
     '88': 'シクラメン'、
     '89': 'クレソン'、
     '9': 'トリカブト'、
     '90': 'カンナユリ'、
     '91': 'ヒッペアストラム'、
     '92': 'ビーバーム'、
     '93': '玉苔'、 
     '94': 'ジギタリス'、
     '95': 'ブーゲンビリア'、
     '96': 'ツバキ'、
     '97': 'アオイ科'、
     '98': 'メキシコペチュニア'、
     '99': 'ブロメリア'}
  • models で提供されるモデルをロードし、トレーニングされた重みを初期化パラメータとして直接使用します

  • 最初の実行はダウンロードする必要がありますが、時間がかかる可能性があります。ダウンロードしたコピーを提供しますので、対応するパスに直接配置できます。
    model_name = 'resnet'  #可选的比较多 ['resnet', 'alexnet', 'vgg', 'squeezenet', 'densenet', 'inception']
    #是否用人家训练好的特征来做
    feature_extract = True #都用人家特征,咱先不更新
    # 是否用GPU训练
    train_on_gpu = torch.cuda.is_available()
    
    if not train_on_gpu:
        print('CUDA is not available.  Training on CPU ...')
    else:
        print('CUDA is available!  Training on GPU ...')
        
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    CUDAは利用できません。CPUのトレーニング...
  • モデルパラメータを更新しますか?

  • 他の人のモデルを使うこともありますが、更新どころかずっと使っていますし、自分たちでカスタマイズすることもできます。
    def set_parameter_requires_grad(model, feature_extracting):
        if feature_extracting:
            for param in model.parameters():
                param.requires_grad = False
    model_ft = models.resnet18()#18层的能快点,条件好点的也可以选152
    model_ft
    ResNet( 
      (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3),bias=False) (bn1): BatchNorm2d(64, eps 
      = 1e-05、momentum=0.1、affine=True、track_running_stats=True) 
      (relu): ReLU(inplace=True) 
      (maxpool): MaxPool2d(kernel_size=3、stride=2、padding=1、dilation=1、ceil_mode=) False) 
      (layer1): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias= False) 
          (bn1): BatchNorm2d(64、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) ( 
          relu): ReLU(inplace=True)  
          (conv2): Conv2d(64, 64, kernel_size= (3, 3)、ストライド=(1, 1)、パディング=(1, 1)、バイアス=False)
          (bn2): BatchNorm2d(64、eps=1e- 05、勢い=0.1、アフィン=True、track_running_stats=True) 
        ) 
        (1): BasicBlock(
          (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) (bn1): BatchNorm2d(64, eps= 
          1e- 05、momentum=0.1、affine=True、track_running_stats=True) 
          (relu): ReLU(inplace=True) 
          (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1),パディング=(1, 1)、バイアス=False) 
          (bn2): BatchNorm2d(64、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) ) ) 
        ( 
      layer2 
      ): Sequential( 
        (0): BasicBlock(  
          (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2) 、2)、パディング=(1, 1)、バイアス=False)
          (bn1): BatchNorm2d(128, eps=1e-05, 勢い=0.1, affine=True, track_running_stats=True) ( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(128, 128, kernel_size= (3, 3)、ストライド=(1, 1)、パディング=(1, 1)、バイアス=False)
          (bn2): BatchNorm2d(128、eps=1e-05、momentum=0.1、affine=True、track_running_stats= True) 
          (ダウンサンプル): Sequential( 
            (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2),bias=False) (1): BatchNorm2d(128, eps= 
            1e- 05、勢い = 0.1、アフィン = True、track_running_stats = True) 
          ) 
        ) 
        (1): BasicBlock( 
          (conv1): Conv2d(128, 128, kernel_size = (3, 3)、stride = (1, 1)、padding = (1, 1)、バイアス=False) 
          (bn1): BatchNorm2d(128、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) ( 
          relu): ReLU(inplace=True)
          (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) ) ) (layer3): Sequential(  
          bn2 ): BatchNorm2d(128、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True)
        ( 
      0 
      ) 
        : BasicBlock( 
          (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1),bias=False) (bn1): BatchNorm2d(256, eps 
          = 1e-05、momentum=0.1、affine=True、track_running_stats=True) 
          (relu): ReLU(inplace=True) 
          (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1) )、パディング=(1, 1)、バイアス=False) 
          (bn2): BatchNorm2d(256、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) 
          (ダウンサンプル): Sequential( 
            (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2),bias=False)
            (1): BatchNorm2d(256, eps=1e-05, 勢い=0.1, affine=True, track_running_stats=True) ) ( 
          conv1 
        BasicBlock 
        (
          ): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1)、パディング=(1, 1)、バイアス=False) 
          (bn1): BatchNorm2d(256、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) 
          (relu): ReLU(inplace=True) ) 
          (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) (bn2): BatchNorm2d(256, eps=1e 
          ) -05、勢い=0.1、アフィン=True、track_running_stats=True) 
        ) 
      ) 
      (layer4): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=( 2, 2)、パディング=(1, 1)、バイアス=False)
          (bn1): BatchNorm2d(512、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(512, 512, kernel_size= (3, 3)、ストライド=(1, 1)、パディング=(1, 1)、バイアス=False)
          (bn2): BatchNorm2d(512、eps=1e-05、momentum=0.1、affine=True、track_running_stats= True) 
          (ダウンサンプル): Sequential( 
            (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2),bias=False) (1): BatchNorm2d(512, eps= 
            1e- 05、勢い = 0.1、アフィン = True、track_running_stats = True) 
          ) 
        ) 
        (1): BasicBlock( 
          (conv1): Conv2d(512, 512, kernel_size = (3, 3)、stride = (1, 1)、padding = (1, 1)、バイアス=False) 
          (bn1): BatchNorm2d(512、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) ( 
          relu): ReLU(inplace=True)
          (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) ) ) (avgpool): AdaptiveAvgPool2d(output_size= 
          bn2 ): BatchNorm2d(512、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True)
        ( 
      1 
      ) 、1)) 
      (fc): Linear(in_features=512、out_features=1000、bias=True)
  • モデル出力レイヤーを独自のものに変更します

    def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True):
        
        model_ft = models.resnet18(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, 102)#类别数自己根据自己任务来
                                
        input_size = 64#输入大小根据自己配置来
    
        return model_ft, input_size

    どのレイヤーをトレーニングする必要があるかを設定する

    model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
    
    #GPU还是CPU计算
    model_ft = model_ft.to(device)
    
    # 模型保存,名字自己起
    filename='checkpoint.pth'
    
    # 是否训练所有层
    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)
    学習するパラメータ: 
    	 fc.weight 
    	 fc.bias
  • model_ft
    ResNet( 
      (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3),bias=False) (bn1): BatchNorm2d(64, eps 
      = 1e-05、momentum=0.1、affine=True、track_running_stats=True) 
      (relu): ReLU(inplace=True) 
      (maxpool): MaxPool2d(kernel_size=3、stride=2、padding=1、dilation=1、ceil_mode=) False) 
      (layer1): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias= False) 
          (bn1): BatchNorm2d(64、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) ( 
          relu): ReLU(inplace=True)  
          (conv2): Conv2d(64, 64, kernel_size= (3, 3)、ストライド=(1, 1)、パディング=(1, 1)、バイアス=False)
          (bn2): BatchNorm2d(64、eps=1e- 05、勢い=0.1、アフィン=True、track_running_stats=True) 
        ) 
        (1): BasicBlock(
          (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) (bn1): BatchNorm2d(64, eps= 
          1e- 05、momentum=0.1、affine=True、track_running_stats=True) 
          (relu): ReLU(inplace=True) 
          (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1),パディング=(1, 1)、バイアス=False) 
          (bn2): BatchNorm2d(64、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) ) ) 
        ( 
      layer2 
      ): Sequential( 
        (0): BasicBlock( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(128, 128, kernel_size= (3, 3)、ストライド=(1, 1)、パディング=(1, 1)、バイアス=False) 
          (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2) 、2)、パディング=(1, 1)、バイアス=False)
          (bn1): BatchNorm2d(128、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) 
          (bn2): BatchNorm2d(128、eps=1e-05、momentum=0.1、affine=True、track_running_stats= True) 
          (ダウンサンプル): Sequential( 
            (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2),bias=False) (1): BatchNorm2d(128, eps= 
            1e- 05、勢い = 0.1、アフィン = True、track_running_stats = True) 
          ) 
        ) 
        (1): BasicBlock( 
          (conv1): Conv2d(128, 128, kernel_size = (3, 3)、stride = (1, 1)、padding = (1, 1)、バイアス=False) 
          (bn1): BatchNorm2d(128、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) ( 
          relu): ReLU(inplace=True)
          (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) ) ) (layer3): Sequential(  
          bn2 ): BatchNorm2d(128、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True)
        ( 
      0 
      ) 
        : BasicBlock( 
          (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1),bias=False) (bn1): BatchNorm2d(256, eps 
          = 1e-05、momentum=0.1、affine=True、track_running_stats=True) 
          (relu): ReLU(inplace=True) 
          (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1) )、パディング=(1, 1)、バイアス=False) 
          (bn2): BatchNorm2d(256、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) 
          (ダウンサンプル): Sequential( 
            (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2),bias=False) 
            (1): BatchNorm2d(256、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) ) ) (1) 
          : 
        BasicBlock 
        (
          (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) (bn1): BatchNorm2d(256, eps=1e- 
          ) 05、momentum=0.1、affine=True、track_running_stats=True) 
          (relu): ReLU(inplace=True) 
          (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1),パディング=(1, 1)、バイアス=False) 
          (bn2): BatchNorm2d(256、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) ) 
        ) 
      ( 
      layer4): Sequential( 
        (0): BasicBlock( 
          (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=( 2, 2)、パディング=(1, 1)、バイアス=False)
          (bn1): BatchNorm2d(512、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) ( 
          relu): ReLU(inplace=True) 
          (conv2): Conv2d(512, 512, kernel_size= (3, 3)、ストライド=(1, 1)、パディング=(1, 1)、バイアス=False)
          (bn2): BatchNorm2d(512、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) (ダウンサンプル): Sequential( (0): 
          Conv2d 
            (256, 512, kernel_size=(1, 1), stride=(2, 2)、bias=False) 
            (1): BatchNorm2d(512、eps=1e-05、momentum=0.1、affine=True、track_running_stats=True) ) ) (1) 
          : 
        BasicBlock 
        ( 
          (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1),bias=False) (bn1): BatchNorm2d(512, eps=1e-05,勢い
          = 0.1、affine=True、track_running_stats=True) 
          relu): ReLU(inplace=True)
          (conv2): Conv2d(512, 512、kernel_size=(3, 3)、stride=(1, 1)、padding=(1, 1)、bias=False) ( 
          bn2 ): BatchNorm2d(512、eps=1e-05、勢い=0.1、affine=True、track_running_stats=True) 
        ( 
      1 
      ) 、1)) 
      (fc): Linear(in_features=512、out_features=102、bias=True) 
    )
  • オプティマイザー設定

    # 优化器设置
    optimizer_ft = optim.Adam(params_to_update, lr=1e-2)#要训练啥参数,你来定
    scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=10, gamma=0.1)#学习率每7个epoch衰减成原来的1/10
    criterion = nn.CrossEntropyLoss()

    トレーニングモジュール

    def train_model(model, dataloaders, criterion, optimizer, num_epochs=25,filename='best.pt'):
        #咱们要算时间的
        since = time.time()
        #也要记录最好的那一次
        best_acc = 0
        #模型也得放到你的CPU或者GPU
        model.to(device)
        #训练过程中打印一堆损失和指标
        val_acc_history = []
        train_acc_history = []
        train_losses = []
        valid_losses = []
        #学习率
        LRs = [optimizer.param_groups[0]['lr']]
        #最好的那次模型,后续会变的,先初始化
        best_model_wts = copy.deepcopy(model.state_dict())
        #一个个epoch来遍历
        for epoch in range(num_epochs):
            print('Epoch {}/{}'.format(epoch, num_epochs - 1))
            print('-' * 10)
    
            # 训练和验证
            for phase in ['train', 'valid']:
                if phase == 'train':
                    model.train()  # 训练
                else:
                    model.eval()   # 验证
    
                running_loss = 0.0
                running_corrects = 0
    
                # 把数据都取个遍
                for inputs, labels in dataloaders[phase]:
                    inputs = inputs.to(device)#放到你的CPU或GPU
                    labels = labels.to(device)
    
                    # 清零
                    optimizer.zero_grad()
                    # 只有训练的时候计算和更新梯度
                    outputs = model(inputs)
                    loss = criterion(outputs, labels)
                    _, preds = torch.max(outputs, 1)
                    # 训练阶段更新权重
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()
    
                    # 计算损失
                    running_loss += loss.item() * inputs.size(0)#0表示batch那个维度
                    running_corrects += torch.sum(preds == labels.data)#预测结果最大的和真实值是否一致
                    
                
                
                epoch_loss = running_loss / len(dataloaders[phase].dataset)#算平均
                epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)
                
                time_elapsed = time.time() - since#一个epoch我浪费了多少时间
                print('Time elapsed {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
                print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
                
    
                # 得到最好那次的模型
                if phase == 'valid' and epoch_acc > best_acc:
                    best_acc = epoch_acc
                    best_model_wts = copy.deepcopy(model.state_dict())
                    state = {
                      'state_dict': model.state_dict(),#字典里key就是各层的名字,值就是训练好的权重
                      'best_acc': best_acc,
                      'optimizer' : optimizer.state_dict(),
                    }
                    torch.save(state, filename)
                if phase == 'valid':
                    val_acc_history.append(epoch_acc)
                    valid_losses.append(epoch_loss)
                    #scheduler.step(epoch_loss)#学习率衰减
                if phase == 'train':
                    train_acc_history.append(epoch_acc)
                    train_losses.append(epoch_loss)
            
            print('Optimizer learning rate : {:.7f}'.format(optimizer.param_groups[0]['lr']))
            LRs.append(optimizer.param_groups[0]['lr'])
            print()
            scheduler.step()#学习率衰减
    
        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, val_acc_history, train_acc_history, valid_losses, train_losses, LRs 

    トレーニングを始めましょう!

  • これで出力層のトレーニングのみが完了しました。
    model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs  = train_model(model_ft, dataloaders, criterion, optimizer_ft, num_epochs=20)
    エポック 0/19 
    ----------
    経過時間 0 分 39 秒
    列車損失: 4.0874 検出数: 0.2355
    経過時間 0 分 43 秒
    有効損失: 3.5746 検出数: 0.2531
    オプティマイザ学習率 : 0.0100000
    
    エポック 1/19 
    ----- -----
    経過時間 1 分 22 秒の
    列車 損失: 2.8185 一致度: 0.3953
    経過時間 1 分 26 秒
    有効 損失: 3.5450 一致度: 0.3142
    オプティマイザの学習率 : 0.0100000
    
    エポック 2/19 
    ----------
    経過時間 2 分 5 秒
    列車の損失: 2.7673 Acc: 0.4174
    経過時間 2 分 9 秒
    有効 損失: 3.9110 Acc: 0.2653
    オプティマイザの学習率 : 0.0100000
    
    エポック 3/19 
    ----------
    経過時間 2 分 48 秒
    列車の損失: 2.7962 Acc: 0.4255
    経過時間 2 分 52 秒
    有効 損失: 3.6922 Acc: 0.3142
    オプティマイザーの学習率 : 0.0100000
    
    エポック 4/19 
    ----------
    経過時間 3 分 32 秒の
    列車の損失: 2.7453 Acc: 0.4428
    経過時間3 分 36 秒
    有効損失: 3.9310 有効損失: 0.3044
    オプティマイザ学習率 : 0.0100000
    
    エポック 5/19 
    ----------
    経過時間 4 分 14 秒の
    列車損失: 2.2935 有効損失: 0.5043
    経過時間 4 分 18 秒
    有効損失: 3.3299 有効損失: 0.3435
    オプティマイザーの学習率 : 0.0010000
    
    エポック 6/19 
    ----------
    経過時間 4 分 57 秒
    列車損失: 2.0654 ACC: 0.5258
    経過時間 5 分 1 秒
    有効損失: 3.2608 ACC: 0.3411
    オプティマイザ学習率 : 0.0010000
     
    Epoch 7/19 
    ----------
    経過時間 5 分 40 秒
    列車損失: 1.9603 Acc: 0.5369
    経過時間 5 分 44 秒
    有効損失: 3.2618 Acc: 0.3472
    オプティマイザ学習率 : 0.0010000
    
    エポック 8 /19 
    ----------
    経過時間 6 分 23 秒
    列車損失: 1.9216 精度: 0.5401
    経過時間 6 分 27 秒
    有効損失: 3.1651 精度: 0.3386
    オプティマイザ学習率: 0.0010000
    
    エポック 9/19 
    ------- ---
    経過時間 7 分 5 秒の
    列車損失: 1.9203 有効損失: 0.5458
    経過時間 7 分 9 秒
    有効損失: 3.0449 有効損失: 0.3680
    オプティマイザ学習率 : 0.0010000
    
    エポック 10/19 
    ----------
    経過時間 7 分 48 秒
    train Loss: 1.8366 Acc: 0.5553
    経過時間 7 分 52 秒
    有効損失: 3.0722 有効損失: 0.3545
    オプティマイザ学習率 : 0.0001000
    
    エポック 11/19 
    ----------
    経過時間 8 分 31 秒の
    列車損失: 1.8324 有効損失: 0.5546
    経過時間8 分 35 秒
    有効損失: 3.0115 有効損失: 0.3643
    オプティマイザーの学習率 : 0.0001000
    
    エポック 12/19 
    ----------
    経過時間 9 分 13 秒の
    列車損失: 1.8054 ACC: 0.5553
    経過時間 9 分 17 秒
    の有効損失: 3.0688 ACC: 0.3619
    オプティマイザーの学習率 : 0.0001000
    
    エポック13 /19 
    ----------
    経過時間 9 分 56 秒の
    列車 損失: 1.8436 一致度: 0.5534
    オプティマイザ学習率 : 0.0001000
    経過時間 10 分 0 秒
    有効損失: 3.0100 Acc: 0.3631 
    
    Epoch 14/19 
    ----------
    経過時間 10 分 39 秒
    列車損失: 1.7417 Acc: 0.5614
    経過時間 10 分 43 秒
    有効損失: 3.0129 Acc: 0.3655
    オプティマイザ学習率 : 0.0001000
    
    エポック 15 /19 
    ----------
    経過時間 11 分 22 秒の
    列車 損失: 1.7610 一致度: 0.5672
    経過時間 11 分 26 秒
    有効な損失: 3.0220 一致度: 0.3606
    オプティマイザーの学習率 : 0.0000100
    
    エポック 16/19 
    ------- ---
    経過時間 12 分 6 秒の
    列車 損失: 1.7788 精度: 0.5676
    経過時間 12 分 10 秒
    有効損失: 3.0104 精度: 0.3557
    オプティマイザーの学習率 : 0.0000100
    
    エポック 17/19 
    ----------
    経過時間 12 分 49 秒
    列車の損失: 1.8033 Acc: 0.5638
    経過時間 12 分 53 秒
    有効な損失: 3.0428 Acc: 0.3606
    オプティマイザの学習率 : 0.0000100 
    
    Epoch 18/19 
    ----------
    経過時間 13 分 33 秒
    列車の損失: 1.8294 Acc: 0.5568
    経過時間13 分 37 秒
    有効損失: 3.0307 有効損失: 0.3509
    オプティマイザ学習率 : 0.0000100
    
    エポック 19/19 
    ----------
    経過時間 14 分 16 秒
    列車損失: 1.7949 有効損失: 0.5612
    経過時間 14 分 20 秒
    有効損失: 3.0396 有効損失: 0.364 3
    オプティマイザーの学習率 : 0.0000100
    
    トレーニングは 14 分 20 秒で完了
    最良の値 Acc: 0.367971
  • その後、すべてのレイヤーのトレーニングを続行します

    for param in model_ft.parameters():
        param.requires_grad = True
    
    # 再继续训练所有的参数,学习率调小一点
    optimizer = optim.Adam(model_ft.parameters(), lr=1e-3)
    scheduler = optim.lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)
    
    # 损失函数
    criterion = nn.CrossEntropyLoss()
    # 加载之前训练好的权重参数
    
    checkpoint = torch.load(filename)
    best_acc = checkpoint['best_acc']
    model_ft.load_state_dict(checkpoint['state_dict'])
    model_ft, val_acc_history, train_acc_history, valid_losses, train_losses, LRs  = train_model(model_ft, dataloaders, criterion, optimizer, num_epochs=10,)
    エポック 0/9 
    ----------
    経過時間 1 分 32 秒の
    列車損失: 2.2451 一致度: 0.4846
    経過時間 1 分 36 秒
    有効な損失: 2.3190 一致度: 0.4633
    オプティマイザ学習率 : 0.0010000
    
    エポック 1/9 
    ----- -----
    経過時間 2 分 54 秒
    列車 損失: 1.2920 一致度: 0.6505
    経過時間 2 分 58 秒
    有効 損失: 2.2263 一致度: 0.4670
    オプティマイザー学習率 : 0.0010000
    
    エポック 2/9 
    ----------
    経過時間 4 分 15 秒
    train Loss: 1.1026 Acc: 0.6993
    経過時間 4 分 19 秒
    有効な Loss: 1.8115 Acc: 0.5452 
    Optimizer 学習率 : 0.0010000 
    
    Epoch 3/9 
    ----------
    経過時間 5 分 35 秒
    train Loss: 0.9062 Acc: 0.7515
    経過時間 5 分 39 秒
    有効 損失: 2.0045 Acc: 0.5403
    オプティマイザ学習率 : 0.0010000 
    
    Epoch 4/9 
    ----------
    経過時間 6 分 56 秒
    train loss: 0.8392 Acc: 0.7643
    経過時間7 分 0 秒
    有効損失: 2.1381 有効損失: 0.5171
    オプティマイザ学習率 : 0.0010000
    
    エポック 5/9 
    ----------
    経過時間 8 分 17 秒
    列車損失: 0.7081 有効損失: 0.7953
    経過時間 8 分 21 秒
    有効損失: 2.0461 有効損失: 0.5599
    オプティマイザーの学習率 : 0.0010000
    
    エポック 6/9 
    ----------
    経過時間 9 分 38 秒
    列車損失: 0.6400 ACC: 0.8147
    経過時間 9 分 42 秒
    有効損失: 2.2603 精度: 0.5452
    トレーニングは 13 分 45 秒で完了しました
    オプティマイザの学習率 : 0.0010000
    
    エポック 7/9 
    ----------
    経過時間 10 分 59 秒
    列車損失: 0.6406 加速度: 0.8117
    経過時間 11 分 3 秒
    有効損失: 1.4649 加速度: 0.6406
    オプティマイザ学習率 : 0.0010000
    
    エポック 8/9 
    ----- -----
    経過時間 12 分 20 秒
    列車 損失: 0.5686 精度: 0.8300
    経過時間 12 分 24 秒
    有効損失: 1.7538 精度: 0.6100
    オプティマイザ学習率 : 0.0010000
    
    エポック 9/9 
    ----------
    経過時間 13 分 41 秒
    train Loss: 0.5978 Acc: 0.8245
    経過時間 13 分 45 秒
    有効な Loss: 1.6953 Acc: 0.6161
    オプティマイザーの学習率 : 0.0010000 
    
    Best val Acc: 0.640587
  • トレーニング済みモデルをロードする

    model_ft, input_size = initialize_model(model_name, 102, feature_extract, use_pretrained=True)
    
    # GPU模式
    model_ft = model_ft.to(device)
    
    # 保存文件的名字
    filename='best.pt'
    
    # 加载模型
    checkpoint = torch.load(filename)
    best_acc = checkpoint['best_acc']
    model_ft.load_state_dict(checkpoint['state_dict'])

    テストデータの前処理

  • テストデータの処理方法はトレーニング時と同じにする必要があります。
  • トリミング操作の目的は、入力サイズの一貫性を確保することです。
  • 標準化操作も必要です。トレーニング データと同じ平均値と標準偏差を使用します。ただし、トレーニング データは 0 ~ 1 で標準化されているため、最初にテスト データも正規化する必要があることに注意してください。
  • 最後に、PyTorch のカラー チャネルは最初の次元であり、多くのツールキットとは異なり、変換する必要があります。
  • # 得到一个batch的测试数据
    dataiter = iter(dataloaders['valid'])
    images, labels = dataiter.next()
    
    model_ft.eval()
    
    if train_on_gpu:
        output = model_ft(images.cuda())
    else:
        output = model_ft(images)

    出力は、バッチ内の各データが各カテゴリに属する​​確率を表します。

    output.shape

    最も確率の高いものを入手する

    _, preds_tensor = torch.max(output, 1)
    
    preds = np.squeeze(preds_tensor.numpy()) if not train_on_gpu else np.squeeze(preds_tensor.cpu().numpy())
    preds
    array([ 34,  49,  43,  54,  20,  14,  49,  43,  50,  20,  19, 100,  78,
            96,  96,  62,  62,  63,  32,  38,  82,  43,  88,  73,   6,  51,
            43,  89,  55,  75,  55,  11,  46,  82,  48,  82,  20, 100,  48,
            20,  24,  49,  76,  93,  49,  46,  90,  75,  89,  75,  76,  99,
            56,  48,  77,  66,  60,  72,  89,  97,  76,  73,  17,  48,  39,
            31,  19,  74,  61,  46,  93,  80,  27,  11,  91,  18,  23,  47,
            29,  54,  18,  93,   1,  50,  79,  96,  39,  53,  63,  60,  49,
            23,  23,  52,  99,  89,   3,  50,  64,  15,  19,  60,  19,  75,
            50,  78,  82,  18,  75,  18,  82,  53,   3,  52,  60,  38,  62,
            47,  21,  59,  81,  48,  89,  64,  60,  55, 100,  60], dtype=int64)

    予測結果を表示する

    def im_convert(tensor):
        """ 展示数据"""
        
        image = tensor.to("cpu").clone().detach()
        image = image.numpy().squeeze()
        image = image.transpose(1,2,0)
        image = image * np.array((0.229, 0.224, 0.225)) + np.array((0.485, 0.456, 0.406))
        image = image.clip(0, 1)
    
        return image
    fig=plt.figure(figsize=(20, 20))
    columns =4
    rows = 2
    
    for idx in range (columns*rows):
        ax = fig.add_subplot(rows, columns, idx+1, xticks=[], yticks=[])
        plt.imshow(im_convert(images[idx]))
        ax.set_title("{} ({})".format(cat_to_name[str(preds[idx])], cat_to_name[str(labels[idx].item())]),
                     color=("green" if cat_to_name[str(preds[idx])]==cat_to_name[str(labels[idx].item())] else "red"))
    plt.show()

おすすめ

転載: blog.csdn.net/qq_65838372/article/details/132745442