{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "71c3af11-0b78-4c07-b73b-dd610890b735",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/anaconda3/envs/yt38/lib/python3.8/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "import torchvision.transforms as transforms\n",
    "from torch.utils.data import DataLoader\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "01231eb4-ae01-40b0-bb47-d863b358b5f9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 데이터셋을 불러오고 전처리하는 부분\n",
    "# 데이터를 텐서로 변환하고 정규화합니다. CIFAR-10의 평균과 표준편차를 사용하여 정규화합니다.\n",
    "transform = transforms.Compose(\n",
    "    [transforms.ToTensor(),\n",
    "     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "58532ed1-13f1-45b6-8b3c-eac4c7225d49",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Files already downloaded and verified\n",
      "Files already downloaded and verified\n"
     ]
    }
   ],
   "source": [
    "# train 데이터셋 로드\n",
    "trainset = torchvision.datasets.CIFAR10(root='./data', train=True,\n",
    "                                        download=True, transform=transform)\n",
    "trainloader = DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)\n",
    "\n",
    "# test 데이터셋 로드\n",
    "testset = torchvision.datasets.CIFAR10(root='./data', train=False,\n",
    "                                       download=True, transform=transform)\n",
    "testloader = DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "eb956f82-d2af-4476-b76e-143122b54446",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 간단한 CNN 모델을 정의합니다.\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(3, 6, 5)\n",
    "        self.pool = nn.MaxPool2d(2, 2)\n",
    "        self.conv2 = nn.Conv2d(6, 16, 5)\n",
    "        self.fc1 = nn.Linear(16 * 5 * 5, 120)\n",
    "        self.fc2 = nn.Linear(120, 84)\n",
    "        self.fc3 = nn.Linear(84, 10)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.pool(nn.functional.relu(self.conv1(x)))\n",
    "        x = self.pool(nn.functional.relu(self.conv2(x)))\n",
    "        x = torch.flatten(x, 1) # flatten all dimensions except batch\n",
    "        x = nn.functional.relu(self.fc1(x))\n",
    "        x = nn.functional.relu(self.fc2(x))\n",
    "        x = self.fc3(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c0c83da0-57e0-4e1b-94c8-e5c33ec52639",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 모델 인스턴스를 생성합니다.\n",
    "net = Net()\n",
    "\n",
    "# 손실 함수와 옵티마이저를 정의합니다.\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "3e2a09a5-1549-4282-a3c5-bd4a1b8ab642",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 정확도 계산 함수\n",
    "def calculate_accuracy(loader):\n",
    "    correct = 0\n",
    "    total = 0\n",
    "    total_loss = 0.0\n",
    "    with torch.no_grad():\n",
    "        for data in loader:\n",
    "            images, labels = data\n",
    "            outputs = net(images)\n",
    "            loss = criterion(outputs, labels)\n",
    "            total_loss += loss.item()\n",
    "            _, predicted = torch.max(outputs.data, 1)\n",
    "            total += labels.size(0)\n",
    "            correct += (predicted == labels).sum().item()\n",
    "    accuracy = 100 * correct / total\n",
    "    return accuracy, total_loss / len(loader)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "93441db5-7d6a-40cd-a94f-65efaf887e9c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1:\n",
      "Train - Loss: 1.343, Accuracy: 51.92%\n",
      "Test - Loss: 1.362, Accuracy: 51.21%\n",
      "Epoch 2:\n",
      "Train - Loss: 1.187, Accuracy: 58.56%\n",
      "Test - Loss: 1.243, Accuracy: 55.92%\n",
      "Epoch 3:\n",
      "Train - Loss: 1.069, Accuracy: 61.83%\n",
      "Test - Loss: 1.190, Accuracy: 58.04%\n",
      "Epoch 4:\n",
      "Train - Loss: 1.040, Accuracy: 63.48%\n",
      "Test - Loss: 1.175, Accuracy: 58.87%\n",
      "Epoch 5:\n",
      "Train - Loss: 0.908, Accuracy: 67.71%\n",
      "Test - Loss: 1.123, Accuracy: 61.51%\n",
      "Epoch 6:\n",
      "Train - Loss: 0.851, Accuracy: 70.11%\n",
      "Test - Loss: 1.075, Accuracy: 62.86%\n",
      "Epoch 7:\n",
      "Train - Loss: 0.827, Accuracy: 70.71%\n",
      "Test - Loss: 1.091, Accuracy: 63.12%\n",
      "Epoch 8:\n",
      "Train - Loss: 0.792, Accuracy: 72.13%\n",
      "Test - Loss: 1.116, Accuracy: 62.37%\n",
      "Epoch 9:\n",
      "Train - Loss: 0.797, Accuracy: 71.76%\n",
      "Test - Loss: 1.149, Accuracy: 62.64%\n",
      "Epoch 10:\n",
      "Train - Loss: 0.716, Accuracy: 74.68%\n",
      "Test - Loss: 1.126, Accuracy: 62.93%\n",
      "Finished Training\n"
     ]
    }
   ],
   "source": [
    "# 학습 시작\n",
    "for epoch in range(10):  # 데이터셋을 여러 번(10번) 반복합니다.\n",
    "    running_loss = 0.0\n",
    "    for i, data in enumerate(trainloader, 0):\n",
    "        inputs, labels = data\n",
    "\n",
    "        optimizer.zero_grad()\n",
    "\n",
    "        outputs = net(inputs)\n",
    "        loss = criterion(outputs, labels)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "\n",
    "        running_loss += loss.item()\n",
    "\n",
    "    train_accuracy, train_loss = calculate_accuracy(trainloader)\n",
    "    test_accuracy, test_loss = calculate_accuracy(testloader)\n",
    "    \n",
    "    print(f'Epoch {epoch + 1}:')\n",
    "    print(f'Train - Loss: {train_loss:.3f}, Accuracy: {train_accuracy:.2f}%')\n",
    "    print(f'Test - Loss: {test_loss:.3f}, Accuracy: {test_accuracy:.2f}%')\n",
    "    \n",
    "    # 모델의 가중치를 저장합니다.\n",
    "    torch.save(net.state_dict(), f'./cifar_net_epoch_{epoch + 1}.pth')\n",
    "\n",
    "print('Finished Training')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64ffe3d8-aefe-420a-a399-0b2dce0e156a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e00b51ca-bf98-441f-950b-04d3b28515ce",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "yt38",
   "language": "python",
   "name": "yt38"
  },
  "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.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
