{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bee88c73-8bd2-4d3c-ae56-c289c8262a48",
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from torch.utils.data import TensorDataset, DataLoader\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "500c43c0-2cd6-44f1-b189-c69646b3ceeb",
   "metadata": {},
   "source": [
    "# Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9616b609-a2cc-405d-a23f-84723402fb1d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load to Pandas Dataframe\n",
    "train_path = 'training.dat'\n",
    "test_path = 'testing.dat'\n",
    "\n",
    "train_df = pd.read_csv(train_path, delim_whitespace=True, header=None)\n",
    "test_df = pd.read_csv(test_path, delim_whitespace=True, header=None)\n",
    "\n",
    "# Assuming that all columns are features and classes are based on row indices\n",
    "X_train = torch.tensor(train_df.values).float()  # Convert feature data to tensor\n",
    "X_test = torch.tensor(test_df.values).float()    # Convert feature data to tensor\n",
    "\n",
    "# Create labels based on row indices\n",
    "y_train = torch.tensor([(i // 25) for i in range(len(train_df))]).long()\n",
    "y_test = torch.tensor([(i // 25) for i in range(len(test_df))]).long()\n",
    "\n",
    "# Create data loaders\n",
    "train_loader = DataLoader(TensorDataset(X_train, y_train), batch_size=5, shuffle=True)\n",
    "test_loader = DataLoader(TensorDataset(X_test, y_test), batch_size=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9367529a-9ce1-4aed-ae7a-9ad49b0870bb",
   "metadata": {},
   "source": [
    "# Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4723d5ce-2f2d-4dc9-b4a4-40639588b152",
   "metadata": {},
   "outputs": [],
   "source": [
    "class NeuralNetwork(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(NeuralNetwork, self).__init__()\n",
    "        self.hidden1 = nn.Linear(4, 8)\n",
    "        self.hidden2 = nn.Linear(8, 8)\n",
    "        self.hidden3 = nn.Linear(8, 8)\n",
    "        self.hidden4 = nn.Linear(8, 8)\n",
    "        self.output = nn.Linear(8, 3)\n",
    "        self.relu = nn.ReLU()\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.relu(self.hidden1(x))\n",
    "        x = self.relu(self.hidden2(x))\n",
    "        x = self.relu(self.hidden3(x))\n",
    "        x = self.relu(self.hidden4(x))\n",
    "        x = self.output(x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b08bc191-9c9c-423c-8e3c-597099f2a519",
   "metadata": {},
   "source": [
    "# Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f7f3d240-0ba4-443e-9b1c-172419c311d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Instantiate the model, loss function, and optimizer\n",
    "model = NeuralNetwork()\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "optimizer = optim.Adam(model.parameters(), lr=0.001)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "56b466a1-cdaa-4143-b097-6737a91eeed3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1, Loss: 1.1656708717346191\n",
      "Epoch 2, Loss: 1.069056749343872\n",
      "Epoch 3, Loss: 1.1333191394805908\n",
      "Epoch 4, Loss: 1.1097159385681152\n",
      "Epoch 5, Loss: 1.0479941368103027\n",
      "Epoch 6, Loss: 1.1416243314743042\n",
      "Epoch 7, Loss: 1.016518235206604\n",
      "Epoch 8, Loss: 1.1750520467758179\n",
      "Epoch 9, Loss: 1.0874340534210205\n",
      "Epoch 10, Loss: 1.0893971920013428\n",
      "Epoch 11, Loss: 1.0989606380462646\n",
      "Epoch 12, Loss: 1.1664495468139648\n",
      "Epoch 13, Loss: 1.0913177728652954\n",
      "Epoch 14, Loss: 1.0568711757659912\n",
      "Epoch 15, Loss: 0.9801815152168274\n",
      "Epoch 16, Loss: 0.9334077835083008\n",
      "Epoch 17, Loss: 0.7538875341415405\n",
      "Epoch 18, Loss: 0.7881473302841187\n",
      "Epoch 19, Loss: 0.7299363613128662\n",
      "Epoch 20, Loss: 0.2598203122615814\n",
      "Epoch 21, Loss: 0.7928000688552856\n",
      "Epoch 22, Loss: 0.7305868864059448\n",
      "Epoch 23, Loss: 0.2939522862434387\n",
      "Epoch 24, Loss: 0.43748903274536133\n",
      "Epoch 25, Loss: 0.25262290239334106\n",
      "Epoch 26, Loss: 0.2567386031150818\n",
      "Epoch 27, Loss: 0.32417288422584534\n",
      "Epoch 28, Loss: 0.36710914969444275\n",
      "Epoch 29, Loss: 0.44611167907714844\n",
      "Epoch 30, Loss: 0.2571166157722473\n",
      "Epoch 31, Loss: 0.3475134074687958\n",
      "Epoch 32, Loss: 0.33021003007888794\n",
      "Epoch 33, Loss: 0.24303965270519257\n",
      "Epoch 34, Loss: 0.14755365252494812\n",
      "Epoch 35, Loss: 0.07536564767360687\n",
      "Epoch 36, Loss: 0.16837753355503082\n",
      "Epoch 37, Loss: 0.1387643814086914\n",
      "Epoch 38, Loss: 0.44958290457725525\n",
      "Epoch 39, Loss: 0.09252478182315826\n",
      "Epoch 40, Loss: 0.10783408582210541\n",
      "Epoch 41, Loss: 0.031535036861896515\n",
      "Epoch 42, Loss: 0.06791599839925766\n",
      "Epoch 43, Loss: 0.05487314984202385\n",
      "Epoch 44, Loss: 0.07081137597560883\n",
      "Epoch 45, Loss: 0.039346300065517426\n",
      "Epoch 46, Loss: 0.02455393224954605\n",
      "Epoch 47, Loss: 0.04027646780014038\n",
      "Epoch 48, Loss: 0.22815446555614471\n",
      "Epoch 49, Loss: 0.006961571518331766\n",
      "Epoch 50, Loss: 0.04802575707435608\n"
     ]
    }
   ],
   "source": [
    "# Training loop\n",
    "for epoch in range(50):  # number of epochs\n",
    "    for inputs, labels in train_loader:\n",
    "        optimizer.zero_grad()\n",
    "        outputs = model(inputs)\n",
    "        loss = criterion(outputs, labels) # 오차(오류) 계산\n",
    "        loss.backward() # 오차(오류) 역전파\n",
    "        optimizer.step() # 모델 가중치값 업데이트 -> Adam optimizer 기반\n",
    "\n",
    "    print(f'Epoch {epoch+1}, Loss: {loss.item()}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "faad1d77-d622-4d15-9a8a-82d5af1cfdec",
   "metadata": {},
   "source": [
    "# Test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "765d9b68-6e8b-4c34-a03c-c56356fed22f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 94.66666666666667%\n"
     ]
    }
   ],
   "source": [
    "# Testing the model\n",
    "correct = 0\n",
    "total = 0\n",
    "with torch.no_grad():\n",
    "    for inputs, labels in test_loader:\n",
    "        outputs = model(inputs)\n",
    "        _, predicted = torch.max(outputs.data, 1)\n",
    "        total += labels.size(0)\n",
    "        correct += (predicted == labels).sum().item()\n",
    "\n",
    "print(f'Accuracy: {100 * correct / total}%')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "prac",
   "language": "python",
   "name": "prac"
  },
  "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.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
