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

参考にしたのは

https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py

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

入力層
conv層　２層
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%達成したいです。