{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "L01zuR_k7Y6Q"
      },
      "source": [
        "# 第五回：ニューラルネットワークの実装と訓練\n",
        "\n",
        "PyTorchを使用したMNIST手書き数字認識の実装"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gu6lw-k47Y6R"
      },
      "source": [
        "## 1. セットアップ"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install japanize_matplotlib"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "K4aoDxdz7hGf",
        "outputId": "35aede09-b614-4959-9ace-53c83e5183d1"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Collecting japanize_matplotlib\n",
            "  Downloading japanize-matplotlib-1.1.3.tar.gz (4.1 MB)\n",
            "\u001b[?25l     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/4.1 MB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K     \u001b[91m━━━━━\u001b[0m\u001b[91m╸\u001b[0m\u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.6/4.1 MB\u001b[0m \u001b[31m21.8 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K     \u001b[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[91m╸\u001b[0m \u001b[32m4.1/4.1 MB\u001b[0m \u001b[31m67.2 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4.1/4.1 MB\u001b[0m \u001b[31m48.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h  Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/dist-packages (from japanize_matplotlib) (3.10.0)\n",
            "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (1.3.2)\n",
            "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (0.12.1)\n",
            "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (4.58.4)\n",
            "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (1.4.8)\n",
            "Requirement already satisfied: numpy>=1.23 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (2.0.2)\n",
            "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (24.2)\n",
            "Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (11.2.1)\n",
            "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (3.2.3)\n",
            "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/dist-packages (from matplotlib->japanize_matplotlib) (2.9.0.post0)\n",
            "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.7->matplotlib->japanize_matplotlib) (1.17.0)\n",
            "Building wheels for collected packages: japanize_matplotlib\n",
            "  Building wheel for japanize_matplotlib (setup.py) ... \u001b[?25l\u001b[?25hdone\n",
            "  Created wheel for japanize_matplotlib: filename=japanize_matplotlib-1.1.3-py3-none-any.whl size=4120257 sha256=06d62e2d3f96ff94d2894a06039b66e6e0ade7b906ed9fa4f13702f79515db46\n",
            "  Stored in directory: /root/.cache/pip/wheels/da/a1/71/b8faeb93276fed10edffcca20746f1ef6f8d9e071eee8425fc\n",
            "Successfully built japanize_matplotlib\n",
            "Installing collected packages: japanize_matplotlib\n",
            "Successfully installed japanize_matplotlib-1.1.3\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8sTXOzl97Y6R",
        "outputId": "59ac1cba-1d18-4699-d46f-778c2e7d1441"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "使用デバイス: cuda\n"
          ]
        }
      ],
      "source": [
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.nn.functional as F\n",
        "import torch.optim as optim\n",
        "from torch.utils.data import DataLoader\n",
        "from torchvision import datasets, transforms\n",
        "import japanize_matplotlib # noqa\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "# デバイスの設定（CPUかGPUか）\n",
        "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
        "print(f'使用デバイス: {device}')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "COPr776g7Y6T"
      },
      "source": [
        "## 2. データセットの準備"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Q0QRGzVj7Y6T",
        "outputId": "e4e0f5b9-98e4-42f0-a976-42c796c8cb94"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "100%|██████████| 9.91M/9.91M [00:00<00:00, 16.8MB/s]\n",
            "100%|██████████| 28.9k/28.9k [00:00<00:00, 492kB/s]\n",
            "100%|██████████| 1.65M/1.65M [00:00<00:00, 3.96MB/s]\n",
            "100%|██████████| 4.54k/4.54k [00:00<00:00, 6.76MB/s]\n"
          ]
        }
      ],
      "source": [
        "# 1. 画像データをどう変換するかのルールを定義\n",
        "transform = transforms.Compose([\n",
        "    transforms.ToTensor(), # データをテンソルに変換\n",
        "    transforms.Normalize((0.5,), (0.5,)) # データを[-1, 1]の範囲に正規化\n",
        "])\n",
        "\n",
        "# 2. MNISTデータセットを読み込み、変換ルールを適用\n",
        "train_dataset = datasets.MNIST(\n",
        "    root='./data',        # データ保存先\n",
        "    train=True,           # 訓練データを使用\n",
        "    download=True,        # なければダウンロード\n",
        "    transform=transform   # 上で定義した変換を適用\n",
        ")\n",
        "\n",
        "test_dataset = datasets.MNIST(\n",
        "    root='./data',\n",
        "    train=False,\n",
        "    download=True,\n",
        "    transform=transform\n",
        ")\n",
        "\n",
        "# 3. データをバッチにまとめて供給するDataLoaderを作成\n",
        "train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)\n",
        "test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "train_dataset[1]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "zSzcbPaXHO4v",
        "outputId": "83650713-312d-43d4-f7b3-e75fda2da319",
        "collapsed": true
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "(tensor([[[-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -0.6000,  0.2471,  0.9843,  0.2471, -0.6078, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -0.6235,  0.8667,  0.9765,  0.9765,  0.9765,  0.8588, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.5765,\n",
              "            0.7804,  0.9843,  0.9765,  0.8745,  0.8275,  0.9765, -0.5529,\n",
              "           -0.9529, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -0.9216, -0.5294,  0.7569,\n",
              "            0.9765,  0.9843,  0.9765,  0.5843, -0.3412,  0.9765,  0.9843,\n",
              "           -0.0431, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000,  0.2784,  0.9765,  0.9765,\n",
              "            0.9765,  0.9843,  0.9765,  0.9765, -0.2471,  0.4824,  0.9843,\n",
              "            0.3098, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -0.6000,  0.8667,  0.9843,  0.9843,\n",
              "            0.4902, -0.1059,  0.9843,  0.7882, -0.6314, -0.3804,  1.0000,\n",
              "            0.3176, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -0.6235,  0.8667,  0.9765,  0.9765,  0.4039,\n",
              "           -0.9059, -0.4118, -0.0510, -0.8353, -1.0000, -1.0000,  0.9843,\n",
              "            0.9059, -0.6078, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -0.7020,  0.2941,  0.9843,  0.8275,  0.6314, -0.3412,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,  0.9843,\n",
              "            0.9765,  0.2941, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -0.9451,  0.3961,  0.9765,  0.8824, -0.4431, -0.8510, -0.7804,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,  0.9843,\n",
              "            0.9765,  0.5294, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -0.5529,  0.9765,  0.9765, -0.5059, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,  0.9843,\n",
              "            0.9765,  0.5294, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "            0.5529,  0.9843,  0.4902, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,  1.0000,\n",
              "            0.9843,  0.5373, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.4039,\n",
              "            0.9294,  0.9765, -0.1216, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,  0.9843,\n",
              "            0.9765,  0.1608, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3333,\n",
              "            0.9765,  0.8039, -0.8039, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -0.9451,  0.0588,  0.9843,\n",
              "            0.4588, -0.9059, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3333,\n",
              "            0.9765,  0.7490, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -0.9451,  0.0275,  0.9765,  0.7647,\n",
              "           -0.4431, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3333,\n",
              "            0.9765,  0.1373, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -0.6235,  0.2941,  0.9765,  0.3569, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3255,\n",
              "            0.9843,  0.7647, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -0.1059,  0.8667,  0.9843,  0.2706, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3333,\n",
              "            0.9765,  0.9529,  0.1451, -0.6235, -0.7725, -0.3333,  0.3961,\n",
              "            0.7647,  0.9843,  0.7490,  0.3098, -0.5608, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.3333,\n",
              "            0.9765,  0.9765,  0.9765,  0.7961,  0.6863,  0.9765,  0.9765,\n",
              "            0.9765,  0.5373,  0.0196, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -0.7804,\n",
              "            0.5608,  0.9765,  0.9765,  0.9843,  0.9765,  0.9765,  0.8275,\n",
              "            0.1373, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -0.8039,  0.0039,  0.9765,  0.9843,  0.9765,  0.1059, -0.7098,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000],\n",
              "          [-1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000,\n",
              "           -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000, -1.0000]]]),\n",
              " 0)"
            ]
          },
          "metadata": {},
          "execution_count": 5
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7mXTMQI07Y6T"
      },
      "source": [
        "## 3. モデルの定義"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ksEYhS_I7Y6T"
      },
      "outputs": [],
      "source": [
        "class MNISTClassifier(nn.Module):\n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.layer1 = nn.Linear(28 * 28, 128)  # 784 -> 128\n",
        "        self.layer2 = nn.Linear(128, 64)       # 128 -> 64\n",
        "        self.layer3 = nn.Linear(64, 10)        # 64 -> 10 (クラス数)\n",
        "\n",
        "    def forward(self, x):\n",
        "        x = x.view(-1, 28 * 28)  # 1. 入力画像を1次元のベクトルに平坦化\n",
        "        x = F.relu(self.layer1(x))  # 2. layer1に通し、活性化関数ReLUを適用\n",
        "        x = F.relu(self.layer2(x))  # 3. layer2に通し、活性化関数ReLUを適用\n",
        "        x = self.layer3(x)  # 4. 出力層に通す（活性化関数は不要）\n",
        "        return x"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "model = MNISTClassifier().to(device)\n",
        "print(model)\n",
        "print(model(torch.randn(4, 28, 28).to(device)).shape)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3h-MsHHnSjKI",
        "outputId": "8208117a-f37a-4133-d1f9-c28e753e5d17"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "MNISTClassifier(\n",
            "  (layer1): Linear(in_features=784, out_features=128, bias=True)\n",
            "  (layer2): Linear(in_features=128, out_features=64, bias=True)\n",
            "  (layer3): Linear(in_features=64, out_features=10, bias=True)\n",
            ")\n",
            "torch.Size([4, 10])\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JaEjO4zG7Y6U"
      },
      "source": [
        "## 4. 損失関数とオプティマイザの設定"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FMXOHAsr7Y6U"
      },
      "outputs": [],
      "source": [
        "# モデル、損失関数、オプティマイザの初期化\n",
        "model = MNISTClassifier().to(device)\n",
        "criterion = nn.CrossEntropyLoss()\n",
        "optimizer = optim.SGD(model.parameters(), lr=0.01)"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "output = torch.tensor([[0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])\n",
        "output.shape"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PAEikxbmVlmC",
        "outputId": "f879f2ec-8b58-4a4e-a542-0967a36491f9"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "torch.Size([1, 10])"
            ]
          },
          "metadata": {},
          "execution_count": 22
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "target = torch.tensor([5])\n",
        "target.shape"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "M3_fpdoAV3S5",
        "outputId": "d539a65a-e992-478d-9582-ce88b07645ee"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "torch.Size([1])"
            ]
          },
          "metadata": {},
          "execution_count": 23
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "criterion(output, target)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Lhml9ZIOV7s5",
        "outputId": "f4bca4ee-a9c3-48d9-f07f-6c6c8b88a3d5"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "tensor(10.0004)"
            ]
          },
          "metadata": {},
          "execution_count": 24
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2RNgkPUl7Y6U"
      },
      "source": [
        "## 5. 訓練関数"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Uvf5kwkB7Y6U"
      },
      "outputs": [],
      "source": [
        "def train(model, device, train_loader, optimizer, criterion, epoch):\n",
        "    model.train()  # 訓練モードに設定\n",
        "    total_loss = 0\n",
        "\n",
        "    for batch_idx, (data, target) in enumerate(train_loader):\n",
        "        data, target = data.to(device), target.to(device)\n",
        "\n",
        "        # 勾配の初期化\n",
        "        optimizer.zero_grad()\n",
        "\n",
        "        # 順伝播\n",
        "        output = model(data)\n",
        "        loss = criterion(output, target)\n",
        "\n",
        "        # 逆伝播\n",
        "        loss.backward()\n",
        "\n",
        "        # パラメータ更新\n",
        "        optimizer.step()\n",
        "\n",
        "        total_loss += loss.item()\n",
        "\n",
        "    return total_loss / len(train_loader)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4RVNfHhz7Y6U"
      },
      "source": [
        "## 6. 評価関数"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "J1ZCTy0L7Y6U"
      },
      "outputs": [],
      "source": [
        "def evaluate(model, device, test_loader, criterion):\n",
        "    model.eval()  # 評価モードに設定\n",
        "    test_loss = 0\n",
        "    correct = 0\n",
        "\n",
        "    with torch.no_grad():  # 勾配計算を無効化\n",
        "        for data, target in test_loader:\n",
        "            data, target = data.to(device), target.to(device)\n",
        "            output = model(data)\n",
        "            test_loss += criterion(output, target).item()\n",
        "\n",
        "            # 予測値の計算\n",
        "            pred = output.argmax(dim=1, keepdim=True)\n",
        "            correct += pred.eq(target.view_as(pred)).sum().item()\n",
        "\n",
        "    test_loss /= len(test_loader)\n",
        "    accuracy = 100. * correct / len(test_loader.dataset)\n",
        "\n",
        "    return test_loss, accuracy"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FNyuch657Y6V"
      },
      "source": [
        "## 7. 訓練ループの実行"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "giDZBlYI7Y6V",
        "outputId": "6c92559d-fd9c-44c3-82d0-a0c99a0a5216"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Epoch 1: Train Loss: 1.0084, Test Loss: 0.4321, Accuracy: 87.75%\n",
            "Epoch 2: Train Loss: 0.3844, Test Loss: 0.3371, Accuracy: 90.21%\n",
            "Epoch 3: Train Loss: 0.3268, Test Loss: 0.3005, Accuracy: 90.95%\n",
            "Epoch 4: Train Loss: 0.2965, Test Loss: 0.2817, Accuracy: 91.60%\n",
            "Epoch 5: Train Loss: 0.2728, Test Loss: 0.2527, Accuracy: 92.66%\n",
            "Epoch 6: Train Loss: 0.2502, Test Loss: 0.2435, Accuracy: 93.06%\n",
            "Epoch 7: Train Loss: 0.2295, Test Loss: 0.2134, Accuracy: 93.95%\n",
            "Epoch 8: Train Loss: 0.2112, Test Loss: 0.1994, Accuracy: 94.31%\n",
            "Epoch 9: Train Loss: 0.1943, Test Loss: 0.1822, Accuracy: 94.79%\n",
            "Epoch 10: Train Loss: 0.1794, Test Loss: 0.1786, Accuracy: 94.67%\n"
          ]
        }
      ],
      "source": [
        "# 訓練ループ\n",
        "train_losses = []\n",
        "test_losses = []\n",
        "accuracies = []\n",
        "\n",
        "for epoch in range(1, 11):\n",
        "    train_loss = train(model, device, train_loader, optimizer, criterion, epoch)\n",
        "    test_loss, accuracy = evaluate(model, device, test_loader, criterion)\n",
        "\n",
        "    train_losses.append(train_loss)\n",
        "    test_losses.append(test_loss)\n",
        "    accuracies.append(accuracy)\n",
        "\n",
        "    print(f'Epoch {epoch}: Train Loss: {train_loss:.4f}, '\n",
        "          f'Test Loss: {test_loss:.4f}, Accuracy: {accuracy:.2f}%')"
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "cSe7fRmLZsAi"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lhsNRCfb7Y6V"
      },
      "source": [
        "## 8. 学習曲線の可視化"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 312
        },
        "id": "0eoYyrEl7Y6V",
        "outputId": "d8caafd0-78a7-4a69-83ed-be73c77e4fad"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1200x400 with 2 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAGGCAYAAACqvTJ0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAApGlJREFUeJzs3Xd4FOX6xvHvpm4KCaQBaZCEDtIEJHQQBAVFARUUQRREBRsKiL+DAnpE0WPX4xEVLIiKDURs9Bakhd5CQiAFSCOFhPT5/RFYjYDUZFLuz3XtJTszO3tPCObNs+/7jMUwDAMREREREREREZFyZGd2ABERERERERERqX5UlBIRERERERERkXKnopSIiIiIiIiIiJQ7FaVERERERERERKTcqSglIiIiIiIiIiLlTkUpEREREREREREpdypKiYiIiIiIiIhIuVNRSkREREREREREyp2KUiIiIiIiIiIiUu5UlBIRERERERERkXKnopSIlIm5c+disViIjY01O8o5GYbBvHnz6NatG56enri7u3PNNdfw/PPPk52dbXY8ERERqQKeffZZnJycSEpKMjtKhRYREcGgQYPw8/PDarUSGhrKww8/zKFDh8yOJiJlTEUpEal2ioqKGDZsGKNGjaJDhw4sWbKElStXMmbMGN555x06d+5MRkaG2TFFRESkEisqKmLOnDlYrVY+/fRTs+NUWG+//TZdunQB4NNPP2XDhg28+OKLRERE0K5dO7Zs2WJyQhEpSxbDMAyzQ4hI1TN37lxGjRrFoUOHqF+/vtlxSnnuued4/vnnWbRoEQMGDCi178CBA7Rt25Ynn3yS6dOnm5RQREREKruffvqJe++9l4cffpivv/6avXv3mh2pwlm2bBl9+vThqaeeYtasWaX2ZWdn06VLFzw8PFi1apVJCUWkrGmmlIiYau7cuVxzzTU4Ozvj7+/P+PHjSU9PL3XMihUraNu2LS4uLjRo0ICXX36Z4uJiAIqLi5k6dSqBgYG4urrSvXt31q1bd973O3HiBK+++irDhg07qyAF0KhRIyIjI5k2bZptm8ViKfUcYOXKlVgsFlauXGnb1qNHD+69916ioqLo2LEjvXv3plevXlx77bVnvc/dd99NgwYNOPO5wJYtW+jTpw+urq74+/szYsQIEhISSr3m7bffJjQ0FBcXF9q1a8eiRYvOe50iIiJirg8//JDbbruNu+++m3379p01PiksLGTGjBmEhIRgtVpp3Lgxb7755iUfcyXjlDN+/PFH2rVrh6urK40aNeKdd94563oiIyPp168f7u7u1KpVi1tvvZWDBw8C8Nhjj+Hi4nLWGG7GjBm4uLhw4sSJc36Npk6dSlBQEC+++OJZ+9zc3Fi0aBG//PJLqWvo0aPHWcf+/Wswbdo06tevT05ODnfeeSc1a9Zk+vTpODk5kZqaWuq1s2fPxt7ensOHDwOQlJTEyJEj8fb2pmbNmvTu3Zs//vjjnPlF5MqpKCUipnn++ecZPXo0AwcOZM2aNbz66qssWrSI7t27k5OTA0B6ejoDBw6ka9euREREMG3aNN566y0iIiIAmDNnDq+//jpvv/02a9eupXXr1owbN47CwsJzvufy5cvJycnhjjvuOG+uhg0bYrFYLuuaiouLGTVqFI899hgff/wxo0ePZuvWraU+Hc3JyWHhwoXcf//9WCwWtm3bRrdu3WjUqBHLli3j008/5fDhw4SHh9sGccuWLePxxx9n6tSpREREcOutt56zgCciIiLmO3bsGIsXL+aee+6hUaNGdOrUiY8++qjUMSNGjODll1/mkUceYd26dTzxxBNMmTKFGTNmXNIxl+Lv4xSAH374wTbWWrNmDWPGjOHRRx/lm2++sb1u27ZtdOnShby8PBYuXMiiRYs4deoUnTt3JiUlhfHjx5OXl8eXX35Z6v3mzZvH7bffTq1atc7KkpKSwoYNGxg0aBAODg7nzBsUFISLi8tlXSvAxIkTadGiBWvXruX++++nqKiIr7/+utQx8+fPp3fv3tSrV4+srCy6detGXFwcX375Jb/++ithYWG2caiIlAFDRKQMzJkzxwCMQ4cOnXP/kSNHDAcHB+OJJ54otX3Lli2GnZ2d8dJLLxmGYRibNm0yAGPz5s22Y3Jycmx/HjdunNGiRYtS5/jr/r+bNWuWARh79uy56GsBjOeee67UthUrVhiAsWLFCtu27t27G35+fsbnn39u23bq1CmjVq1axv/93//Ztn355ZeGg4ODcfToUcMwDOP666837r777rOuwdvb23j55ZcNwzCMV155xahZs6ZRUFBwUdcpIiIi5pk5c6bRqFEj2/O5c+cabm5uRmZmpmEYhrFmzRoDMN56661Sr/vqq6+MBQsWXPQxhnFl4xTDMIyNGzca//rXv0ptu/HGG4277rrL9vz66683goKCjOzsbNu2U6dOGU899ZRx7Ngx22s6dOhg239mDLdmzZpzfo02btxoAMZ77713zv3n0r17d6N79+5nbf/71+C5554zPD09jXHjxp11XZ07d7Y9T0xMNOzs7Gxfz+eff94IDQ018vLyznrdjTfeeNE5ReTiaaaUiJjil19+obCwkAceeKDU9rZt29K+fXt++uknAK655hqaNm3K0KFDWbBgAXl5eaU+MRs0aBB79+5l2LBhbNu2DeAfP1E7s+zP3t7+Kl/Rn+cfOnSo7bnVamX48OF88cUXtqV68+fPp3///tSpU4fc3FxWrVrF/PnzcXBwsD1q1KhBamoqkZGRAPTv35/8/Hxuuukm1q5di2EYV/TJoYiIiJQNwzD46KOPGDlyJIWFhRQWFtpmA52ZSbRkyRIsFgv3339/qdfecccdDBky5KKPuVR/H6cAtG/fnueff77UtmbNmpGYmAjAqVOnWLlyJXfddReurq62Y6xWK6+88gq1a9cG4NFHH2Xjxo3s2bMHKJkl1axZM1sT83NlgbIbk2VkZJw1zhw9ejTr16+33dXvq6++wtvbm4EDBwIl49NDhw7h6upaalz2yy+/2MZkInJ1qSglIqY4c2vkevXqnbUvODiYY8eOAeDs7MzatWsZMGAADzzwAEFBQaX6HPTq1YvVq1dz4sQJrr32Wq677jp27Nhx3vc9835RUVFX83JsmjRpctbgavTo0Rw6dIj169eTnp7Ozz//zJgxYwBITU2lsLCQSZMmsW3btlKPnTt38vLLLwPQtGlTNm3ahKenJ7169aJ58+asWLGiTK5BRERELt/KlSs5ePAg//d//4ejoyOOjo54eHiQkZFhW8KXnJyMr69vqSLP313MMZfqXOOU48eP8/jjj9O8eXM8PDxwdHTktddes32YlpaWRlFR0TnHbH/Vt29fGjVqxJw5cygqKuLLL7+0jXfOpazHZADNmzcv9fzmm2/Gz8+PL774AoAvvviCkSNH4ujoCJR8LXr16nXWmGzHjh0sX768zHKKVGcqSomIKXx9fQGIi4s7a9+RI0fw8fGxPffy8uL1118nISGBRx99lEceeYQFCxbY9nfq1IlffvmF/fv3Y7Va6dOnD9nZ2ed83169euHk5GQbjJxLbGws+fn5tud2dna2T/POyMzMPOdrz/VpX8uWLWnfvj1ffvklP/zwA35+fvTr1w+AmjVrYmdnx8mTJ2nRosVZj+DgYNt5mjVrxoIFCzh8+DDNmjXjpptuOufXT0RERMzz4Ycf0rFjRzZt2lTqMXv2bP744w927dqFr68vKSkp5Obmnvc8F3MMXNk4pbi4mJ49e/L5558zatQoFi9ezJYtWxg7dqztGC8vL+zt7S845rBYLIwfP54vvviC33//nfT0dEaMGHHe4+vUqUPr1q355ptvKCgoOOcxaWlppRqT29vbX/S1nut6HR0dGTFiBF9++SWHDh1i8+bNjB492rbf29ub48ePn3NM1rRp03+8fhG5PCpKiYgpbrjhBuzt7fnwww9LbY+MjGTz5s3cdNNNtm1nBiOurq7861//ok2bNqxevRoouV3wmcFagwYNePvtt0lKSmLfvn3nfF8/Pz/GjRvH/Pnz+fbbb8/an5ycTI8ePXjooYds2+rWrcuRI0dszw3DOOvONxcyevRovv/+exYsWMCoUaNsgyQ3Nze6dOnCp59+SnJycqnXvPTSS7ZljEVFRWRkZNjyfPzxx+Tm5rJx48ZLyiEiIiJl58SJE3z33Xfcc889tGvXrtRj1KhR+Pn58dFHH3HTTTdRXFx8VvPzrVu38uqrr2IYxkUdA1c2TklJSWHv3r0888wzPPXUU3Tr1o2WLVty+PBhioqKgJK2CD169GDevHm2G9GcMWPGDNtyPYB7772XkydP8tRTTzF48GC8vLz+8f2nT59ObGwsTz311Fn7CgsLGTVqFOHh4bYsf79WgNdff/2irvWM0aNHs2vXLl566SW6dOlC48aNbfv69u3Lrl27+O2330q9ZtmyZWfd4VBErhLz2lmJSFV2ptH50qVLjb1795Z6HD582DAMw/i///s/w97e3pg6daqxceNGY/78+UZQUJDRvHlzIysryzAMw/j5558NT09P44033jC2bdtmfP3114aLi4vx2WefGYZhGHfeeafRoUMHY/HixUZkZKTx4IMPGp6enrbXn0teXp4xcOBAw97e3njkkUeM1atXG1u2bDE++OADo379+kbz5s1tTcgNwzDGjx9vuLq6Gl988YWxYcMG4+677zbatGlzzgai52q+aRiGkZmZabi5uRn29vZnNX/fvHmz4erqajRs2NBYsGCBsWnTJmPSpEmGs7OzsXbtWsMwDGPy5MlG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fn5+LF++nGXLluHr63vF76/vfblUZ75X1H9MRET+SjOlRERErpCWLVUNle3vMTw8nHXr1p13/0033cRNN91Uphkq29dMzKPvFRERORfTZkoVFxezYcMGnnzySby8vJg7d+4/Hp+QkMCdd95J/fr1CQgIYMKECeTn55dPWBERERERERERuapMK0rNmTOHRx99FBcXlwuuK8/Pz6dPnz4EBwcTHR3N7t272bp163nvLGOGJTuPMvSDCGavjjE7ioiIyD8KDAy0PTw8PHB2di617bXXXrus8y5YsIDAwMDLzrVy5UrNppAyVVbf+5cqPT0dV1dX5s+fXy7vJyIilycuLYd3Vxxk1JyNPPZlJM8v3sN7Kw/y9eY4VuxLYmd8Bonpp8grrPhL/ysq05bv3X///dx///0AfP755/947IIFC0hKSuLFF1/E3t6emjVr8tprr9GpUyemTZuGj49PeUT+R8lZeWyIScPBzo4x3ULNjiMiInJe8fHxtj9PmzaNlStXsnLlyis+7+23387tt99+xecRKStl9b1/xujRoxk5ciRdu3b9x+PmzZuHr68vH374IcOGDbtq7y8iIlfuRHY+i3ceZWFkApsPn7jo13lYHfCp4YyPuzM+7k6n//vnc293Z3zdnfGp4YSrkzopnVEpvhLLly/nhhtuKHUnnLZt2+Ll5cXy5cu54447TExXIjys5M4zmw+nkVdYhLOD7ioiIiIiUp0sXbqU4cOHX/C42bNn8+abbzJs2DAOHTpESEhIOaQTEZHzOZVfxNK9x/khMoFVB5IpLDYAsFggPNSbPs1qU1hkkJKdR0pWPikn82yP1JP5FBYbZOYWkplbSExy9gXfz9XJHh93Z7z/UrzyPV24shW1The4PKwOVXomeaUoSiUkJNCiRYuztgcEBJCQkHDe1+Xl5ZGXl2d7npmZWSb5ABr6uePj7kTKyXy2x2XQIcSrzN5LREQqLsMwOFVgzhRuF0f7qzZoWblyJUOHDuW3335j5MiRjBw5kscff5w//viDxx57jCNHjuDu7s7MmTMZPHgwAHPnzmXatGnExsYCJTNR9u3bR4sWLfjkk09IT09nyJAhvPfee5eV8+DBg0yYMIHIyEicnJwYMGAAL7zwAjVq1ADgl19+YcKECaSlpRESEsJ//vMfOnXqREpKCvfeey/btm3D3t6eBx98kKeffrpK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5tj9u8HXOtzJIVX5AmnibClr9FULWTarKgrM/lJnTR75NQPBiFp6B9Ta448FVoMrrZp7zOMDoYg6vUF1eoMjNmOXzG2C5QXJ2wMrCp2qKsyJhVlOuXPYJojTj9fr1fr167V582aFQiEVFBTo5ptv1q233ipJ2rNnj+677z79+c9/lmEYmjJlitavX6+LLroozZUfXZc3oP/z9l5J0l2XzGTFJAAApylCKQAYj/LLzTHj4sFjgT5zu1/bjsGVVe1/kwIeaf975oizZkuls80tf/EtgGXzpZzh/alG47TbNG1inqZNzBvxecMw1NMfMgOq3qHB1eDKq4N9AYWjhpq6B9TUPfo2wTxHlioS2wNzVFngjG0bNFdblRfkyJHFL73ILNdee628Xq+2bt2q4uJi7dixQ8uXL1c0GtUNN9ygZcuW6eqrr9Yvf/lLZWdn67nnntPll1+ud999V2eddVa6yz+if3trj/oCYc2rdOuKRVXpLgcAAJwiFsMwjHQXkSoej0cFBQXq7e2V233svzgBwLgVDkqdu4ff/S8w8qol5RRIuaVS7kQpb6L5NbdUyi2R8kqTH9vzhm0L/MzlRaJq7wskbw2MbxmMrbzq7g8d07lK8hxDAiszrIr3taooyNHEPIeybNYTqheZayzOIZxOp5599lmtXLkycez222/X3r17df/992vx4sXD6v3c5z6na665RnfcccdRz5+uz9zQ6dNFP/wvhaOGfnn9eVoyffjdQwEAwNh2rPOItK6U2rRpkx5++GH19PSosrJSjz76qJYsWTLiaxsbG3XXXXdpy5YtkqSzzz5b//qv/6qamppUlgwA40uWXSqfb444w5B69ieHVG3bJU+z5O81R9enx3DunMMCq5IhgVbsa/yxc4K5FfHwU9isieboo4lvE2yJbQk0V16ZK67ix/2hqDq9AXV6A9reNHLgZrWYwVV5QY7K3Dkqd+cc9tih8gKn8hwsQkZqnH322XrxxRd12WWXyWq1yuv16u2339bVV1+tmTNnyu12a/PmzVq9erUkqa6uTnv27NHSpUvTW/hR/PMbuxSOGrpw5kQCKQAATnNpmzk//fTTuu+++/TWW29p9uzZ+o//+A9deuml+vDDDzV16tSk14ZCIV188cW64oor9PTTT8tqteruu+/WihUr9NFHHykri18AACBlLBaz+fmEKdKcywePD3RL3nZz+DoGh7dd8nVKvvbBxyGfFPZLvQfMcdT3tEqukiOswJqYHGZlORI/eizbBLv7Q+Zqq6StgoMrr9pj2wTb+wJq7wtIGmWlmMytgmXu0cOrioIcFec5ZKM5O07Q888/r1tuuUULFy7U0qVLtXXrVq1Zs0Y33XSTLBaLXn/9dd1666369a9/rdLSUh04cEC//e1vde655454vkAgoEAgkPje4/Gk6qMkfHigW/9ve6ssFuneL85O+fsDAIDUSlua89BDD+muu+7S7NnmhOOrX/2qfv7zn+vxxx/XI488kvTauro6VVRUaOPGjYlGtQ899JAeffRR7dy5UwsXLkx5/QCAwzgnmGPirKO/NuiLBVbx8Kr9sO+HBFoDhyQjGntNu9R+DLU4CkZZgTU00DK/tzjcKsq1qyjXrvlVBSOeLho11OkL6GBvQG0ev9o8fh3sjX31+NXaa37fFwjLGwjL2xHW3g7fqOXZrBaV5juGh1YF5rGKAqfK3Tly2ulzhdG1traqra1NS5Ys0Xnnnafdu3frxRdf1MqVK1VZWan6+npFo1Gdf/75Kikp0QcffKCXXnpJF1xwgez24Tcq2LBhgx566KE0fBKTYRja8GqdJOmrZ1ZrTsXY2CYJAABOnbT0lGpsbFRNTY127dqlmTNnJo4/+eSTiaDpaLZs2aIlS5Zo3759w1ZWjWYs9oMAABxFJCT1dx15BdbQQCt6bD2kEmyOI6/AyiuV3FWSu1Ky5x7xVL5AOCmwSnoc+9rRF1D0GP/mdedkHWG7oDmKXHZZWXV1yo21OYTH41Ftba1+8pOf6Etf+lLi+C233KKdO3fqe9/7nlasWKFPPvkk0erA7/dryZIlWrlypdavXz/snCOtlJo0aVLKPvPvdx7UDb/YKkeWVX+4e5kqCkbflgsAAMa2Md1Tqrm5WZJUWVmZdLyysjLx3JFs27ZNq1at0urVq48YSI2FZegAgBNkyx68W+DRGIbk7zlsBVbn6IFWsE+KBCRPkzmOJqfADKjyK8yQKh5Wxb7muis0raRw1K2CktmcvdMbTARVBz1DQqsh3/cHI/L4w/L4vdp90Dvq+bJtFpXmx0Iqd/KKq6FBVk42q65OJ3V1derq6tKyZcuSjl9yySX62c9+pi1btqi2tjap92ZOTo4uvPBCvf/++yOe0+FwyOFwjPjcqRaORLXxtb9Jkv5p6VQCKQAAxom0hFLZ2dmSJKs1+S5GFotFR1u49dhjj+nee+/V7bffru9+97tHfG26l6EDAFLMYhmyjXDm0V8f7I8FVUNXXB22AquvTfK0SEHvYCP39iOs6M12xYKqIaFVfkXicZa7SuX5xSovyJEmjXwKwzDUFwgnrbJKCq88frX1BtTlCygUMdTcM6DmnoEjftQJruxYYGWGVaX5Dk0cOvJyNDHfwZbBDDF37lyVlpbqO9/5jjZu3CiXy6X9+/drw4YNWr58uS688EJ9+9vf1lNPPaWrrrpKVqtV7777rp5++ml9+9vfTnf5wzy7tVF7O3wqyrVrzbJp6S4HAACkSFpCqerqaklSS0uLpk+fnjje0tKiqqqqEX8mGo3qxhtv1DvvvKO3335b55133lHfZ926dUm3PI4vQwcAQJJkd0n2ydKEyUd/rd9jhlN9LeZXT4t5x0HPkO8HDkmhfqlrjzlGY7MPWW1VOWzVlSW/Qu68MrnL8jWjLH/U04QiUbX3BQZDq97BHlfxfldtvX4FwlF194fU3R9SXVvfET9mniMrFlIdFlolwiuHSvMdKsq1K8tmPeK5cOrk5eXpnXfe0fr16zVr1ixFIhE5nU6tWrVKDzzwgHJzc/XSSy/pBz/4gdatW6dwOKzKykp973vf00033ZTu8pP4AmE9+nvzjp3f+sJ0uXOy01wRAABIlbSEUmVlZVq0aJFeffVVfetb30ocf/3117V8+fIRf+aee+7Rrl27tHXr1mPua5DOZegAgNNMjtscpUe4I1hoIDmk8jRLfa3JAZa3XYoEpZ795hiNxSrllR8WXA0NryqVnV+hqkKnqgpH3+pkGIZ6B0LJK656A+rwmv2tOvoC6vAG1O4JKBCOmo3aA2HVd47eqF0yF6UV59pVcnh4NeT70tgKLLczK3GjEpw8s2bN0jPPPDPq88uXLx91XjWWPPnHfer0BjS52KV/OO8YAmIAAHDaSNvd9+655x7dfffdWr58uWbOnKnf/va3euONN/TBBx8Me+3777+vTZs2qa6ubkw0FwUAYETZTql4mjlGEw5K3jbJ03rYSqvY43iIZUTMVVl9LdKR2i26SoaFVeZjc8ugxV2pQleuCl12zS4f/e9QwzDkDYSTgqrE48O+7/Sazdo7vUF1eoNHXX1lt1k1Md+hkpFWYOUNCbDyHfS+Gmfa+/z68Tv7JElrL5ktexar7wAAGE/SFkpdeeWV8ng8uuyyy+T1elVVVaVXXnlF06ZNU1NTkxYvXqxHH31Uq1at0u9+9zt5vV4tWrRo2HnuuOOOpC16AACMaVl2qbDGHKOJRsx+VodvDzw8wIoEpP5Oc7RtH/18wxq0x+4kaM02G8nb7LLYspVvsyvflq1aa7bktEt52VK1+bxsDsmaJ9nsilhs6g1a1NFvqGMgqg5fVAd9UbV7w+rwBdXRN7gKy+MPKxiJHlPfK0nKj20fLBlh5RXbB08///Lmp+oPRnTGpEKtWHAMNzMAAACnFYtxtM7ip5GxdjtnAACOm2FIA91DgquRAqxms0F7Ktns5rBmSTa7DFu2IpYshZWlkLIUNGwKGDb5ozb5o1b1R2zqD1vkC1vlN2wKGzbzdcpSWEMex46bw6awsmR35MiZkyOX0ymXy6l8l1PnX7hCkyorTvrHGo9ziFP9mfe09+mSf/mjIlFDz910vs6dWnTS3wMAAKTHsc4j0rZSCgAAnACLRXIVmaN8weivizdoT+pv1SKF/VIkZPa3ioSk6JDHRzw+5Fg0PPz9IkFzxMuUOdnIkpRzpM9zPIueopL6Y6PLPLR71jTpFIRSOPn+9+92KRI1dPHcMgIpAADGKUIpAABOZ8fSoP14RaNmMBUPooY+jox0fEjgFT0s/Bp2fPRgLBoJKhTwKxgMKhwKKBwMKBIOKhoOamJxycn/nDjpDMPQmTUTtLXhkO5Zfgr+bAIAgIxAKAUAAI6P1SpZ7WafrFS+rSRHbCAzWSwW3bxsmq5bMoXm9gAAjGN0CAUAAEBaEEgBADC+EUoBAAAAAAAg5QilAAAAAAAAkHKEUgAAAAAAAEg5QikAAAAAAACkHKEUAAAAAAAAUo5QCgAAAAAAAClHKAUAAAAAAICUI5QCAAAAAABAyhFKAQAAAAAAIOUIpQAAAAAAAJByWekuIJUMw5AkeTyeNFcCAAAySXzuEJ9LjAfMmwAAwPE61rnTuAql+vr6JEmTJk1KcyUAACAT9fX1qaCgIN1lpATzJgAAcKKONneyGOPof/lFo1G1tLQoPz9fFovlpJ/f4/Fo0qRJamxslNvtPunnx8nDtcocXKvMwbXKHFyrz84wDPX19amyslJW6/jofsC8CXFcq8zBtcocXKvMwbU6Psc6dxpXK6WsVquqq6tP+fu43W7+sGYIrlXm4FplDq5V5uBafTbjZYVUHPMmHI5rlTm4VpmDa5U5uFaf3bHMncbH/+oDAAAAAADAmEIoBQAAAAAAgJQjlDqJHA6H1q9fL4fDke5ScBRcq8zBtcocXKvMwbXCWMCfw8zBtcocXKvMwbXKHFyrU2tcNToHAAAAAADA2MBKKQAAAAAAAKQcoRQAAAAAAABSjlDqJNm0aZPmz5+v6upqnXvuuXrvvffSXRJG8NOf/lTz5s1TVVWV5syZox//+MfpLgnHoKmpSUVFRVq9enW6S8EI6uvrdcUVV6iqqkoVFRX6+te/rtbW1nSXhRF4vV7deeedmjp1qqqrqzVv3jw9/vjj6S4L4xRzp8zA3CnzMG8a+5g7ZQ7mTqceodRJ8PTTT+u+++7TCy+8oKamJt1zzz269NJLVV9fn+7SMMRTTz2lBx98UM8995yam5u1efNmfec739Gvf/3rdJeGIzAMQ9/85jdVXV2d7lIwgp6eHv393/+9Lr/8cjU1NWnfvn3Kzs7WY489lu7SMIJrr71WO3bs0NatW9XU1KRnnnlGGzZs4Hoh5Zg7ZQbmTpmHedPYx9wpszB3OvVodH4SzJgxQzfffLPuuOOOxLGVK1dqxowZeuSRR9JYGYa65ZZbtHTpUl155ZWJY3feeafq6+u1efPmNFaGI3n44Yf15ptvavHixWpoaNCmTZvSXRKGWL9+vT744AO9/PLLiWORSEQ2my2NVWE0TqdTzz77rFauXJk4dvvtt2vv3r166aWX0lgZxhvmTpmBuVPmYd409jF3yizMnU49VkqdoMbGRu3Zs0eXXXZZ0vHLL79cr732Wpqqwkh+9KMfJU2qJGnHjh1yu91pqghH8/HHH2vjxo164okn0l0KRvHSSy9pxYoVSceYVI1dZ599tl588UVFo1FJ5pL0t99+W5///OfTXBnGE+ZOmYO5U2Zh3pQZmDtlFuZOpx6h1Alqbm6WJFVWViYdr6ysTDyHsScUCum2227Tn/70J911113pLgcj8Pv9uuqqq7Rx40bV1tamuxyM4tNPP1VhYaFuuOEGTZ06VQsWLND3v/99hcPhdJeGETz//PPq6enRwoULtWbNGi1btkxr1qzRnXfeme7SMI4wd8pMzJ3GNuZNmYO5U2Zh7nTqEUqdoOzsbEmS1Zr8j9JisYidkWPTgQMHdMEFF+g///M/9e6772r+/PnpLgkjWLt2raZNm6brr78+3aXgCCKRiL7//e/r6quv1r59+/TCCy/omWee0T333JPu0jCC1tZWtbW1acmSJTrvvPPkdrv14osv0lwVKcXcKfMwdxr7mDdlDuZOmYW506lHKHWC4k0EW1pako63tLSoqqoqHSXhCLZt26ZzzjlHS5cu1YcffqhFixaluySM4I033tCzzz6rJ598Mt2l4Chqamp044036sILL5TFYtGsWbP0wAMP6Be/+EW6S8NhPB6PLr74Yt19993693//d1133XV66623VFtbq6uuuird5WEcYe6UWZg7jX3MmzILc6fMwdwpNQilTlBZWZkWLVqkV199Nen466+/ruXLl6epKozkwIEDWrFihR5//HE9/PDDcjgc6S4Jo3j11VfV3t6usrIyWSwWWSwWPfTQQ/r5z38ui8WiN998M90lIuaCCy5QIBAYdpx/v8aeuro6dXV1admyZUnHL7nkEr3//vvpKQrjEnOnzMHcKTMwb8oszJ0yB3OnFDFwwn71q18ZVVVVxq5duwzDMIzf/OY3htvtNvbs2ZPmyjDUF7/4RePBBx9Mdxk4TuvXrze++c1vprsMHObTTz81KisrjT/84Q+GYRhGQ0ODMXfuXOOBBx5Ic2U4XF9fn1FaWmrcdttths/nMwzDvF6LFy82vvzlL6e5Oow3zJ0yA3OnzMW8aexi7pQ5mDulRla6Q7HTwZVXXimPx6PLLrtMXq9XVVVVeuWVVzRt2rR0l4YhXnvtNW3btm3Epc1NTU1pqAjIfNOnT9evfvUrrV27VvX19crPz9fq1au1bt26dJeGw+Tl5emdd97R+vXrNWvWLEUiETmdTq1atUoPPPBAusvDOMPcKTMwdwJOPuZOmYO5U2pYDIOOkgAAAAAAAEgtekoBAAAAAAAg5QilAAAAAAAAkHKEUgAAAAAAAEg5QikAAAAAAACkHKEUAAAAAAAAUo5QCgAAAAAAAClHKAUAAAAAAICUI5QCAAAAAABAyhFKAchoq1evVm5urqqrq5PG2rVrU/L+U6ZM0aZNm1LyXgAAACeKuROAsSQr3QUAwIlatWoVkxsAAIBjxNwJwFjBSikAAAAAAACkHKEUgNPWpk2bdPbZZ2vTpk2aNWuWSktLdc0116i7uzvxGo/Ho9tuu021tbWqqanRl770Je3duzfpPD/5yU80Z84cVVVV6YwzztArr7yS9PzBgwf15S9/WVVVVaqtrdXLL7+cks8HAABwMjF3ApBqhFIATmt1dXX6/e9/r48++kh79+5Va2urrr/+ekmSYRhasWKFmpqatH37djU0NOjcc8/V4sWL1dbWJkn60Y9+pHXr1umZZ55Rc3OznnjiCa1Zs0ZdXV2J9/jhD3+o+++/X83Nzbr11lv1j//4jzIMIy2fFwAA4EQwdwKQShaDf/sBZLDVq1frhRdeUElJSdLxnTt36rnnntNtt92m9vZ2OZ1OSdLHH3+sM844Q+3t7dq9e7cuuOACdXR0qLi4OPGzCxcu1De+8Q3dd999mj59um6++WbdeeedieeDwaDsdrsks1nnDTfcoPvvv1+StHv3bs2aNUutra0qLy8/1R8fAADgM2HuBGAsodE5gIz3ta99bdRmncXFxYlJlSTNnDlTktTQ0KCGhgaVlJQkTaokafbs2WpoaJAk7d+/X3PmzEl6Pj6piquqqhr2nN/vP67PAgAAcKoxdwIwVrB9D8BpraenR5FIJPF9fX29JGny5MmqqalRZ2enDh06lPQzu3btUk1NTeJ1u3btSno+FAqd4qoBAADSg7kTgFQilAJwWvN4PLrrrrsUDAbV39+vtWvX6oorrlBpaamWLFmic845RzfeeKN8Pp8Mw9APfvADNTY26rrrrpMk3X777dqwYYO2bdsmSdqzZ4/mz5+vnTt3pvNjAQAAnBLMnQCkEtv3AGS8559/Xm+++WbSsTPPPFNf+cpXVFNTo6lTp2r+/PnyeDy66KKL9Nhjj0mSrFarXn/9dd17772aN2+eIpGIFi1apC1btiSWld9yyy3KycnRNddco97eXhUVFWn9+vWaO3duyj8nAADAycDcCcBYQaNzAKetTZs26cEHH0z0OAAAAMDomDsBSDW27wEAAAAAACDlCKUAAAAAAACQcmzfAwAAAAAAQMqxUgoAAAAAAAApRygFAAAAAACAlCOUAgAAAAAAQMoRSgEAAAAAACDlCKUAAAAAAACQcoRSAAAAAAAASDlCKQAAAAAAAKQcoRQAAAAAAABSjlAKAAAAAAAAKff/Ac6Jb0D7CvxVAAAAAElFTkSuQmCC\n"
          },
          "metadata": {}
        }
      ],
      "source": [
        "def plot_learning_curves(train_losses, test_losses, accuracies):\n",
        "    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n",
        "\n",
        "    # 損失の推移\n",
        "    ax1.plot(train_losses, label='Train Loss')\n",
        "    ax1.plot(test_losses, label='Test Loss')\n",
        "    ax1.set_xlabel('Epoch')\n",
        "    ax1.set_ylabel('Loss')\n",
        "    ax1.legend()\n",
        "    ax1.set_title('Loss Curves')\n",
        "\n",
        "    # 精度の推移\n",
        "    ax2.plot(accuracies, label='Test Accuracy')\n",
        "    ax2.set_xlabel('Epoch')\n",
        "    ax2.set_ylabel('Accuracy (%)')\n",
        "    ax2.legend()\n",
        "    ax2.set_title('Accuracy Curve')\n",
        "\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "plot_learning_curves(train_losses, test_losses, accuracies)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VW3tpOAr7Y6W"
      },
      "source": [
        "## 9. モデルの保存と読み込み"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "4rWOm85A7Y6W",
        "outputId": "b91eaf53-f50c-4b0e-b0f5-8a7b32420b6e"
      },
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "MNISTClassifier(\n",
              "  (layer1): Linear(in_features=784, out_features=128, bias=True)\n",
              "  (layer2): Linear(in_features=128, out_features=64, bias=True)\n",
              "  (layer3): Linear(in_features=64, out_features=10, bias=True)\n",
              ")"
            ]
          },
          "metadata": {},
          "execution_count": 11
        }
      ],
      "source": [
        "# モデルの保存\n",
        "torch.save(model.state_dict(), 'mnist_model.pth')\n",
        "\n",
        "# モデルの読み込み\n",
        "model = MNISTClassifier()\n",
        "model.load_state_dict(torch.load('mnist_model.pth'))\n",
        "model.eval()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0j7lasZj7Y6W"
      },
      "source": [
        "## 10. 実際の予測例"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 465
        },
        "id": "ETnGonpV7Y6X",
        "outputId": "937a4b11-e2ac-444c-8faa-79d9e0b0b089"
      },
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "実際のラベル: 6\n",
            "予測: 6, 信頼度: 0.99\n"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ],
            "image/png": "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\n"
          },
          "metadata": {}
        }
      ],
      "source": [
        "def predict_single_image(model, image):\n",
        "    model.eval()\n",
        "    with torch.no_grad():\n",
        "        image = image.to(device)\n",
        "        image = image.unsqueeze(0)  # バッチ次元を追加\n",
        "        output = model(image)\n",
        "        prediction = output.argmax(dim=1)\n",
        "        confidence = F.softmax(output, dim=1).max()\n",
        "        return prediction.item(), confidence.item()\n",
        "\n",
        "# 使用例\n",
        "i = 50\n",
        "test_image, test_label = test_dataset[i]\n",
        "prediction, confidence = predict_single_image(model, test_image)\n",
        "print(f'実際のラベル: {test_label}')\n",
        "print(f'予測: {prediction}, 信頼度: {confidence:.2f}')\n",
        "\n",
        "# 画像の表示\n",
        "plt.imshow(test_image.squeeze(), cmap='gray')\n",
        "plt.title(f'予測: {prediction} (信頼度: {confidence:.2f})')\n",
        "plt.axis('off')\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lmGoTAP77Y6X"
      },
      "outputs": [],
      "source": []
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.12"
    },
    "colab": {
      "provenance": [],
      "gpuType": "T4"
    },
    "accelerator": "GPU"
  },
  "nbformat": 4,
  "nbformat_minor": 0
}