PyTorch入門一:ボリュームニューラルネットワークMNIST手書きデジタル識別を実現

47460 ワード

まずいくつかの入門PyTorchの良い資料を提供します:
  • PyTorch公式チュートリアル(中国語版):http://pytorch123.com
  • 「手作業で深く学ぶ」PyTorch版:https://github.com/ShusenTang/Dive-into-DL-PyTorch

  • 1.PyTorch紹介
    PyTorchはTorch 7チームが開発したもので、Torchとの違いはPyTorchが開発言語としてPythonを使用している点であり、同様にPython優先の深さ学習フレームワークであり、強力なGPU加速を実現するだけでなく、動的ニューラルネットワークもサポートしていることを示しており、TensorFlowなど多くの主流フレームワークではサポートされていない.さらにPyTorchは簡単に拡張でき、ここ2年はTensorFlowを追い抜く勢いがある.
    2.コンボリューションニューラルネットワーク(CNN)
    コンボリューションニューラルネットワーク(CNN-Convolutional Neural Network)は、フィードフォワードニューラルネットワークである.長い間、画像認識分野のコアアルゴリズムの1つであるPyTorch入门一:卷积神经网络实现MNIST手写数字识别_第1张图片これはボリュームとニューラルネットワーク機構の概略図であり、次の各部分を理解してみましょう.
  • 入力層(Input Layer):私たちにとって入力されたのは画像ですが、コンピュータにとって入力されたのはマトリクスタイプのデータで、これらのデータはこの画像の画素値
  • を表しています.
  • ボリューム層(Convolution Layers):入力されたデータを特徴抽出し、各ボリュームコアが1つの小領域から1つの特徴値を抽出するたびに、すべての特徴値を組み合わせて1つの特徴図が得られ、複数のボリューム照合で入力データを特徴抽出すると、複数の特徴図が得られる.このボリュームコアは
  • と呼ばれています
  • 活性化関数(Activation Function):人工ニューラルネットワークのニューロン上で動作する関数で、ニューロンの入力を出力端にマッピングし、活性化関数を導入するのはニューラルネットワークモデルの非線形性
  • を増加させるためである.
  • プール化層(Pooling Layer):特徴品質に影響を及ぼさずに画像を圧縮してパラメータを減らし、プール化は主に2種類あり、1つはMaxPooling、1つはAvePoolingである.プール化されたカーネルが2*2の行列であると仮定し、MaxPoolingを用いるとその最大値を出力し、AvePoolingを用いるとすべてのデータの平均値
  • を出力する.
  • フルコネクション層(Fully Connected Layer、略称FC):ボリュームニューラルネットワーク全体にわたって「分類器」の役割を果たす.ボリューム層、プール化層、アクティブ化関数層などの動作が元のデータを暗黙層の特徴空間にマッピングする場合、全接続層は、学習した「分布式特徴表現」をサンプルタグ空間にマッピングする役割を果たす
  • .
  • 出力層(Output Layer):コンボリューションニューラルネットワークにおける出力層の上流は通常、全接続層であるため、その構造および動作原理は従来のフィードフォワードニューラルネットワークにおける出力層と同じである.画像分類問題では、出力層は論理関数または正規化指数関数(softmax function)を使用して分類ラベルを出力する.物体認識(object detection)問題では、出力層は、出力物体の中心座標、大きさ、分類として設計することができる.画像の意味分割において、出力層は、各画素の分類結果
  • を直接出力.
    ボリュームニューラルネットワークを理解したら、PyTorchのボリュームニューラルネットワークを見てみましょう.
    3.PyTorchにおける畳み込みニューラルネットワーク
    3.1ボリューム:nn.Conv2d()
    パラメータは次のとおりです.
  • in_channels:入力信号のチャネル数.
  • out_channels:ボリューム後に出力結果のチャネル数.
  • kernel_size:ボリュームコアの形状.例えばkernel_size=(3,2)は3 X 2の畳み込みコアを表し、幅と高さが同じであれば1つの数字だけで
  • を表すことができる.
  • stride:移動するステップの長さをロールアップし、デフォルトは1です.
  • padding:境界を処理するときの塗りつぶし0の数、デフォルトは0(塗りつぶしなし)です.
  • dilation:サンプリング間隔の数、デフォルトは1、無間隔サンプリング
  • groups:入力と出力チャネルのパケット数.1でない場合、デフォルトは1(フル接続)
  • です.
  • biasがTrueの場合、バイアスを加える.

  • 3.2池化層:nn.MaxPool2d()
    パラメータは次のとおりです.
  • kernel_Size:最大プール化操作時のウィンドウサイズ
  • stride:最大プール化操作時のウィンドウ移動のステップ長、デフォルト値はkernel_size
  • padding:入力エッジごとに暗黙的に0を補う数
  • dilation:ウィンドウ内の要素のステップ長を制御するパラメータ
  • return_indices:Trueに等しい場合、max pooling結果を返しながら最大値のインデックスを返します.これは、その後のUnpoolingで
  • に役立ちます.
  • ceil_mode:Trueに等しい場合、計算出力が大きい場合、デフォルトの下方向の整列の代わりに上向きの整列が採用される
  • .
    4.MNIST手書きデジタル認識を実現
    次にpytorchを用いて,手書き数字を訓練し識別するためのボリュームニューラルネットワークを構築する.
    4.1ライブラリ関数の導入
    import torch.nn as nn  # pytorch       ,            
    import torch.nn.functional as F  #           , softmax
    import torch.optim as optim  #     ,             , Adam SGD
    from torch.optim import lr_scheduler  #       ,             
    from torchvision import transforms  # pytorch                 
    from torchvision import datasets  # pytorch               
    

    4.2スーパーパラメータの設定
    #         (                
     
    BATCH_SIZE = 64  #            ,              
     
    EPOCHS = 3  #          
     
    #  torch      GPU,    GPU  ,      
    DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
     
    learning_rate = 0.001  #         
    

    4.3データセットのロード
    ここではdataloader反復器を使用してデータセットをロードします
    #      
    train_loader = torch.utils.data.DataLoader(
        datasets.MNIST('data', train=True, download=True,
                       transform=transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize(mean=(0.5,), std=(0.5,))  #           
                       ])),
        batch_size=BATCH_SIZE, shuffle=True)  #       ,  ,           。
     
    test_loader = torch.utils.data.DataLoader(
        datasets.MNIST('data', train=False, transform=transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize((0.5,), (0.5,))
        ])),
        batch_size=BATCH_SIZE, shuffle=True)
    

    上記のコードの役割は、次のとおりです.
  • mnistトレーニングセットとテストセットをフォルダdataの
  • にダウンロード
  • は、tensorデータ型への変換を含むデータを変化させ、トレーニングセットのテストセットの独立した同分布を保証するために、データを正規分布
  • に正規化する.
  • データは一括して保存され、順序が乱れ、後続の訓練が便利である.

  • 4.4ネットワーク構造の設計
    単純なボリュームニューラルネットワークの構造であり、一般的には:
  • 畳み込み層Conv:畳み込みコアにより画像特徴を抽出し、feature map
  • を得る.
  • プール化層Pool:ボリュームチェックを利用してfeature mapをダウンサンプリングし、サイズを減らす.最大プール化層はスライドウィンドウ内の最大画素であり、平均プール化層はスライドウィンドウ内の平均画素結果である.
  • フル接続レイヤ:複数のlinear model+アクティブ化関数eg:ReLU.これで基本的なCNNが構成されていますが、私たちは勉強が好きな心理状態から、モデルの汎化能力を高めるために、深い学習訓練過程のtricksを理解したほうがいいです.
  • batch normalization:簡単に言えば、前のレイヤの重み付け合計のすべての出力結果を一括正規化(標準正規分布)し、線形モデルを入力してアクティブ化関数に接続します.
  • DropOut:全接続層では、確率を設定してランダムにこの層のいくつかの重みを0にし、ニューロンが無効になることに相当します.
  •  
    #     
    class ConvNet(nn.Module):
        def __init__(self):
            super(ConvNet, self).__init__()
            #      
            self.features = nn.Sequential(
                #    
                #         1,           ,    
                #      32(    32    ),                
                #    kernel_size     3 * 3,stride                1
                # padding   , 1              
                nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1, padding=1),# ((28-3+2*1)/1)+1=28  28*28*1  》 28*28*32
     
                #      ,     out_channels    ,                
                nn.BatchNorm2d(num_features=32),   #28*28*32  》 28*28*32
     
                #     ,inplace=true        
                nn.ReLU(inplace=True),
                nn.Conv2d(32, 32, kernel_size=3, stride=1, padding=1),   #  ((28-3+2*1)/1)+1=28     28*28*32 》 28*28*32
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
     
                #      
                # kernel_size  2 * 2     
                # stride 2,         2   
                #      ,       1/4,  28 * 28 -》 7 * 7
                nn.MaxPool2d(kernel_size=2, stride=2),
                nn.Conv2d(32, 64, kernel_size=3, padding=1),
                nn.BatchNorm2d(64),
                nn.ReLU(inplace=True),
                nn.Conv2d(64, 64, kernel_size=3, padding=1),
                nn.BatchNorm2d(64),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2, stride=2)
            )
            #    
            self.classifier = nn.Sequential(
                # Dropout 
                # p = 0.5           0.5     0
                nn.Dropout(p=0.5),
                #       64 *     7 * 7,     512     
                nn.Linear(64 * 7 * 7, 512),
                nn.BatchNorm1d(512),
                nn.ReLU(inplace=True),
                nn.Dropout(p=0.5),
                nn.Linear(512, 512),
                nn.BatchNorm1d(512),
                nn.ReLU(inplace=True),
                nn.Dropout(p=0.5),
                nn.Linear(512, 10),
            )
        #           
        def forward(self, x):
            #        
            x = self.features(x)
            #              
            x = x.view(x.size(0), -1)
            x = self.classifier(x)
            return x
    

    4.5訓練前準備
    #               GPU  CPU
     
    ConvModel = ConvNet().to(DEVICE)
    #          
    criterion = nn.CrossEntropyLoss().to(DEVICE)
    #        :      ,       
    optimizer = torch.optim.Adam(ConvModel.parameters(), lr=learning_rate)
    #         :       ,         step_size,gamma        
    exp_lr_scheduler = lr_scheduler.StepLR(optimizer, step_size=6, gamma=0.1)
    #        。       lr = 0.05,    step_size 30,      gamma=0.01
    # Assuming optimizer uses lr = 0.05 for all groups
    # >>> # lr = 0.05     if epoch < 30
    # >>> # lr = 0.005    if 30 <= epoch < 60
    # >>> # lr = 0.0005   if 60 <= epoch < 90
    

    4.6訓練
    def train(num_epochs, _model, _device, _train_loader, _optimizer, _lr_scheduler):
        _model.train()  #          
        _lr_scheduler.step() #               
        for epoch in range(num_epochs):
            #            
            for i, (images, labels) in enumerate(_train_loader):
                samples = images.to(_device)
                labels = labels.to(_device)
                #          , CNN    ,          ,
                # reshape   -1              n
                #   reshape       n   ,           28 * 28,      
                output = _model(samples.reshape(-1, 1, 28, 28))
                #        
                loss = criterion(output, labels)
                #              0
                optimizer.zero_grad()
                #        
                loss.backward()
                #       
                optimizer.step()
                if (i + 1) % 100 == 0:
                    print("Epoch:{}/{}, step:{}, loss:{:.4f}".format(epoch + 1, num_epochs, i + 1, loss.item()))
    

    4.7予測
    def test(_test_loader, _model, _device):
        _model.eval()  #            evaluation
        loss = 0
        correct = 0
     
        with torch.no_grad():  #       backward    ,          ,           。
            for data, target in _test_loader:
                data, target = data.to(_device), target.to(_device)
                output = ConvModel(data.reshape(-1, 1, 28, 28))
                loss += criterion(output, target).item()  #      
                pred = output.data.max(1, keepdim=True)[1]  #          ,    
                correct += pred.eq(target.data.view_as(pred)).cpu().sum()  # .cpu()       cpu  。
     
        loss /= len(_test_loader.dataset)
     
        print('
    Average loss: {:.4f}, Accuracy: {}/{} ({:.3f}%)
    '
    .format( loss, correct, len(_test_loader.dataset), 100. * correct / len(_test_loader.dataset)))

    4.8運転
    for epoch in range(1, EPOCHS + 1):
        train(epoch, ConvModel, DEVICE, train_loader, optimizer, exp_lr_scheduler)
        test(test_loader,ConvModel, DEVICE)
        test(train_loader,ConvModel, DEVICE)
    

    5結果
    用のpytorch=0.4 CPUで走る
    Epoch:1/1, step:100, loss:0.1579
    Epoch:1/1, step:200, loss:0.0809
    Epoch:1/1, step:300, loss:0.0673
    Epoch:1/1, step:400, loss:0.1391
    Epoch:1/1, step:500, loss:0.0323
    Epoch:1/1, step:600, loss:0.0870
    Epoch:1/1, step:700, loss:0.0441
    Epoch:1/1, step:800, loss:0.0705
    Epoch:1/1, step:900, loss:0.0396
     
    Average loss: 0.0006, Accuracy: 9881/10000 (98.000%)
     
    Epoch:1/2, step:100, loss:0.0487
    Epoch:1/2, step:200, loss:0.1519
    Epoch:1/2, step:300, loss:0.0262
    Epoch:1/2, step:400, loss:0.2133
    Epoch:1/2, step:500, loss:0.0161
    Epoch:1/2, step:600, loss:0.0805
    Epoch:1/2, step:700, loss:0.0927
    Epoch:1/2, step:800, loss:0.0663
    Epoch:1/2, step:900, loss:0.0669
    Epoch:2/2, step:100, loss:0.0124
    Epoch:2/2, step:200, loss:0.0527
    Epoch:2/2, step:300, loss:0.0256
    Epoch:2/2, step:400, loss:0.0138
    Epoch:2/2, step:500, loss:0.0894
    Epoch:2/2, step:600, loss:0.1030
    Epoch:2/2, step:700, loss:0.0528
    Epoch:2/2, step:800, loss:0.1106
    Epoch:2/2, step:900, loss:0.0044
     
    Average loss: 0.0003, Accuracy: 9930/10000 (99.000%)