【Python初学者】画像処理クラス分類の精度・正解率（accuracy）を向上するには。【FashionMNIST】

##はじめに
この記事の対象者は「python初学者」「機械学習初学者」です。
つまり私です。

##今回の例
今回は「**FashionMNIST**」のデータセットを用いて学習し
テストデータに対するクラス分類の**正解率 90% 以上**を目指します。

以下のように準備しました。

①訓練データ

```
torchvision.datasets.FashionMNIST(
    root="datasets", train=True, transform=transform, download=True
)
```
②テストデータ

```
torchvision.datasets.FashionMNIST(
    root="datasets", train=False, transform=transform, download=True
)
```
テストデータは`train=False`としています。


##画像処理のネットワーク構築（改善前）

```
class Net(pl.LightningModule):

    def __init__(self):
        super().__init__()

        self.conv = nn.Conv2d(in_channels=1, out_channels=3, kernel_size=3, padding=1)
        self.bn = nn.BatchNorm2d(3)
        self.fc = nn.Linear(14*14*3, 10)


    def forward(self, x):
        h = self.conv(x)
        h = F.relu(h)
        h = self.bn(h)
        h = F.max_pool2d(h, kernel_size=2, stride=2)
        h = h.view(-1, 14*14*3)
        h = self.fc(h)
        return h


    def training_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log('train_loss', loss, on_step=True, on_epoch=True, prog_bar=True)
        self.log('train_acc', accuracy(y.softmax(dim=-1), t), on_step=True, on_epoch=True, prog_bar=True)
        return loss


    def validation_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log('val_loss', loss, on_step=False, on_epoch=True)
        self.log('val_acc', accuracy(y.softmax(dim=-1), t), on_step=False, on_epoch=True)
        return loss


    def test_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log('test_loss', loss, on_step=False, on_epoch=True)
        self.log('test_acc', accuracy(y.softmax(dim=-1), t), on_step=False, on_epoch=True)
        return loss


    def configure_optimizers(self):
        optimizer = torch.optim.SGD(self.parameters(), lr=0.01)
        return optimizer
```
以上を`max_epochs=20`で学習し
テストデータで検証したところ

結果は、正解率：約85%でした。
まだまだでした。


##画像処理のネットワーク構築（★改善後）

```
（#★は改善したところ）

class Net(pl.LightningModule):

    def __init__(self):
        super().__init__()
　　　　　　　　　　　　　　　　　　　　　　　　　　
        self.conv = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1, padding=1)                                    #★out_channel=3→32に！
        self.bn = nn.BatchNorm2d(32) 　　　　 #★3→32に！
        self.fc1 = nn.Linear(14*14*32, 300)　 #★中間層を作る！！！
        self.fc2 = nn.Linear(300, 10)


    def forward(self, x):
        h = self.conv(x)
        h = self.bn(h)
        h = F.relu(h)　　　#★位置をself.bn(h)と上下入れ替え
        h = F.max_pool2d(h, kernel_size=2, stride=2)
        h = h.view(-1, 14*14*32)
        h = self.fc1(h)　　#★中間層
        h = F.relu(h)　　　#★relu関数を通す！
        h = self.fc2(h)
        return h


    def training_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log('train_loss', loss, on_step=True, on_epoch=True, prog_bar=True)
        self.log('train_acc', accuracy(y.softmax(dim=-1), t), on_step=True, on_epoch=True, prog_bar=True)
        return loss


    def validation_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log('val_loss', loss, on_step=False, on_epoch=True)
        self.log('val_acc', accuracy(y.softmax(dim=-1), t), on_step=False, on_epoch=True)
        return loss


    def test_step(self, batch, batch_idx):
        x, t = batch
        y = self(x)
        loss = F.cross_entropy(y, t)
        self.log('test_loss', loss, on_step=False, on_epoch=True)
        self.log('test_acc', accuracy(y.softmax(dim=-1), t), on_step=False, on_epoch=True)
        return loss


    def configure_optimizers(self):
        optimizer = torch.optim.Adam(self.parameters(), lr=0.001) #★SGD→ADM、lrを0.001に！
        return optimizer
```
以上を
前回`max_epochs=20`→`max_epochs=30`に増やし
て学習し、テストデータで検証したところ

結果は、正解率：**約91.5%**という結果が得られました！

これで目標の90%を超えることができました！

##おわりに

画像処理のクラス分類の精度をあげるには、
ネットワークの中間層のout_channnelのようなノード数を調整を行ったり
optimizer（最適化手法）を色々と変えてみるのも
有効なのだと理解しました。

今後、別の課題を処理する場合は
データに合わせて違う調整をする必要があると思いますが、
ある程度人間側の経験に基づいて行うことになるのかな
とも思いました。