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": [ + "\"Open" + ] + }, + { + "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