[闘鶏眼]闘鶏眼でCNNモードを実現しましょう!(VGGNet編)


こんにちは!今日の位置づけから次の位置づけまで、CNNモデルの骨格となるモデルVGNET、GoogleNet、ResNetを紹介し、それを実装します.)今回のポスターはVGGNetに関する記事です.
まずILSVRC (Imagenet Large Scale Visual Recognition Challenges)という大会で、この大会は巨大な画像を1000個のサブ画像に分割することを目的としている.次の図はCNN構造の大衆化をリードするベンチャー企業のモデルたちで、AlexNet(2012)-VGGnet(2014)-GogleeNet(2014)-resNet(2015)の順だ.

Source : https://icml.cc/2016/tutorials/
上の図では、layersはCNN layerの個数(深さ)を表していますが、直感的な理解のために下図を描きました.

VGGNetの概要


紹介する


本稿のトピックは、大規模な画像認識のためのVery deepボリュームネットワークです.次のリンクにアクセスしてください.リンク

モデル性能に及ぼすニューラルネットワークの深さの影響を調べるため,VGGSETは対応する研究を開始し,これを実証するために3×3畳み込みDeep CNnsを用いることを提案した.ILSVVRC-2014大会ではVGNETがGoogle LeNetで2位だったが、Google LeNetよりも構造が簡単なため、1位機種よりも使用範囲が広い.

じっけんせっけい


モデルは3つの演算のみを含む:3 x 3ボリューム、Maxプール、および全接続ネットワーク、およびA、A−LRN、B、C、D、およびEの5つのモデルを下図に示すように実験した.

使用する各window sizeとactivation functionの設定は以下の通りです.
  • 3x3 convolution filters (stride: 1)
  • 2x2 Max pooling (stride : 2)
  • Activation function : ReLU
  • 📢 ここで待って!
    上の表のconv 3-64は、使用するウィンドウ数が64個、ウィンドウサイズが3 x 3であることを示しています.

    パフォーマンス:


    以下の性能表により,モデルの性能は深さが増すほど良くなり,「局所応答正常化」(Local Response Normalization,LR)は性能に大きな影響を及ぼさないことが分かった.

    VGGNETの実装


    VGNETの概要を理解した以上、今からそれを実施しましょうか.上記実験設計表におけるD列の設定を実施した.次の行は、この構造を再度説明します.
  • 3 x 3合成乗算x 2(チャネル64)
  • 3 x 3合成乗算x 2(チャネル128)
  • 3 x 3合成乗算x 3(256チャネル)
  • 3 x 3合成乗算x 3(チャネル512)
  • 3 x 3合成乗算x 3(チャネル512)
  • FC layer x3
    - FC layer 4096
  • FC layer 4096
  • FC layer 1000

  • 符号化を容易にするために,2つのconv layerのblockと3つのblockをそれぞれ宣言する.

    conv_2_block

    def conv_2_block(in_dim,out_dim):
        model = nn.Sequential(
            nn.Conv2d(in_dim,out_dim,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.Conv2d(out_dim,out_dim,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2,2)
        )
        return model

    conv_3_block

    def conv_3_block(in_dim,out_dim):
        model = nn.Sequential(
            nn.Conv2d(in_dim,out_dim,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.Conv2d(out_dim,out_dim,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.Conv2d(out_dim,out_dim,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2,2)
        )
        return model

    Define VGG16

    class VGG(nn.Module):
        def __init__(self, base_dim, num_classes=10):
            super(VGG, self).__init__()
            self.feature = nn.Sequential(
                conv_2_block(3,base_dim), #64
                conv_2_block(base_dim,2*base_dim), #128
                conv_3_block(2*base_dim,4*base_dim), #256
                conv_3_block(4*base_dim,8*base_dim), #512
                conv_3_block(8*base_dim,8*base_dim), #512        
            )
            self.fc_layer = nn.Sequential(
                # CIFAR10은 크기가 32x32이므로 
                nn.Linear(8*base_dim*1*1, 4096),
                # IMAGENET이면 224x224이므로
                # nn.Linear(8*base_dim*7*7, 4096),
                nn.ReLU(True),
                nn.Dropout(),
                nn.Linear(4096, 1000),
                nn.ReLU(True),
                nn.Dropout(),
                nn.Linear(1000, num_classes),
            )
    
        def forward(self, x):
            x = self.feature(x)
            #print(x.shape)
            x = x.view(x.size(0), -1)
            #print(x.shape)
            x = self.fc_layer(x)
            return x

    モデル、ロス、オプティマイザ宣言

    # device 설정
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
    # VGG 클래스를 인스턴스화
    model = VGG(base_dim=64).to(device)
    
    # 손실함수 및 최적화함수 설정
    loss_func = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

    load CIFAR10 dataset


  • CIFAR 10は、「飛行機」「自動車」「鳥」「猫」「鹿」「犬」「カエル」「馬」「船」「トラック」の10種類からなるデータセットです.

  • CIFAR 10は、3x32x32ピクセルサイズの画像が3チャンネルの色からなることを意味する32x32ピクセルサイズの画像を含む.
  • TRAIN/TESTデータセットの定義
    import torchvision
    import torchvision.datasets as datasets
    import torchvision.transforms as transforms
    from torch.utils.data import DataLoader
    
    # Transform 정의
    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
    
    # CIFAR10 TRAIN 데이터 정의
    cifar10_train = datasets.CIFAR10(root="../Data/", train=True, transform=transform, target_transform=None, download=True)
    
    # CIFAR10 TEST 데이터 정의
    cifar10_test = datasets.CIFAR10(root="../Data/", train=False, transform=transform, target_transform=None, download=True)
    
    classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    
    TRAINデータセットの表示
    import matplotlib.pyplot as plt
    import numpy as np
    
    # 이미지를 보여주기 위한 함수
    
    def imshow(img):
        img = img / 2 + 0.5     # unnormalize
        npimg = img.numpy()
        plt.imshow(np.transpose(npimg, (1, 2, 0)))
        plt.show()
    
    
    # 학습용 이미지를 무작위로 가져오기
    dataiter = iter(train_loader)
    images, labels = dataiter.next()
    
    # 이미지 보여주기
    imshow(torchvision.utils.make_grid(images))
    
    # 정답(label) 출력
    print(' '.join('%5s' % classes[labels[j]] for j in range(batch_size)))
    Source : https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

    TRAIN & TEST


    データセットが定義されました.正式に学習と検証を開始しましょう.学習設定は次のように定義されます.
    batch_size = 100
    learning_rate = 0.0002
    num_epoch = 100
    TRAIN
    loss_arr = []
    for i in trange(num_epoch):
        for j,[image,label] in enumerate(train_loader):
            x = image.to(device)
            y_= label.to(device)
            
            optimizer.zero_grad()
            output = model.forward(x)
            loss = loss_func(output,y_)
            loss.backward()
            optimizer.step()
    
        if i % 10 ==0:
            print(loss)
            loss_arr.append(loss.cpu().detach().numpy())
    非表示の表示
    plt.plot(loss_arr)
    plt.show()

    テスト結果
    # 맞은 개수, 전체 개수를 저장할 변수를 지정합니다.
    correct = 0
    total = 0
    
    model.eval()
    
    # 인퍼런스 모드를 위해 no_grad 해줍니다.
    with torch.no_grad():
        # 테스트로더에서 이미지와 정답을 불러옵니다.
        for image,label in test_loader:
            
            # 두 데이터 모두 장치에 올립니다.
            x = image.to(device)
            y= label.to(device)
    
            # 모델에 데이터를 넣고 결과값을 얻습니다.
            output = model.forward(x)
            _,output_index = torch.max(output,1)
    
            
            # 전체 개수 += 라벨의 개수
            total += label.size(0)
            correct += (output_index == y).sum().float()
        
        # 정확도 도출
        print("Accuracy of Test Data: {}%".format(100*correct/total))
    Accuracy of Test Data: 82.33999633789062%
    長い文章読んでくれてありがとう^~^