LoginSignup
2
3

More than 3 years have passed since last update.

機械学習初心者がPytorchチュートリアルを改造しまくってCIFAR10の精度をあげる

Last updated at Posted at 2019-06-08

参考にしたのは

にあるCIFAR10の分類器のトレーニングからベースとなるコードをコピーしました。
チュートリアルでは

入力層
conv層 2層
fc 3層
出力層

という構造になっているものからいじっていったものを説明して行こうと思います

1 data augmentation

Cifar10のような少ない(?)データセットではdata augmentationが効くらしいです。

transform = transforms.Compose(
[transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

transforms.RandomHorizontalFlip()を加えた。これはランダムに(多分バッチごとに)画像を左右反転にさせる前処理となります。

おまじないのように書いていたtransdorms.Composeですが、
どうやらデータの前処理をまとめてくれるようで結構便利そうだと感じました。

2 network構造

class Net(nn.Module):
  def __init__(self):
    super(Net, self).__init__()
    self.conv1 = nn.Conv2d(3, 64, 3) 
    self.bn1 = nn.BatchNorm2d(64)
    self.conv2 = nn.Conv2d(64, 64, 3) 
    self.conv3 = nn.Conv2d(64, 64, 3) 
    self.do1 = nn.Dropout2d(p=0.3)
    self.pool = nn.MaxPool2d(2, 2)  
    self.conv4 = nn.Conv2d(64, 128, 3) 
    self.bn2 = nn.BatchNorm2d(128)
    self.conv5 = nn.Conv2d(128, 128, 3) 
    self.conv6 = nn.Conv2d(128, 128, 3)
    #self.pool = nn.Maxpool2d(2,2) 
    self.conv7 = nn.Conv2d(128, 256, 3) 

    self.conv8 = nn.Conv2d(256, 256, 3) 
    self.conv9 = nn.Conv2d(256, 256, 3) 
    #self.pool = nn.Maxpool2d(2,2) 
    self.conv10 = nn.Conv2d(256,100,1)
    self.bn3 = nn.BatchNorm2d(256)
    self.conv11 = nn.Conv2d(100, 10, 4)
    self.zeropad = nn.ConstantPad2d(1, 0)

  def forward(self, x):
    x = F.relu(self.conv1(self.zeropad(x)))#32*32
    x = self.bn1(x)
    x = F.relu(self.conv2(self.zeropad(x)))
    x = self.do1(x)
    x = self.pool(F.relu(self.conv3(self.zeropad(x))))#16*16
    x = F.relu(self.conv4(self.zeropad(x)))
    x = self.bn2(x)
    x = self.do1(x)
    x = F.relu(self.conv5(self.zeropad(x)))
    x = self.pool(F.relu(self.conv6(self.zeropad(x))))#8*8
    x = F.relu(self.conv7(self.zeropad(x)))
    x = self.bn3(x)
    x = self.do1(x)
    x = F.relu(self.conv8(self.zeropad(x)))
    x = self.pool(F.relu(self.conv9(self.zeropad(x))))#4*4
    x = self.bn3(x)
    x = self.do1(x)
    x = F.relu(self.conv10(x))
    x = self.conv11(x)
    x = x.view(-1, 10)

    return x

(書いてから思ったんだが、conv層って同じだったらこんなに定義しなくてもよいのでは...)

とりあえず深くして、畳み込み層を増やしてみた形です。
val lossを確認しながら、各パラメータを調整しました

3 dropout層とBatchNorm層の追加

やってみるとiteration=30くらいで激しく過学習を起こしていることがわかりました。
そこで、Dropout層をいくつか追加しました。

また、深くするにつれ、1 iter目から学習が進まなくなりましたので、
BatchNorm層を追加すると学習が進むようになりました(batchnormすげぇ。。。)

4 GPU のおまじない

device = 'cuda' if torch.cuda.is_available() else 'cpu'
net = Net()
net = net.to(device)
if device == 'cuda':
    net = torch.nn.DataParallel(net)
    cudnn.benchmark = True

Colabでやってますが、GPUでないと時間がすごくかかります。

5 optimizerとscheduler

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr = 0.01, momentum=0.9)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)

optimizerにmomentumを追加
また、schedulerを用いて10epochが進むごとに学習率が半分になるようにしました。


精度をあげるためにしたのはこんなところです。

以下パラメータ数
| ---------------------------------------------------------------- |
|:--|
| Layer (type) Output Shape Param # |
| ================================================================ |
| ConstantPad2d-1 [-1, 3, 34, 34] 0 |
| Conv2d-2 [-1, 64, 32, 32] 1,792 |
| BatchNorm2d-3 [-1, 64, 32, 32] 128 |
| ConstantPad2d-4 [-1, 64, 34, 34] 0 |
| Conv2d-5 [-1, 64, 32, 32] 36,928 |
| Dropout2d-6 [-1, 64, 32, 32] 0 |
| ConstantPad2d-7 [-1, 64, 34, 34] 0 |
| Conv2d-8 [-1, 64, 32, 32] 36,928 |
| MaxPool2d-9 [-1, 64, 16, 16] 0 |
| ConstantPad2d-10 [-1, 64, 18, 18] 0 |
| Conv2d-11 [-1, 128, 16, 16] 73,856 |
| BatchNorm2d-12 [-1, 128, 16, 16] 256 |
| Dropout2d-13 [-1, 128, 16, 16] 0 |
| ConstantPad2d-14 [-1, 128, 18, 18] 0 |
| Conv2d-15 [-1, 128, 16, 16] 147,584 |
| ConstantPad2d-16 [-1, 128, 18, 18] 0 |
| Conv2d-17 [-1, 128, 16, 16] 147,584 |
| MaxPool2d-18 [-1, 128, 8, 8] 0 |
| ConstantPad2d-19 [-1, 128, 10, 10] 0 |
| Conv2d-20 [-1, 256, 8, 8] 295,168 |
| Dropout2d-21 [-1, 256, 8, 8] 0 |
| ConstantPad2d-22 [-1, 256, 10, 10] 0 |
| Conv2d-23 [-1, 256, 8, 8] 590,080 |
| ConstantPad2d-24 [-1, 256, 10, 10] 0 |
| Conv2d-25 [-1, 256, 8, 8] 590,080 |
| MaxPool2d-26 [-1, 256, 4, 4] 0 |
| BatchNorm2d-27 [-1, 256, 4, 4] 512 |
| Dropout2d-28 [-1, 256, 4, 4] 0 |
| Conv2d-29 [-1, 100, 4, 4] 25,700 |
| Conv2d-30 [-1, 10, 1, 1] 16,010 |
| Net-31 [-1, 10] 0 |
| ================================================================|
| Total params: 1,962,606 |
| Trainable params: 1,962,606 |
| Non-trainable params: 0 |
| ----------------------------------------------------------------|
| Input size (MB): 0.01 |
| Forward/backward pass size (MB): 6.98 |
| Params size (MB): 7.49 |
| Estimated Total Size (MB): 14.48 |
| ----------------------------------------------------------------|


87%まで出ているコードは
https://github.com/daikiclimate/CIFAR10
に載っています。


https://qiita.com/koshian2/items/e66a7ee9bf60ca24c940
よりも少ないパラメータで90%達成したいです。

2
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3