深層学習における基本ニューラルネットワークの構築（メモ）


## <font color="DarkGray">●</font><font color="DeepSkyBlue"> TensorFlow2 (tf.keras)でニューラルネットワークを構築</font>

```python
# ① import
import tensorflow as tf
from tensorflow.keras.layers import Dense, Dropout, Flatten
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.datasets import mnist
import os
from matplotlib import pyplot as plt

batch_size = 128
epochs = 30

# ②データの取得
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# データの前処理
x_train, x_test = x_train / 255.0, x_test / 255.0


# ③モデルの構築 (Sequential法)
model = tf.keras.models.Sequential([
    Flatten(),
    Dense(120, activation='relu'),
    Dropout(0.2),  # 過学習防止
    Dense(10, activation='softmax')
])


# # ③モデルの構築 (class法 ※PyTorchに似た書き方)
# class MnistMode(tf.keras.Model):
#     def __init__(self):
#         super().__init__()
#         self.flatten = Flatten()
#         self.d1 = Dense(120, activation="relu")
#         self.dropout = Dropout(0.2)
#         self.d2 = Dense(10, activation="softmax")
#
#     def call(self, x, training=False):
#         x = self.flatten(x)
#         x = self.d1(x)
#         if training:  # 予測時には適用しない
#             x = self.dropout(x, training=training)
#         x = self.d2(x)
#         return x
#
#
# model = MnistMode()

# ④モデルのコンパイル
model.compile(optimizer=Adam(),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(),
              metrics=['accuracy'])

checkpoint_save_path = "./checkpoint/mnist.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------重みロード-----------------')
    model.load_weights(checkpoint_save_path)

# 訓練中にチェックポイントを保存します。
# (再び訓練を行うことなくモデルを使用することができます）
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True)
# ⑤モデルの学習
history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
                    validation_data=(x_test, y_test),
                    callbacks=[cp_callback])
# ⑥モデルの構造の表示
model.summary()

# ----------  学習過程（accuracyとloss）をプロット  ----------
plt.figure(figsize=(10, 5))
metrics = ['loss', 'accuracy']
for i in range(len(metrics)):
    metric = metrics[i]
    plt.subplot(1, 2, i + 1)
    plt.plot(history.history[metric], label='Training ' + metric)
    plt.plot(history.history['val_' + metric], label='Validation ' + metric)
    plt.title(metric)
    plt.legend()
plt.show()

```

## <font color="DarkGray">●</font><font color="DeepSkyBlue"> PyTorchでニューラルネットワークを構築</font>

```python
# ① import
import torch
from torch import nn
from torch.nn import functional as F
from torch import optim
import torchvision
from matplotlib import pyplot as plt

batch_size = 128
epochs = 30
torch.manual_seed(20)
# ②データの取得、データの前処理
train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.5,), (0.5,))
                               ])),
    batch_size=batch_size, shuffle=True)

test_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data/', train=False, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.5,), (0.5,))
                               ])),
    batch_size=batch_size, shuffle=False)

# ③モデルの構築
class MnistMode(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(1 * 28 * 28, 120)
        self.fc2 = nn.Linear(120, 10)

    def forward(self, x):
        x = x.view(-1, 1 * 28 * 28)
        x = F.relu(self.fc1(x))
        if self.training:
            x = F.dropout(x, 0.2, training=self.training)
        x = self.fc2(x)
        return x

device = "cuda" if torch.cuda.is_available() else "cpu"
model = MnistMode().to(device)

# ④　損失関数、最適化手法
loss_func = nn.CrossEntropyLoss().to(device)  # softmax処理含み
optimizer = optim.Adam(model.parameters(), lr=0.0001)

# ⑤モデルの学習
history = {'loss': [], 'val_loss': [], 'accuracy': [], 'val_accuracy': []}
train_loader_len = len(train_loader)
for epoch in range(epochs):
    total_train_loss = 0
    total_train_acc = 0
    model.train()  # 学習モードに (training->True)
    print('----- Epoch {}/{} ------'.format(epoch + 1, epochs))
    for batch_idx, (x, y) in enumerate(train_loader):
        x = x.to(device)
        y = y.to(device)
        out = model(x)
        loss = loss_func(out, y)
        total_train_loss += loss.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        pred_train = out.argmax(dim=1)
        correct = (pred_train == y).sum().item() / x.shape[0]
        total_train_acc += correct
        if (batch_idx + 1) % 50 == 0:
            print('{:6}/{}  loss: {:.5f} accuracy: {:.5f}'.format(batch_idx + 1, train_loader_len,
                                                                loss.item(), correct))
    cnt = len(train_loader)
    history['loss'].append(total_train_loss / cnt)
    history['accuracy'].append(total_train_acc / cnt)

    total_val_loss = 0
    total_val_acc = 0
    model.eval()  # 推論モードに (training->False)
    with torch.no_grad():
        for x, y in test_loader:
            x = x.to(device)
            y = y.to(device)
            x = x.view(-1, 1 * 28 * 28)
            out = model(x)
            loss = loss_func(out, y)
            pred = out.argmax(dim=1)
            correct = (pred == y).sum().item()
            total_val_loss += loss.item()
            total_val_acc += correct
    history['val_loss'].append(total_val_loss / len(test_loader))
    history['val_accuracy'].append(total_val_acc / len(test_loader.dataset))
    format_str = 'Epoch {}/{} loss: {:.5f} - accuracy: {:.5f} - val_loss: {:.5f} - val_accuracy: {:.5f}'
    print(format_str.format(epoch + 1, epochs,
                            history['loss'][-1], history['accuracy'][-1],
                            history['val_loss'][-1], history['val_accuracy'][-1]))

# ⑥モデルの構造の表示
print(model)

# ----------  学習過程（lossとaccuracy）をプロット  ----------
plt.figure(figsize=(10, 5))
metrics = ['loss', 'accuracy']
for i in range(len(metrics)):
    metric = metrics[i]
    plt.subplot(1, 2, i + 1)
    plt.plot(history[metric], label='Training ' + metric)
    plt.plot(history['val_' + metric], label='Validation ' + metric)
    plt.title(metric)
    plt.legend()
plt.show()

```