[Python pyg] TransformerConvを用いたMNISTの分類

# 1. TransformerConvを用いてMNISTを分類してみる

Pytorch_Geometricを用いてMNISTを分類してみました。
よければ参考にしてください。

```mnistClassification.py
import torch
import pickle
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

from torch_geometric.data import Data
from torch_geometric.loader import DataLoader
from torch_geometric.nn import Linear, TransformerConv
from torch_geometric.datasets import MNISTSuperpixels

from sklearn.metrics import accuracy_score
from torch_geometric.nn import global_mean_pool

seed = 0
np.random.seed(seed)
torch.manual_seed(seed)

class Net(torch.nn.Module):
    def __init__(self, hid1, hid2):
        super(Net, self).__init__()
        
        self.conv1 = TransformerConv(3, hid1)
        self.conv2 = TransformerConv(hid1, hid2)
        self.lin = Linear(hid2, 10)

    def forward(self, data):
        x, edge_index, batch = data.x, data.edge_index,  data.batch
        
        # ノードの特徴量xとノードの位置情報posを結合する
        x = torch.cat((x, data.pos), dim=1)
        
        x = self.conv1(x, edge_index)
        x = x.relu()
        x = self.conv2(x, edge_index)

        x = global_mean_pool(x, batch)
        
        x = F.dropout(x)
        x = self.lin(x)
        
        return x

hid1 = 32
hid2 = 16

data_size = 3200
batch_size = 64

# MNISTデータセット取得
dataset = MNISTSuperpixels(
    root="./data",
    train=True
)

print(f"len(dataset): {len(dataset)}")
print(f"dataset[0]: {dataset[0]}")

# 訓練データとテストデータの分割
train_loader = DataLoader(
    dataset=dataset[:data_size],
    batch_size=batch_size,
    shuffle=False
)
test_loader = DataLoader(
    dataset=dataset[data_size:data_size + 128],
    batch_size=1,
    shuffle=False
)

print("train_size:", len(train_loader))
print("test_size", len(test_loader))

# モデル呼び出し
model = Net(hid1, hid2)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 予測結果の格納用リスト
pred_list = np.array([])

print("\n学習開始")
model.train()
for epoch in range(100):
    for i, d in enumerate(train_loader):
        optimizer.zero_grad()
        out = model(d)
        loss = criterion(out, d.y)
        loss.backward()
        optimizer.step()
    
    print(f'train || epoch: {epoch+1} | Loss: {round(loss.item(), 5)}')

path_file = "./model/mnistClassificationModel.pkl"
pickle.dump(model, open(path_file, 'wb'))

print("\n検証開始")
model.eval()
for k, data in enumerate(test_loader):
    pred = model(data).argmax(dim=1)
    
    print(f'test: {k}番目 || 予測: {pred.item()} | 正解: {data.y.item()}')
    
    pred_list = np.append(pred_list, accuracy_score(pred, data.y))

print(f"\naccuracy_rate: {round(np.mean(pred_list), 5)}\n")
```

## 1-1. 実行してみる

<details><summary>コンソール結果</summary><div>

```
$ python mnistClassification.py

len(dataset): 60000
dataset[0]: Data(x=[75, 1], edge_index=[2, 1399], y=[1], pos=[75, 2])
train_size: 50
test_size 128

学習開始
train || epoch: 1 | Loss: 2.33488
train || epoch: 2 | Loss: 2.34369
train || epoch: 3 | Loss: 2.31591
train || epoch: 4 | Loss: 2.33647
train || epoch: 5 | Loss: 2.3193
train || epoch: 6 | Loss: 2.26698
train || epoch: 7 | Loss: 2.20072
train || epoch: 8 | Loss: 2.07612
train || epoch: 9 | Loss: 1.90644
train || epoch: 10 | Loss: 1.81442
train || epoch: 11 | Loss: 1.80464
train || epoch: 12 | Loss: 1.78072
train || epoch: 13 | Loss: 1.73206
train || epoch: 14 | Loss: 1.64946
train || epoch: 15 | Loss: 1.52958
train || epoch: 16 | Loss: 1.69794
train || epoch: 17 | Loss: 1.53447
train || epoch: 18 | Loss: 1.58224
train || epoch: 19 | Loss: 1.40572
train || epoch: 20 | Loss: 1.4548
train || epoch: 21 | Loss: 1.55386
train || epoch: 22 | Loss: 1.38888
train || epoch: 23 | Loss: 1.53538
train || epoch: 24 | Loss: 1.54074
train || epoch: 25 | Loss: 1.18985
train || epoch: 26 | Loss: 1.52624
train || epoch: 27 | Loss: 1.36777
train || epoch: 28 | Loss: 1.32414
train || epoch: 29 | Loss: 1.40242
train || epoch: 30 | Loss: 1.35917
train || epoch: 31 | Loss: 1.22846
train || epoch: 32 | Loss: 1.49594
train || epoch: 33 | Loss: 1.24816
train || epoch: 34 | Loss: 1.26932
train || epoch: 35 | Loss: 1.20363
train || epoch: 36 | Loss: 1.18598
train || epoch: 37 | Loss: 1.37455
train || epoch: 38 | Loss: 1.26109
train || epoch: 39 | Loss: 1.31707
train || epoch: 40 | Loss: 1.37859
train || epoch: 41 | Loss: 1.18632
train || epoch: 42 | Loss: 1.19362
train || epoch: 43 | Loss: 1.27971
train || epoch: 44 | Loss: 1.0987
train || epoch: 45 | Loss: 1.43908
train || epoch: 46 | Loss: 1.207
train || epoch: 47 | Loss: 1.16193
train || epoch: 48 | Loss: 1.10968
train || epoch: 49 | Loss: 1.03804
train || epoch: 50 | Loss: 1.12924
train || epoch: 51 | Loss: 1.11143
train || epoch: 52 | Loss: 1.14482
train || epoch: 53 | Loss: 1.25098
train || epoch: 54 | Loss: 1.27033
train || epoch: 55 | Loss: 1.1975
train || epoch: 56 | Loss: 1.21743
train || epoch: 57 | Loss: 1.10605
train || epoch: 58 | Loss: 1.18476
train || epoch: 59 | Loss: 1.16106
train || epoch: 60 | Loss: 1.12857
train || epoch: 61 | Loss: 1.12722
train || epoch: 62 | Loss: 1.47715
train || epoch: 63 | Loss: 1.12729
train || epoch: 64 | Loss: 1.06766
train || epoch: 65 | Loss: 0.9067
train || epoch: 66 | Loss: 1.19369
train || epoch: 67 | Loss: 1.11482
train || epoch: 68 | Loss: 1.14615
train || epoch: 69 | Loss: 1.05891
train || epoch: 70 | Loss: 1.0601
train || epoch: 71 | Loss: 0.987
train || epoch: 72 | Loss: 1.08562
train || epoch: 73 | Loss: 1.15782
train || epoch: 74 | Loss: 1.12615
train || epoch: 75 | Loss: 1.1964
train || epoch: 76 | Loss: 1.01085
train || epoch: 77 | Loss: 1.15968
train || epoch: 78 | Loss: 1.04715
train || epoch: 79 | Loss: 1.01706
train || epoch: 80 | Loss: 1.26346
train || epoch: 81 | Loss: 1.20232
train || epoch: 82 | Loss: 0.83773
train || epoch: 83 | Loss: 1.00814
train || epoch: 84 | Loss: 1.01452
train || epoch: 85 | Loss: 0.90068
train || epoch: 86 | Loss: 1.03064
train || epoch: 87 | Loss: 1.00292
train || epoch: 88 | Loss: 1.22165
train || epoch: 89 | Loss: 1.14631
train || epoch: 90 | Loss: 1.1025
train || epoch: 91 | Loss: 1.20301
train || epoch: 92 | Loss: 1.08872
train || epoch: 93 | Loss: 1.14535
train || epoch: 94 | Loss: 1.23129
train || epoch: 95 | Loss: 0.9997
train || epoch: 96 | Loss: 1.06955
train || epoch: 97 | Loss: 0.99494
train || epoch: 98 | Loss: 1.15878
train || epoch: 99 | Loss: 1.29191
train || epoch: 100 | Loss: 1.12133

検証開始
test: 0番目 || 予測: 2 | 正解: 2
test: 1番目 || 予測: 2 | 正解: 3
test: 2番目 || 予測: 9 | 正解: 9
test: 3番目 || 予測: 4 | 正解: 4
test: 4番目 || 予測: 3 | 正解: 5
test: 5番目 || 予測: 2 | 正解: 5
test: 6番目 || 予測: 9 | 正解: 7
test: 7番目 || 予測: 6 | 正解: 6
test: 8番目 || 予測: 3 | 正解: 2
test: 9番目 || 予測: 7 | 正解: 7
test: 10番目 || 予測: 7 | 正解: 7
test: 11番目 || 予測: 6 | 正解: 8
test: 12番目 || 予測: 1 | 正解: 1
test: 13番目 || 予測: 0 | 正解: 0
test: 14番目 || 予測: 7 | 正解: 7
test: 15番目 || 予測: 2 | 正解: 3
test: 16番目 || 予測: 2 | 正解: 5
test: 17番目 || 予測: 4 | 正解: 4
test: 18番目 || 予測: 2 | 正解: 4
test: 19番目 || 予測: 8 | 正解: 5
test: 20番目 || 予測: 2 | 正解: 3
test: 21番目 || 予測: 6 | 正解: 6
test: 22番目 || 予測: 4 | 正解: 4
test: 23番目 || 予測: 7 | 正解: 7
test: 24番目 || 予測: 2 | 正解: 2
test: 25番目 || 予測: 6 | 正解: 8
test: 26番目 || 予測: 1 | 正解: 1
test: 27番目 || 予測: 9 | 正解: 9
test: 28番目 || 予測: 7 | 正解: 7
test: 29番目 || 予測: 6 | 正解: 6
test: 30番目 || 予測: 1 | 正解: 1
test: 31番目 || 予測: 2 | 正解: 0
test: 32番目 || 予測: 4 | 正解: 9
test: 33番目 || 予測: 3 | 正解: 3
test: 34番目 || 予測: 6 | 正解: 1
test: 35番目 || 予測: 4 | 正解: 4
test: 36番目 || 予測: 7 | 正解: 7
test: 37番目 || 予測: 1 | 正解: 1
test: 38番目 || 予測: 4 | 正解: 9
test: 39番目 || 予測: 4 | 正解: 4
test: 40番目 || 予測: 4 | 正解: 4
test: 41番目 || 予測: 5 | 正解: 0
test: 42番目 || 予測: 2 | 正解: 2
test: 43番目 || 予測: 6 | 正解: 8
test: 44番目 || 予測: 2 | 正解: 2
test: 45番目 || 予測: 6 | 正解: 6
test: 46番目 || 予測: 7 | 正解: 7
test: 47番目 || 予測: 0 | 正解: 0
test: 48番目 || 予測: 0 | 正解: 0
test: 49番目 || 予測: 1 | 正解: 7
test: 50番目 || 予測: 9 | 正解: 7
test: 51番目 || 予測: 2 | 正解: 8
test: 52番目 || 予測: 9 | 正解: 7
test: 53番目 || 予測: 7 | 正解: 7
test: 54番目 || 予測: 0 | 正解: 8
test: 55番目 || 予測: 1 | 正解: 7
test: 56番目 || 予測: 9 | 正解: 9
test: 57番目 || 予測: 9 | 正解: 9
test: 58番目 || 予測: 3 | 正解: 3
test: 59番目 || 予測: 6 | 正解: 0
test: 60番目 || 予測: 4 | 正解: 4
test: 61番目 || 予測: 9 | 正解: 4
test: 62番目 || 予測: 0 | 正解: 0
test: 63番目 || 予測: 9 | 正解: 9
test: 64番目 || 予測: 2 | 正解: 3
test: 65番目 || 予測: 9 | 正解: 9
test: 66番目 || 予測: 5 | 正解: 5
test: 67番目 || 予測: 9 | 正解: 7
test: 68番目 || 予測: 1 | 正解: 6
test: 69番目 || 予測: 0 | 正解: 0
test: 70番目 || 予測: 9 | 正解: 7
test: 71番目 || 予測: 5 | 正解: 5
test: 72番目 || 予測: 1 | 正解: 1
test: 73番目 || 予測: 2 | 正解: 8
test: 74番目 || 予測: 2 | 正解: 2
test: 75番目 || 予測: 8 | 正解: 5
test: 76番目 || 予測: 7 | 正解: 7
test: 77番目 || 予測: 9 | 正解: 9
test: 78番目 || 予測: 4 | 正解: 4
test: 79番目 || 予測: 8 | 正解: 8
test: 80番目 || 予測: 4 | 正解: 4
test: 81番目 || 予測: 8 | 正解: 8
test: 82番目 || 予測: 7 | 正解: 7
test: 83番目 || 予測: 7 | 正解: 7
test: 84番目 || 予測: 9 | 正解: 9
test: 85番目 || 予測: 8 | 正解: 5
test: 86番目 || 予測: 0 | 正解: 0
test: 87番目 || 予測: 6 | 正解: 6
test: 88番目 || 予測: 6 | 正解: 6
test: 89番目 || 予測: 5 | 正解: 5
test: 90番目 || 予測: 4 | 正解: 4
test: 91番目 || 予測: 3 | 正解: 3
test: 92番目 || 予測: 9 | 正解: 9
test: 93番目 || 予測: 8 | 正解: 8
test: 94番目 || 予測: 6 | 正解: 6
test: 95番目 || 予測: 1 | 正解: 1
test: 96番目 || 予測: 9 | 正解: 9
test: 97番目 || 予測: 6 | 正解: 6
test: 98番目 || 予測: 7 | 正解: 7
test: 99番目 || 予測: 6 | 正解: 8
test: 100番目 || 予測: 0 | 正解: 2
test: 101番目 || 予測: 2 | 正解: 5
test: 102番目 || 予測: 9 | 正解: 9
test: 103番目 || 予測: 9 | 正解: 9
test: 104番目 || 予測: 8 | 正解: 2
test: 105番目 || 予測: 2 | 正解: 2
test: 106番目 || 予測: 1 | 正解: 1
test: 107番目 || 予測: 2 | 正解: 2
test: 108番目 || 予測: 4 | 正解: 2
test: 109番目 || 予測: 0 | 正解: 0
test: 110番目 || 予測: 9 | 正解: 9
test: 111番目 || 予測: 4 | 正解: 9
test: 112番目 || 予測: 4 | 正解: 4
test: 113番目 || 予測: 2 | 正解: 2
test: 114番目 || 予測: 0 | 正解: 3
test: 115番目 || 予測: 6 | 正解: 4
test: 116番目 || 予測: 4 | 正解: 9
test: 117番目 || 予測: 7 | 正解: 7
test: 118番目 || 予測: 3 | 正解: 3
test: 119番目 || 予測: 2 | 正解: 3
test: 120番目 || 予測: 7 | 正解: 3
test: 121番目 || 予測: 1 | 正解: 1
test: 122番目 || 予測: 9 | 正解: 9
test: 123番目 || 予測: 8 | 正解: 3
test: 124番目 || 予測: 7 | 正解: 7
test: 125番目 || 予測: 6 | 正解: 6
test: 126番目 || 予測: 8 | 正解: 5
test: 127番目 || 予測: 6 | 正解: 6

accuracy_rate: 0.64062
```

</div></details>

# 2. FasionMnistデータセットを用いて分類してみる

次はFasionMnistデータセットを用いて分類してみました。

## 2-1. データセットの前処理

torchvisionのデータセットをPytorch-Geometricで扱えるように前処理を行います。

```create_fasionMnistDataset.py
import torch
import pickle
import torchvision
import torchvision.transforms as transforms

from torch_geometric.data import Data
from torch_geometric.transforms import KNNGraph

# fasionMnistデータセットを取得する
transform = transforms.ToTensor()
dataset = torchvision.datasets.FashionMNIST(root='./data', train=True, transform=transform)

# 近傍ノードを接続する。
t = KNNGraph()

data_list = []

# 画像のセルごとにグレースケールの値が「0.」以上の場合、そのセルをノードとする。
for i in range(len(dataset)):
    
    if i % 1000 == 0:
        print(f"{i+1}番目")
    
    for j in range(len(dataset[i])):
        img, label = dataset[i]
        img = img[0]
        
        # ノードの特徴量
        x = []
        # ノードの位置(行番号, 列番号)
        pos = []
        
        for k in range(len(img)):
            for l in range(len(img[k])):
                if img[k][l] != .0:
                    x.append([img[k][l].item()])
                    pos.append([k, l])
    
    d = Data(
        x=torch.tensor(x),
        y=torch.tensor([label]),
        pos=torch.tensor(pos)
    )
    
    # 「d.pos」データをもとに「d.edge_index」を作成する。
    data = t(d)
    
    # ノードの特徴量pos情報を付与する(posは画素数で正規化する)
    data.x = torch.cat((data.x, data.pos/28), dim=1)
    
    data_list.append(data)

print(f"len(data_list): {len(data_list)}")

path = "./dataset/fasionMnistDataset.pkl"
pickle.dump(data_list, open(path, 'wb'))
```

## 2-2. 実行してみる

<details><summary>コンソール結果</summary><div>

```
$ python create_fasionMnistDataset.py

1番目
1001番目
2001番目
3001番目
4001番目
5001番目
6001番目
7001番目
8001番目
9001番目
10001番目
11001番目
12001番目
13001番目
14001番目
15001番目
16001番目
17001番目
18001番目
19001番目
20001番目
21001番目
22001番目
23001番目
24001番目
25001番目
26001番目
27001番目
28001番目
29001番目
30001番目
31001番目
32001番目
33001番目
34001番目
35001番目
36001番目
37001番目
38001番目
39001番目
40001番目
41001番目
42001番目
43001番目
44001番目
45001番目
46001番目
47001番目
48001番目
49001番目
50001番目
51001番目
52001番目
53001番目
54001番目
55001番目
56001番目
57001番目
58001番目
59001番目
len(data_list): 60000
```

</div></details>

## 2-3. 分類してみる

```val.py
import torch
import pickle
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F


from torch_geometric.data import Data
from torch_geometric.loader import DataLoader
from torch_geometric.nn import Linear, TransformerConv

from sklearn.metrics import accuracy_score
from torch_geometric.nn import global_mean_pool

seed = 0
np.random.seed(seed)
torch.manual_seed(seed)

class Net(torch.nn.Module):
    def __init__(self, hid1, hid2):
        super(Net, self).__init__()
        
        self.conv1 = TransformerConv(3, hid1)
        self.conv2 = TransformerConv(hid1, hid2)
        self.lin = Linear(hid2, 10)

    def forward(self, data):
        x, edge_index, batch = data.x, data.edge_index,  data.batch
        
        x = self.conv1(x, edge_index)
        x = x.relu()
        x = self.conv2(x, edge_index)

        x = global_mean_pool(x, batch)
        
        x = F.dropout(x)
        x = self.lin(x)
        
        return x

hid1 = 512
hid2 = 256

data_size = 3200
batch_size= 64

# fasionMNISTデータセット取得
path = "./dataset/fasionMnistDataset.pkl"
with open(path, 'rb') as f:
    dataset = pickle.load(f)

print(f"len(dataset): {len(dataset)}")
print(f"dataset[0]: {dataset[0]}")

# 訓練データとテストデータの分割
train_loader = DataLoader(
    dataset=dataset[:data_size],
    batch_size=batch_size,
    shuffle=False
)
test_loader = DataLoader(
    dataset=dataset[data_size:data_size + 128],
    batch_size=1,
    shuffle=False
)

print("train_size:", len(train_loader))
print("test_size", len(test_loader))

# モデル呼び出し
model = Net(hid1, hid2)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 予測結果の格納用リスト
pred_list = np.array([])

print("\n学習開始")
model.train()
for epoch in range(100):
    for i, d in enumerate(train_loader):
        optimizer.zero_grad()
        out = model(d)
        loss = criterion(out, d.y)
        loss.backward()
        optimizer.step()
    
    print(f'train || epoch: {epoch+1} | Loss: {round(loss.item(), 5)}')

path_file = "./model/fasionMnistClassificationModel.pkl"
pickle.dump(model, open(path_file, 'wb'))

print("\n検証開始")
model.eval()
for k, data in enumerate(test_loader):
    pred = model(data).argmax(dim=1)
    
    print(f'test: {k}番目 || 予測: {pred.item()} | 正解: {data.y.item()}')
    
    pred_list = np.append(pred_list, accuracy_score(pred, data.y))

print(f"\naccuracy_rate: {round(np.mean(pred_list), 5)}\n")
```

## 2-4. 実行してみる

<details><summary>コンソール結果</summary><div>

```
$ python val.py

len(dataset): 60000
dataset[0]: Data(x=[433, 3], y=[1], pos=[433, 2], edge_index=[2, 2598])
train_size: 50
test_size 128

学習開始
train || epoch: 1 | Loss: 1.56631
train || epoch: 2 | Loss: 1.25475
train || epoch: 3 | Loss: 0.98292
train || epoch: 4 | Loss: 0.93533
train || epoch: 5 | Loss: 0.89738
train || epoch: 6 | Loss: 0.90898
train || epoch: 7 | Loss: 0.87947
train || epoch: 8 | Loss: 0.82032
train || epoch: 9 | Loss: 0.77414
train || epoch: 10 | Loss: 0.78221
train || epoch: 11 | Loss: 0.75873
train || epoch: 12 | Loss: 0.71112
train || epoch: 13 | Loss: 0.69232
train || epoch: 14 | Loss: 0.67328
train || epoch: 15 | Loss: 0.70638
train || epoch: 16 | Loss: 0.64185
train || epoch: 17 | Loss: 0.61589
train || epoch: 18 | Loss: 0.65663
train || epoch: 19 | Loss: 0.6123
train || epoch: 20 | Loss: 0.68982
train || epoch: 21 | Loss: 0.61527
train || epoch: 22 | Loss: 0.59524
train || epoch: 23 | Loss: 0.60011
train || epoch: 24 | Loss: 0.54645
train || epoch: 25 | Loss: 0.52385
train || epoch: 26 | Loss: 0.59014
train || epoch: 27 | Loss: 0.66215
train || epoch: 28 | Loss: 0.58884
train || epoch: 29 | Loss: 0.54927
train || epoch: 30 | Loss: 0.63354
train || epoch: 31 | Loss: 0.58146
train || epoch: 32 | Loss: 0.56199
train || epoch: 33 | Loss: 0.61343
train || epoch: 34 | Loss: 0.54951
train || epoch: 35 | Loss: 0.55947
train || epoch: 36 | Loss: 0.58261
train || epoch: 37 | Loss: 0.56811
train || epoch: 38 | Loss: 0.50513
train || epoch: 39 | Loss: 0.57378
train || epoch: 40 | Loss: 0.52147
train || epoch: 41 | Loss: 0.51887
train || epoch: 42 | Loss: 0.55677
train || epoch: 43 | Loss: 0.56029
train || epoch: 44 | Loss: 0.60853
train || epoch: 45 | Loss: 0.64635
train || epoch: 46 | Loss: 0.53477
train || epoch: 47 | Loss: 0.57175
train || epoch: 48 | Loss: 0.63044
train || epoch: 49 | Loss: 0.61773
train || epoch: 50 | Loss: 0.60688
train || epoch: 51 | Loss: 0.64101
train || epoch: 52 | Loss: 0.65797
train || epoch: 53 | Loss: 0.58739
train || epoch: 54 | Loss: 0.61174
train || epoch: 55 | Loss: 0.63775
train || epoch: 56 | Loss: 0.7203
train || epoch: 57 | Loss: 0.58409
train || epoch: 58 | Loss: 0.56606
train || epoch: 59 | Loss: 0.5754
train || epoch: 60 | Loss: 0.62622
train || epoch: 61 | Loss: 0.56519
train || epoch: 62 | Loss: 0.62624
train || epoch: 63 | Loss: 0.67562
train || epoch: 64 | Loss: 0.56867
train || epoch: 65 | Loss: 0.53343
train || epoch: 66 | Loss: 0.50976
train || epoch: 67 | Loss: 0.61589
train || epoch: 68 | Loss: 0.53066
train || epoch: 69 | Loss: 0.60616
train || epoch: 70 | Loss: 0.56676
train || epoch: 71 | Loss: 0.5135
train || epoch: 72 | Loss: 0.53256
train || epoch: 73 | Loss: 0.5073
train || epoch: 74 | Loss: 0.5096
train || epoch: 75 | Loss: 0.49309
train || epoch: 76 | Loss: 0.53888
train || epoch: 77 | Loss: 0.67443
train || epoch: 78 | Loss: 0.52665
train || epoch: 79 | Loss: 0.5609
train || epoch: 80 | Loss: 0.50877
train || epoch: 81 | Loss: 0.65272
train || epoch: 82 | Loss: 0.49286
train || epoch: 83 | Loss: 0.55646
train || epoch: 84 | Loss: 0.51027
train || epoch: 85 | Loss: 0.55409
train || epoch: 86 | Loss: 0.56557
train || epoch: 87 | Loss: 0.42696
train || epoch: 88 | Loss: 0.4319
train || epoch: 89 | Loss: 0.54838
train || epoch: 90 | Loss: 0.53443
train || epoch: 91 | Loss: 0.50631
train || epoch: 92 | Loss: 0.45507
train || epoch: 93 | Loss: 0.58498
train || epoch: 94 | Loss: 0.69919
train || epoch: 95 | Loss: 0.45211
train || epoch: 96 | Loss: 0.50194
train || epoch: 97 | Loss: 0.46342
train || epoch: 98 | Loss: 0.5354
train || epoch: 99 | Loss: 0.55627
train || epoch: 100 | Loss: 0.42533

検証開始
test: 0番目 || 予測: 3 | 正解: 3
test: 1番目 || 予測: 7 | 正解: 7
test: 2番目 || 予測: 3 | 正解: 6
test: 3番目 || 予測: 5 | 正解: 5
test: 4番目 || 予測: 2 | 正解: 6
test: 5番目 || 予測: 0 | 正解: 0
test: 6番目 || 予測: 7 | 正解: 7
test: 7番目 || 予測: 3 | 正解: 3
test: 8番目 || 予測: 6 | 正解: 2
test: 9番目 || 予測: 8 | 正解: 8
test: 10番目 || 予測: 7 | 正解: 5
test: 11番目 || 予測: 7 | 正解: 7
test: 12番目 || 予測: 1 | 正解: 1
test: 13番目 || 予測: 7 | 正解: 7
test: 14番目 || 予測: 2 | 正解: 2
test: 15番目 || 予測: 5 | 正解: 5
test: 16番目 || 予測: 7 | 正解: 7
test: 17番目 || 予測: 1 | 正解: 1
test: 18番目 || 予測: 2 | 正解: 2
test: 19番目 || 予測: 4 | 正解: 0
test: 20番目 || 予測: 1 | 正解: 1
test: 21番目 || 予測: 0 | 正解: 0
test: 22番目 || 予測: 3 | 正解: 3
test: 23番目 || 予測: 1 | 正解: 1
test: 24番目 || 予測: 6 | 正解: 4
test: 25番目 || 予測: 2 | 正解: 6
test: 26番目 || 予測: 4 | 正解: 2
test: 27番目 || 予測: 0 | 正解: 0
test: 28番目 || 予測: 3 | 正解: 3
test: 29番目 || 予測: 3 | 正解: 3
test: 30番目 || 予測: 5 | 正解: 5
test: 31番目 || 予測: 9 | 正解: 5
test: 32番目 || 予測: 9 | 正解: 9
test: 33番目 || 予測: 0 | 正解: 0
test: 34番目 || 予測: 2 | 正解: 6
test: 35番目 || 予測: 8 | 正解: 8
test: 36番目 || 予測: 3 | 正解: 3
test: 37番目 || 予測: 0 | 正解: 0
test: 38番目 || 予測: 6 | 正解: 6
test: 39番目 || 予測: 7 | 正解: 7
test: 40番目 || 予測: 0 | 正解: 6
test: 41番目 || 予測: 6 | 正解: 6
test: 42番目 || 予測: 0 | 正解: 0
test: 43番目 || 予測: 1 | 正解: 1
test: 44番目 || 予測: 5 | 正解: 5
test: 45番目 || 予測: 9 | 正解: 9
test: 46番目 || 予測: 1 | 正解: 1
test: 47番目 || 予測: 7 | 正解: 7
test: 48番目 || 予測: 7 | 正解: 7
test: 49番目 || 予測: 6 | 正解: 2
test: 50番目 || 予測: 3 | 正解: 4
test: 51番目 || 予測: 6 | 正解: 6
test: 52番目 || 予測: 2 | 正解: 1
test: 53番目 || 予測: 3 | 正解: 3
test: 54番目 || 予測: 6 | 正解: 6
test: 55番目 || 予測: 2 | 正解: 2
test: 56番目 || 予測: 1 | 正解: 1
test: 57番目 || 予測: 4 | 正解: 4
test: 58番目 || 予測: 9 | 正解: 9
test: 59番目 || 予測: 2 | 正解: 6
test: 60番目 || 予測: 5 | 正解: 5
test: 61番目 || 予測: 7 | 正解: 5
test: 62番目 || 予測: 3 | 正解: 3
test: 63番目 || 予測: 9 | 正解: 9
test: 64番目 || 予測: 3 | 正解: 6
test: 65番目 || 予測: 2 | 正解: 2
test: 66番目 || 予測: 2 | 正解: 2
test: 67番目 || 予測: 4 | 正解: 6
test: 68番目 || 予測: 9 | 正解: 9
test: 69番目 || 予測: 9 | 正解: 9
test: 70番目 || 予測: 0 | 正解: 6
test: 71番目 || 予測: 2 | 正解: 2
test: 72番目 || 予測: 8 | 正解: 8
test: 73番目 || 予測: 5 | 正解: 5
test: 74番目 || 予測: 5 | 正解: 5
test: 75番目 || 予測: 9 | 正解: 9
test: 76番目 || 予測: 4 | 正解: 4
test: 77番目 || 予測: 2 | 正解: 2
test: 78番目 || 予測: 8 | 正解: 8
test: 79番目 || 予測: 1 | 正解: 1
test: 80番目 || 予測: 7 | 正解: 7
test: 81番目 || 予測: 3 | 正解: 3
test: 82番目 || 予測: 7 | 正解: 7
test: 83番目 || 予測: 8 | 正解: 8
test: 84番目 || 予測: 1 | 正解: 1
test: 85番目 || 予測: 7 | 正解: 7
test: 86番目 || 予測: 3 | 正解: 3
test: 87番目 || 予測: 7 | 正解: 9
test: 88番目 || 予測: 2 | 正解: 2
test: 89番目 || 予測: 2 | 正解: 4
test: 90番目 || 予測: 9 | 正解: 9
test: 91番目 || 予測: 6 | 正解: 4
test: 92番目 || 予測: 1 | 正解: 1
test: 93番目 || 予測: 0 | 正解: 6
test: 94番目 || 予測: 0 | 正解: 6
test: 95番目 || 予測: 1 | 正解: 1
test: 96番目 || 予測: 5 | 正解: 5
test: 97番目 || 予測: 9 | 正解: 9
test: 98番目 || 予測: 0 | 正解: 6
test: 99番目 || 予測: 5 | 正解: 5
test: 100番目 || 予測: 9 | 正解: 5
test: 101番目 || 予測: 8 | 正解: 8
test: 102番目 || 予測: 4 | 正解: 4
test: 103番目 || 予測: 5 | 正解: 5
test: 104番目 || 予測: 9 | 正解: 9
test: 105番目 || 予測: 3 | 正解: 0
test: 106番目 || 予測: 1 | 正解: 1
test: 107番目 || 予測: 2 | 正解: 6
test: 108番目 || 予測: 7 | 正解: 5
test: 109番目 || 予測: 1 | 正解: 1
test: 110番目 || 予測: 1 | 正解: 1
test: 111番目 || 予測: 6 | 正解: 3
test: 112番目 || 予測: 3 | 正解: 3
test: 113番目 || 予測: 6 | 正解: 2
test: 114番目 || 予測: 2 | 正解: 4
test: 115番目 || 予測: 8 | 正解: 8
test: 116番目 || 予測: 3 | 正解: 3
test: 117番目 || 予測: 7 | 正解: 7
test: 118番目 || 予測: 4 | 正解: 4
test: 119番目 || 予測: 8 | 正解: 8
test: 120番目 || 予測: 8 | 正解: 8
test: 121番目 || 予測: 9 | 正解: 9
test: 122番目 || 予測: 4 | 正解: 4
test: 123番目 || 予測: 5 | 正解: 5
test: 124番目 || 予測: 9 | 正解: 9
test: 125番目 || 予測: 0 | 正解: 0
test: 126番目 || 予測: 6 | 正解: 0
test: 127番目 || 予測: 9 | 正解: 9

accuracy_rate: 0.74219
```

</div></details>