diff --git "a/[AI_Essential]_Document_Classification_\354\206\224\353\243\250\354\205\230.ipynb" "b/[AI_Essential]_Document_Classification_\354\206\224\353\243\250\354\205\230.ipynb"
new file mode 100644
index 00000000..e49a3689
--- /dev/null
+++ "b/[AI_Essential]_Document_Classification_\354\206\224\353\243\250\354\205\230.ipynb"
@@ -0,0 +1,632 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "view-in-github",
+ "colab_type": "text"
+ },
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "C3HNZJH5LuqI",
+ "metadata": {
+ "id": "C3HNZJH5LuqI"
+ },
+ "source": [
+ "# 로이터 뉴스 분류\n",
+ "- **목표**\n",
+ " - 이 워크샵의 목표는 로이터 뉴스 기사 데이터셋을 사용하여 딥러닝 모델을 학습시키고, 다양한 카테고리의 뉴스 기사를 분류하는 것입니다.\n",
+ "\n",
+ "- **데이터셋 정보**\n",
+ " - 데이터는 (batch, sequence_length) 형태로, 여기서 batch는 한 번에 처리하는 뉴스 기사 수, sequence_length는 각 기사의 단어 시퀀스 길이를 나타냅니다.\n",
+ " - 데이터셋은 총 46개의 클래스(예: 무역, 스포츠, 경제, 기술, 의료 등)로 구성되어 있습니다.\n",
+ " - 데이터는 훈련용 데이터와 테스트용 데이터로 나뉘며, 훈련 데이터는 모델 학습에 사용되고, 테스트 데이터는 학습한 모델의 성능을 평가하는 데 사용됩니다.\n",
+ "\n",
+ "- **문제 유형**\n",
+ " - 이 워크샵은 다중 클래스 분류 문제로, 각 뉴스 기사가 어떤 카테고리에 속하는지를 예측하는 것이 목표입니다. 모델의 성능은 Accuracy 지표로 측정됩니다."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "FerWbWa8ML9S",
+ "metadata": {
+ "id": "FerWbWa8ML9S"
+ },
+ "source": [
+ "## 1. 환경 설정"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "fbebc02c",
+ "metadata": {
+ "id": "fbebc02c"
+ },
+ "outputs": [],
+ "source": [
+ "%%capture\n",
+ "!pip install JAEN -qU"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2b192c23",
+ "metadata": {
+ "id": "2b192c23",
+ "outputId": "b46a090a-a8a1-4273-dd40-d9129cc9ff94",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "device(type='cpu')"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 2
+ }
+ ],
+ "source": [
+ "# 그대로 실행하세요.\n",
+ "import torch\n",
+ "import torch.nn as nn\n",
+ "import torch.optim as optim\n",
+ "from torchinfo import summary\n",
+ "\n",
+ "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
+ "device"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4144477e",
+ "metadata": {
+ "id": "4144477e"
+ },
+ "outputs": [],
+ "source": [
+ "# 사용자명을 입력하세요. (이름이 아니여도 괜찮습니다.)\n",
+ "username = \"\"\n",
+ "assert username, \"username 변수에 값이 설정되지 않았습니다.\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "MkvHc266MWva",
+ "metadata": {
+ "id": "MkvHc266MWva",
+ "jupyter": {
+ "outputs_hidden": true
+ }
+ },
+ "outputs": [],
+ "source": [
+ "# 그대로 실행하세요.\n",
+ "from JAEN.competition import Competition\n",
+ "comp = Competition(\n",
+ " username=username,\n",
+ " course_name='AI Essential',\n",
+ " course_round='0224(4)',\n",
+ " competition_name='Document Classification'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "OSiIE4tdPcSV",
+ "metadata": {
+ "id": "OSiIE4tdPcSV"
+ },
+ "source": [
+ "## 2. 데이터 로드"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "Cwo9d1i-ON3u",
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "Cwo9d1i-ON3u",
+ "outputId": "0983be1a-8429-4f09-bdee-e37c4fc1670e"
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "(torch.Size([460, 100]), torch.Size([460]), torch.Size([212, 100]))"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 5
+ }
+ ],
+ "source": [
+ "from JAEN.datasets import load_documents\n",
+ "X, y, TEST = load_documents()\n",
+ "X.shape, y.shape, TEST.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import numpy as np\n",
+ "len(np.unique(y)), np.unique(y)"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "MIFZSQ9xid3i",
+ "outputId": "c8ce8df6-56d0-4539-99f4-c302f2ce8c86"
+ },
+ "id": "MIFZSQ9xid3i",
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "(46,\n",
+ " array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,\n",
+ " 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,\n",
+ " 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45]))"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 7
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "X[:5, :10]"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "Bn-XhgN10e1O",
+ "outputId": "08be42ce-48b0-493a-c5cd-73e0981e6950"
+ },
+ "id": "Bn-XhgN10e1O",
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "tensor([[ 547, 216, 16134, 1660, 7, 4, 993, 5, 988, 11043],\n",
+ " [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
+ " [ 5, 1458, 1256, 6539, 9, 219, 1528, 87, 13, 1528],\n",
+ " [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
+ " [ 22, 628, 384, 10, 176, 13, 4, 141, 740, 2687]])"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 9
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "I_Vc3a22PgBm",
+ "metadata": {
+ "id": "I_Vc3a22PgBm"
+ },
+ "source": [
+ "## 3. 제출 예시 코드"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "933af893",
+ "metadata": {
+ "id": "933af893",
+ "outputId": "e8b1b3a1-a75c-4bb6-c60d-f4438d346dc8"
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n",
+ " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])"
+ ]
+ },
+ "execution_count": 36,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# TEST의 예측값 대입 (지금은 0으로 채워진 값 대입)\n",
+ "comp.prediction = torch.zeros(212)\n",
+ "comp.prediction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "wvkBKJUbKsW9",
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "wvkBKJUbKsW9",
+ "outputId": "806a3d54-7257-458a-def7-3192d5d070aa"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[Document Classification 평가 결과]\n",
+ " AI Essential 1107(1) 과정 Hello World님의 점수는 0.02358490566037736 입니다."
+ ]
+ }
+ ],
+ "source": [
+ "# 제출\n",
+ "comp.submit()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4wNCB3ATlBe4",
+ "metadata": {
+ "id": "4wNCB3ATlBe4"
+ },
+ "source": [
+ "## 4. 순환신경망 모델을 구성하고 학습하여 TEST를 예측해보세요.\n",
+ "- TEST의 예측 결과는 `comp.prediction`에 대입해주세요. **torch.tensor** 형태여야합니다."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "KtwmpH1EibaM",
+ "metadata": {
+ "id": "KtwmpH1EibaM"
+ },
+ "outputs": [],
+ "source": [
+ "from torch.utils.data import DataLoader, TensorDataset\n",
+ "# TensorDataset을 사용하여 데이터셋 생성\n",
+ "train_dataset = TensorDataset(X, y)\n",
+ "test_dataset = TensorDataset(TEST)\n",
+ "\n",
+ "# DataLoader 생성\n",
+ "batch_size = 32 # 배치 크기 설정\n",
+ "train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n",
+ "test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "for x, y in train_loader:\n",
+ " print(x.shape, y.shape)\n",
+ " print(x[:5, :10], y[:5])\n",
+ " break"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "HRbqEpBMhouj",
+ "outputId": "4b355b9d-0d51-4091-fca9-786e6d75b6e9"
+ },
+ "id": "HRbqEpBMhouj",
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "torch.Size([32, 100]) torch.Size([32])\n",
+ "tensor([[ 47, 18, 470, 2023, 27, 1504, 1505, 31, 1273, 52],\n",
+ " [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n",
+ " [2400, 260, 489, 996, 928, 401, 401, 162, 1661, 1527],\n",
+ " [ 84, 27, 1768, 6, 344, 131, 2519, 4, 2167, 3030],\n",
+ " [1518, 1415, 28, 1734, 72, 7, 286, 177, 237, 173]]) tensor([13, 38, 1, 34, 30])\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "-37EJXcZibcK",
+ "metadata": {
+ "id": "-37EJXcZibcK",
+ "outputId": "69060a0b-d373-49ea-b38c-1a1e8c6355d4",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "=================================================================\n",
+ "Layer (type:depth-idx) Param #\n",
+ "=================================================================\n",
+ "ReutersLSTMModel --\n",
+ "├─Embedding: 1-1 6,400,000\n",
+ "├─LSTM: 1-2 395,264\n",
+ "├─Linear: 1-3 11,822\n",
+ "=================================================================\n",
+ "Total params: 6,807,086\n",
+ "Trainable params: 6,807,086\n",
+ "Non-trainable params: 0\n",
+ "================================================================="
+ ]
+ },
+ "metadata": {},
+ "execution_count": 12
+ }
+ ],
+ "source": [
+ "import torch\n",
+ "import torch.nn as nn\n",
+ "\n",
+ "class ReutersLSTMModel(nn.Module):\n",
+ " def __init__(self, vocab_size, embedding_dim, hidden_dim, output_size):\n",
+ " super().__init__()\n",
+ " # 임베딩 레이어\n",
+ " self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
+ " # LSTM 레이어\n",
+ " self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)\n",
+ " # FC 레이어\n",
+ " self.fc = nn.Linear(hidden_dim, output_size)\n",
+ " # Softmax는 CrossEntropyLoss에서 내부적으로 적용되므로 여기서는 생략\n",
+ "\n",
+ " def forward(self, x):\n",
+ " # 입력 시퀀스를 임베딩\n",
+ " x = self.embedding(x)\n",
+ " # LSTM 레이어\n",
+ " lstm_out, _ = self.lstm(x)\n",
+ " # 마지막 시퀀스의 출력(hidden state)을 사용\n",
+ " out = self.fc(lstm_out[:, -1, :])\n",
+ " return out\n",
+ "\n",
+ "# 모델 초기화\n",
+ "vocab_size = 50000 # 단어 사전 크기\n",
+ "embedding_dim = 128 # 임베딩 차원\n",
+ "hidden_dim = 256 # LSTM의 은닉 상태 크기\n",
+ "output_size = 46 # 로이터 뉴스의 클래스 수\n",
+ "\n",
+ "model = ReutersLSTMModel(vocab_size, embedding_dim, hidden_dim, output_size)\n",
+ "\n",
+ "# 모델 구조 확인\n",
+ "summary(model)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "a2237784",
+ "metadata": {
+ "id": "a2237784"
+ },
+ "outputs": [],
+ "source": [
+ "# 손실함수 및 옵티마이저 설정\n",
+ "criterion = nn.CrossEntropyLoss() # 크로스 엔트로피 손실 함수\n",
+ "optimizer = optim.Adam(model.parameters())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3e1ded1c",
+ "metadata": {
+ "id": "3e1ded1c",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "11cb3816-0682-40f3-a1a7-f96ebe820418"
+ },
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Epoch [0/100], Loss: 3.8606094837188722\n",
+ "Epoch [10/100], Loss: 0.0766895482937495\n",
+ "Epoch [20/100], Loss: 0.012652608721206585\n",
+ "Epoch [30/100], Loss: 0.0071266596826414265\n",
+ "Epoch [40/100], Loss: 0.005854664091020823\n",
+ "Epoch [50/100], Loss: 0.00477049780699114\n",
+ "Epoch [60/100], Loss: 0.004697613829436401\n",
+ "Epoch [70/100], Loss: 0.004398201697040349\n",
+ "Epoch [80/100], Loss: 0.00396974435619389\n",
+ "Epoch [90/100], Loss: 0.18926401883363725\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 모델 학습 과정 구현\n",
+ "epochs = 100\n",
+ "for epoch in range(epochs):\n",
+ " running_loss = 0.0\n",
+ " model.train()\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()\n",
+ " running_loss += loss.item()\n",
+ "\n",
+ " if epoch % 10 == 0:\n",
+ " print(f'Epoch [{epoch}/{epochs}], Loss: {running_loss / len(train_loader)}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c1439106",
+ "metadata": {
+ "id": "c1439106",
+ "outputId": "9c4a9f2f-1190-4c35-bb4d-085a1b0f6c05",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "tensor([44, 33, 29, 44, 35, 3, 44, 33, 19, 35])\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 학습된 모델의 TEST 예측\n",
+ "import torch.nn.functional as F\n",
+ "\n",
+ "# TEST 데이터에 대한 예측\n",
+ "model.eval() # 모델을 평가 모드로 설정\n",
+ "all_predictions = []\n",
+ "\n",
+ "# DataLoader를 사용하여 배치 단위로 예측\n",
+ "with torch.no_grad():\n",
+ " for inputs in test_loader:\n",
+ " outputs = model(inputs[0]) # 배치의 입력을 모델에 전달\n",
+ "\n",
+ " # 소프트맥스를 사용하여 확률로 변환\n",
+ " probabilities = F.softmax(outputs, dim=1)\n",
+ "\n",
+ " # 가장 높은 확률을 가진 클래스를 선택\n",
+ " predicted_labels = torch.argmax(probabilities, dim=1)\n",
+ " all_predictions.append(predicted_labels)\n",
+ "\n",
+ "# 모든 배치의 예측 결과를 하나의 텐서로 결합\n",
+ "all_predictions = torch.cat(all_predictions)\n",
+ "\n",
+ "# 예측 레이블 확인\n",
+ "print(all_predictions[:10])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8fb7b590",
+ "metadata": {
+ "id": "8fb7b590",
+ "outputId": "45bbda27-85a6-490b-c71c-8f662dcf346e",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ "tensor([44, 33, 29, 44, 35, 3, 44, 33, 19, 35, 10, 29, 44, 33, 24, 44, 44, 27,\n",
+ " 26, 28, 44, 27, 33, 44, 29, 29, 42, 31, 44, 19, 44, 19, 33, 6, 30, 33,\n",
+ " 31, 33, 19, 44, 3, 44, 36, 31, 44, 19, 33, 44, 30, 33, 27, 33, 44, 21,\n",
+ " 27, 44, 44, 33, 30, 31, 30, 33, 30, 29, 43, 29, 31, 29, 28, 16, 44, 29,\n",
+ " 33, 29, 44, 30, 33, 29, 40, 29, 19, 44, 43, 43, 16, 30, 19, 44, 36, 44,\n",
+ " 33, 33, 33, 33, 31, 14, 43, 36, 21, 36, 44, 31, 44, 36, 43, 5, 44, 24,\n",
+ " 33, 29, 30, 42, 44, 44, 44, 19, 33, 44, 19, 40, 29, 44, 27, 3, 44, 19,\n",
+ " 30, 19, 33, 19, 44, 33, 5, 33, 28, 36, 29, 44, 27, 29, 36, 30, 30, 30,\n",
+ " 30, 19, 29, 44, 27, 30, 30, 27, 31, 33, 19, 43, 44, 40, 26, 44, 44, 33,\n",
+ " 33, 29, 44, 44, 44, 30, 31, 44, 30, 36, 44, 44, 44, 31, 36, 30, 36, 29,\n",
+ " 31, 19, 24, 33, 28, 44, 41, 44, 30, 36, 22, 7, 33, 31, 43, 31, 27, 31,\n",
+ " 44, 33, 10, 33, 30, 44, 43, 30, 44, 44, 44, 15, 44, 44])"
+ ]
+ },
+ "metadata": {},
+ "execution_count": 11
+ }
+ ],
+ "source": [
+ "# comp.prediction에 TEST 예측 결과 대입\n",
+ "comp.prediction = all_predictions\n",
+ "comp.prediction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ddd1d918",
+ "metadata": {
+ "id": "ddd1d918",
+ "outputId": "514ec5e9-9a62-41f3-cc30-aedfe21cd8d3",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ }
+ },
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "[Document Classification 평가 결과]\n",
+ " AI Essential 0203(1) 과정 님의 점수는 0.0660377358490566 입니다."
+ ]
+ }
+ ],
+ "source": [
+ "# 제출\n",
+ "comp.submit()"
+ ]
+ }
+ ],
+ "metadata": {
+ "colab": {
+ "provenance": [],
+ "include_colab_link": true
+ },
+ "kernelspec": {
+ "display_name": "ai-essential",
+ "language": "python",
+ "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.12.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
\ No newline at end of file