{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 03wk-1: 감성분석 파고들기 (1)\n", "\n", "최규빈 \n", "2024-09-19\n", "\n", "\n", "\n", "# 1. 강의영상\n", "\n", "\n", "\n", "# 2. Imports" ], "id": "cd0dbfcc-193f-417a-86c4-429c22c57fe7" }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/home/cgb3/anaconda3/envs/hf/lib/python3.12/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" ] } ], "source": [ "import datasets\n", "import transformers\n", "import evaluate\n", "import numpy as np\n", "import torch # 파이토치" ], "id": "cell-5" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 3. 이전코드\n", "\n", "`-` Step1~4를 위한 준비" ], "id": "8b11556e-899a-43f0-92d9-748ae6ec828d" }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# ## Step1 \n", "# 데이터불러오기 = datasets.load_dataset\n", "# 데이터전처리하기1 = 토크나이저 = transformers.AutoTokenizer.from_pretrained(\"distilbert/distilbert-base-uncased\") \n", "# def 데이터전처리하기2(examples):\n", "# return 데이터전처리하기1(examples[\"text\"], truncation=True)\n", "# ## Step2 \n", "# 인공지능생성하기 = transformers.AutoModelForSequenceClassification.from_pretrained\n", "# ## Step3 \n", "# 데이터콜렉터 = transformers.DataCollatorWithPadding(tokenizer=토크나이저)\n", "# def 평가하기(eval_pred):\n", "# predictions, labels = eval_pred\n", "# predictions = np.argmax(predictions, axis=1)\n", "# accuracy = evaluate.load(\"accuracy\")\n", "# return accuracy.compute(predictions=predictions, references=labels)\n", "# 트레이너세부지침생성기 = transformers.TrainingArguments\n", "# 트레이너생성기 = transformers.Trainer\n", "# ## Step4 \n", "# 강인공지능생성하기 = transformers.pipeline" ], "id": "cell-8" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` Step 1~4" ], "id": "e28f3e04-9870-492f-bdca-5da8ced2fc28" }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# ## Step1 \n", "# 데이터 = 데이터불러오기('imdb')\n", "# 전처리된데이터 = 데이터.map(데이터전처리하기2,batched=True)\n", "# 전처리된훈련자료, 전처리된검증자료 = 전처리된데이터['train'], 전처리된데이터['test']\n", "# ## Step2 \n", "# 인공지능 = 인공지능생성하기(\"distilbert/distilbert-base-uncased\", num_labels=2)\n", "# ## Step3 \n", "# 트레이너세부지침 = 트레이너세부지침생성기(\n", "# output_dir=\"my_awesome_model\",\n", "# learning_rate=2e-5,\n", "# per_device_train_batch_size=16,\n", "# per_device_eval_batch_size=16,\n", "# num_train_epochs=2, # 전체문제세트를 2번 공부하라..\n", "# weight_decay=0.01,\n", "# eval_strategy=\"epoch\",\n", "# save_strategy=\"epoch\",\n", "# load_best_model_at_end=True,\n", "# push_to_hub=False,\n", "# )\n", "# 트레이너 = 트레이너생성기(\n", "# model=인공지능,\n", "# args=트레이너세부지침,\n", "# train_dataset=전처리된훈련자료,\n", "# eval_dataset=전처리된검증자료,\n", "# tokenizer=토크나이저,\n", "# data_collator=데이터콜렉터,\n", "# compute_metrics=평가하기,\n", "# )\n", "# 트레이너.train()\n", "# ## Step4 \n", "# 강인공지능 = 강인공지능생성하기(\"sentiment-analysis\", model=\"my_awesome_model/checkpoint-1563\")\n", "# print(강인공지능(\"This movie was a huge disappointment.\"))\n", "# print(강인공지능(\"This was a masterpiece.\"))" ], "id": "cell-10" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 4. DataSet\n", "\n", "`-` 가장 중요한 원초적 질문: 데이터 셋을 바꿔치기 하려면?\n", "\n", "`-` 내가 원하는 데이터를 아래와 같은 양식(=형태)으로 정리해야함." ], "id": "95b5c764-b0ff-44de-832e-6918bb8f1da3" }, { "cell_type": "code", "execution_count": 161, "metadata": {}, "outputs": [], "source": [ "데이터 = datasets.load_dataset('imdb')\n", "데이터" ], "id": "cell-14" }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "데이터, type(데이터)" ], "id": "cell-15" }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "데이터['train'], type(데이터['train'])" ], "id": "cell-16" }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "데이터['train'][0]" ], "id": "cell-17" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` `datasets.arrow_dataset.Dataset` 의 인스턴스 만들기\n", "\n", "아래와 같은 함수가 있음." ], "id": "d20d50e0-dd6a-449e-9d8e-267f9ce3a0bb" }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "#datasets.Dataset.from_dict?\n", "#클래스메소드" ], "id": "cell-20" }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **$\\star$ `datasets.Dataset.from_dict` 사용법 (ref: ChatGPT)**\n", ">\n", "> `datasets.Dataset.from_dict`는 Python의 딕셔너리(`dict`)를 `Dataset`\n", "> 객체로 변환하는 함수입니다. 주로 딕셔너리 형태의 데이터를 빠르게\n", "> 데이터셋으로 변환할 때 사용됩니다.\n", ">\n", "> **간단한 사용법**\n", ">\n", "> ``` python\n", "> from datasets import Dataset\n", ">\n", "> # 딕셔너리를 Dataset으로 변환\n", "> data_dict = {\n", "> 'text': [\"Hello world\", \"How are you?\", \"Fine, thanks!\"],\n", "> 'label': [0, 1, 1]\n", "> }\n", ">\n", "> # Dataset 생성\n", "> dataset = Dataset.from_dict(data_dict)\n", ">\n", "> # 출력\n", "> print(dataset)\n", "> ```\n", ">\n", "> **주요 매개변수:**\n", ">\n", "> - `mapping`: 필수, 문자열을 키로 하고 리스트 또는 배열을 값으로 하는\n", "> 딕셔너리.\n", "> - `features`: 선택, 데이터셋의 각 필드 타입을 정의.\n", "> - `info`: 선택, 데이터셋에 대한 추가 정보(설명, 인용 등).\n", "> - `split`: 선택, 데이터셋의 나누기(‘train’, ‘test’ 등).\n", ">\n", "> **반환값:**\n", ">\n", "> - `Dataset`: PyArrow 기반의 데이터셋 객체." ], "id": "c1f7642a-17a9-49eb-bce4-ef87f16009cd" }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "train_dict = {\n", " 'text': [\n", " \"I prefer making decisions based on logic and objective facts.\",\n", " \"I always consider how others might feel when making a decision.\",\n", " \"Data and analysis drive most of my decisions.\",\n", " \"I rely on my empathy and personal values to guide my choices.\"\n", " ],\n", " 'label': [0, 1, 0, 1] # 0은 T(사고형), 1은 F(감정형)\n", "}\n", "\n", "test_dict = {\n", " 'text': [\n", " \"I find it important to weigh all the pros and cons logically.\",\n", " \"When making decisions, I prioritize harmony and people's emotions.\"\n", " ],\n", " 'label': [0, 1] # 0은 T(사고형), 1은 F(감정형)\n", "}" ], "id": "cell-22" }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "train_data = datasets.Dataset.from_dict(train_dict)\n", "test_data = datasets.Dataset.from_dict(test_dict)" ], "id": "cell-23" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` `datasets.dataset_dict.DatasetDict`의 인스턴스 만들기" ], "id": "2b6a0300-714b-4f18-b16e-bcace20b3012" }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "나의데이터 = datasets.dataset_dict.DatasetDict({'train':train_data, 'test':test_data})" ], "id": "cell-25" }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "나의데이터['train'][0]" ], "id": "cell-26" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 일단 아래와 같은 형태로 분석할 데이터를 저장할 수 있다면, 나머지\n", "분석은 코드를 복/붙하여 진행할 수 있음.\n", "\n", "``` python\n", "train_dict = {\n", " 'text': [\n", " \"I prefer making decisions based on logic and objective facts.\",\n", " \"I always consider how others might feel when making a decision.\",\n", " \"Data and analysis drive most of my decisions.\",\n", " \"I rely on my empathy and personal values to guide my choices.\"\n", " ],\n", " 'label': [0, 1, 0, 1] # 0은 T(사고형), 1은 F(감정형)\n", "}\n", "\n", "test_dict = {\n", " 'text': [\n", " \"I find it important to weigh all the pros and cons logically.\",\n", " \"When making decisions, I prioritize harmony and people's emotions.\"\n", " ],\n", " 'label': [0, 1] # 0은 T(사고형), 1은 F(감정형)\n", "}\n", "```\n", "\n", "# 5. 토크나이저\n", "\n", "`-` 토크나이저를 불러오는 코드" ], "id": "ae071403-a016-43d7-ad75-f4d8196eb8ea" }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/home/cgb3/anaconda3/envs/hf/lib/python3.12/site-packages/transformers/tokenization_utils_base.py:1601: FutureWarning: `clean_up_tokenization_spaces` was not set. It will be set to `True` by default. This behavior will be depracted in transformers v4.45, and will be then set to `False` by default. For more details check this issue: https://github.com/huggingface/transformers/issues/31884\n", " warnings.warn(" ] } ], "source": [ "토크나이저 = 데이터전처리하기1 = transformers.AutoTokenizer.from_pretrained(\"distilbert/distilbert-base-uncased\")" ], "id": "cell-30" }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "#토크나이저?" ], "id": "cell-31" }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **$\\star$ `토크나이저` 사용법 (ref: ChatGPT)**\n", ">\n", "> **주요 파라미터**:\n", ">\n", "> 1. **text**:\n", "> - `Union[str, List[str], List[List[str]]]`\n", "> - 주어진 텍스트를 토큰화합니다. 이 텍스트는 문자열일 수도 있고,\n", "> 문자열의 리스트 또는 리스트 안의 리스트일 수도 있습니다.\n", "> 2. **text_pair**:\n", "> - `Union[str, List[str], List[List[str]], NoneType]`\n", "> - 두 개의 텍스트를 함께 모델에 입력할 때 사용됩니다. 예를 들어,\n", "> 질문-답변 쌍 같은 경우 이 두 번째 텍스트를 넣습니다.\n", "> 3. **text_target**:\n", "> - `Union[str, List[str], List[List[str]]]`\n", "> - 토큰화를 할 때 목표(target) 텍스트에 해당하는 부분입니다. 주로\n", "> 시퀀스 생성 모델에서 활용됩니다.\n", "> 4. **text_pair_target**:\n", "> - `Union[str, List[str], List[List[str]], NoneType]`\n", "> - 위의 `text_pair`와 유사하게 목표(target) 텍스트의 두 번째\n", "> 텍스트를 나타냅니다.\n", "> 5. **add_special_tokens**:\n", "> - `bool`\n", "> - 문장의 시작, 끝, 구분자 같은 특별한 토큰을 추가할지 여부를\n", "> 결정합니다. 기본값은 `True`입니다.\n", "> 6. **padding**:\n", "> - `Union[bool, str, transformers.utils.generic.PaddingStrategy]`\n", "> - 문장 길이가 다를 때 패딩을 넣어 문장의 길이를 동일하게\n", "> 맞춥니다. 패딩 전략에는 `True`, `False`, `'longest'`,\n", "> `'max_length'` 등이 있습니다.\n", "> 7. **truncation**:\n", "> - `Union[bool, str, transformers.tokenization_utils_base.TruncationStrategy]`\n", "> - 문장이 너무 길 경우 지정된 최대 길이에 맞춰 잘라내는\n", "> 옵션입니다. 전략에는 `True`, `False`, `'longest_first'`,\n", "> `'only_first'`, `'only_second'` 등이 있습니다.\n", "> 8. **max_length**:\n", "> - `Optional[int]`\n", "> - 문장의 최대 길이를 설정합니다. `None`일 경우 기본 설정을\n", "> 따릅니다.\n", "> 9. **stride**:\n", "> - `int`\n", "> - 텍스트를 자를 때 중첩을 만들기 위한 옵션입니다. 즉, 자른\n", "> 부분과 다음 부분 사이의 겹치는 범위를 설정합니다.\n", "> 10. **is_split_into_words**:\n", "> - `bool`\n", "> - 텍스트가 이미 단어 단위로 분리되어 있는지 여부를 나타냅니다.\n", "> 기본적으로는 `False`로, 텍스트가 단어 단위로 분리되지 않았다고\n", "> 가정합니다.\n", "> 11. **return_tensors**:\n", "> - `Union[str, transformers.utils.generic.TensorType, NoneType]`\n", "> - 출력 형식으로 텐서를 반환할지 여부를 설정합니다.\n", "> `'pt'`(PyTorch), `'tf'`(TensorFlow), `'np'`(NumPy) 등을 지정할\n", "> 수 있습니다.\n", "> 12. **return_token_type_ids**:\n", "> - `Optional[bool]`\n", "> - 토큰 타입 ID를 반환할지 여부를 설정합니다. 주로 두 개의 문장을\n", "> 함께 처리할 때 문장을 구분하기 위해 사용됩니다.\n", "> 13. **return_attention_mask**:\n", "> - `Optional[bool]`\n", "> - `attention_mask`를 반환할지 여부를 설정합니다. 패딩된 토큰이\n", "> 모델의 어텐션에 영향을 주지 않도록 마스크를 설정합니다.\n", "> 14. **return_overflowing_tokens**:\n", "> - `bool`\n", "> - 텍스트가 최대 길이를 초과하는 경우, 잘린 토큰을 반환할지\n", "> 여부를 결정합니다.\n", "> 15. **return_special_tokens_mask**:\n", "> - `bool`\n", "> - 특별한 토큰에 대한 마스크를 반환할지 여부를 설정합니다.\n", "> 16. **return_offsets_mapping**:\n", "> - `bool`\n", "> - 텍스트의 각 토큰이 원본 텍스트에서 어느 위치에 있는지 나타내는\n", "> 오프셋 맵핑을 반환할지 여부를 설정합니다.\n", "> 17. **return_length**:\n", "> - `bool`\n", "> - 토큰화된 문장의 길이를 반환할지 여부를 설정합니다.\n", "> 18. **verbose**:\n", "> - `bool`\n", "> - 디버깅 메시지를 출력할지 여부를 설정합니다. 기본값은 `True`로\n", "> 설정되어 있습니다.\n", ">\n", "> **사용 예시**:\n", ">\n", "> ``` python\n", "> from transformers import AutoTokenizer\n", ">\n", "> # 토크나이저 불러오기\n", "> tokenizer = AutoTokenizer.from_pretrained(\"bert-base-uncased\")\n", ">\n", "> # 텍스트 토큰화\n", "> encoding = tokenizer(\n", "> text=\"Hello, how are you?\",\n", "> padding=True,\n", "> truncation=True,\n", "> max_length=10,\n", "> return_tensors='pt'\n", "> )\n", ">\n", "> print(encoding)\n", "> ```\n", ">\n", "> 이 코드에서는 “Hello, how are you?”라는 텍스트를 `bert-base-uncased`\n", "> 토크나이저로 토큰화하고, 패딩과 트렁케이션을 적용하며, PyTorch 텐서\n", "> 형식으로 반환하도록 설정했습니다.\n", ">\n", "> 이러한 파라미터는 주로 자연어 처리(NLP) 모델을 훈련하거나 추론할 때\n", "> 데이터 전처리 과정에서 많이 사용됩니다.\n", "\n", "`-` 기본사용1: 토크나이저의 기능 – (1) 단어별로 다른숫자를 맵핑 (2)\n", "처음과 끝은 각각 `101`, `102`라는 숫자로 맵핑" ], "id": "6797c75a-c334-4c1c-a36e-6ade40c3fa93" }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "토크나이저('hi hello')" ], "id": "cell-34" }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "토크나이저('hi hi hello')" ], "id": "cell-35" }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "토크나이저('hi hi hello hello hello hi')" ], "id": "cell-36" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 기본사용2: 여러개의 텍스트도 `[텍스트1, 텍스트2, ... ]` 꼴로\n", "전달하면 토크나이저가 알아서 잘 처리해준다." ], "id": "6be702a3-469b-4993-9a06-c2d394cd07de" }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "토크나이저(['hi hello', 'hello hello hello', 'hi hi'])" ], "id": "cell-38" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` `truncation=True` 의 역할 – 너무 문장이 길면 잘라내는 역할을 한다." ], "id": "ca95d4e9-90b8-4653-b82c-677924429506" }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [], "source": [ "토크나이저('hi hello '*2)" ], "id": "cell-40" }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [], "source": [ "len(토크나이저('hi hello '*2)['input_ids']), len(토크나이저('hi hello '*2)['attention_mask'])" ], "id": "cell-41" }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [], "source": [ "len(토크나이저('hi hello '*300,truncation=True)['input_ids']) # 원래는 602가 나와야하는데 짤려서 512만 나옴" ], "id": "cell-42" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 너무 문장이 짧아서 뭔가를 채우기도 할까? – `max_length`, `padding`,\n", "`attention_mask`" ], "id": "48fb374e-6f06-4ccc-ac2b-880fc755f1bd" }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [], "source": [ "토크나이저('hi hello', max_length = 10, padding=\"max_length\" )" ], "id": "cell-44" }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 6. 인공지능 ($\\star$)\n", "\n", "## A. 1단계\n", "\n", "> 인공지능에 대한 이해\n", "\n", "`-` 인공지능 불러오기" ], "id": "c59bd936-7614-43f0-bb05-9a3bd36aeb39" }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "Some weights of DistilBertForSequenceClassification were not initialized from the model checkpoint at distilbert/distilbert-base-uncased and are newly initialized: ['classifier.bias', 'classifier.weight', 'pre_classifier.bias', 'pre_classifier.weight']\n", "You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference." ] } ], "source": [ "torch.manual_seed(43052)\n", "인공지능 = model = transformers.AutoModelForSequenceClassification.from_pretrained(\n", " \"distilbert/distilbert-base-uncased\", num_labels=2\n", ")" ], "id": "cell-49" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 인공지능의 정체? 엄청나게 많은 숫자들이 포함된 어떠한 물체 (엄청나게\n", "많은 파라메터들이 포함된 네트워크)" ], "id": "21395eef-babd-46fe-b45c-34dfc9bc9835" }, { "cell_type": "code", "execution_count": 134, "metadata": {}, "outputs": [], "source": [ "인공지능" ], "id": "cell-51" }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [], "source": [ "인공지능.classifier.weight" ], "id": "cell-52" }, { "cell_type": "code", "execution_count": 136, "metadata": {}, "outputs": [], "source": [ "인공지능.pre_classifier.weight" ], "id": "cell-53" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 인공지능? “입력정보 -\\> 정리된숫자 -\\> 계산 -\\> 계산된숫자 -\\>\n", "출력정보” 의 과정에서 “계산”을 담당.\n", "\n", "- 인공지능이 가지고 있는 숫자들은 “계산”에 사용된다.\n", "\n", "`-` 입력정보에 영화에 대한 부정적 평가에 해당하는 텍스트를 넣는다면?" ], "id": "5a5e71f5-6451-438f-a4fd-fa32bb662f95" }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [], "source": [ "입력정보_원시텍스트 = \"This movie was a huge disappointment.\"\n", "정리된숫자_토큰화된자료 = 토크나이저(입력정보_원시텍스트,return_tensors='pt')\n", "정리된숫자_토큰화된자료" ], "id": "cell-56" }, { "cell_type": "code", "execution_count": 138, "metadata": {}, "outputs": [], "source": [ "인공지능(**정리된숫자_토큰화된자료)" ], "id": "cell-57" }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [], "source": [ "계산된숫자_로짓 = 인공지능(**정리된숫자_토큰화된자료).logits.detach().numpy()\n", "계산된숫자_로짓" ], "id": "cell-58" }, { "cell_type": "code", "execution_count": 140, "metadata": {}, "outputs": [], "source": [ "출력정보_확률 = np.exp(계산된숫자_로짓)/np.exp(계산된숫자_로짓).sum() # 0일확률(=부정평가일확률), 1일확률(=긍정평가일확률)\n", "출력정보_확률" ], "id": "cell-59" }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [], "source": [ "출력정보_확률.argmax() # 부정적 영화평가에 대한 인공지능의 예측 " ], "id": "cell-60" }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [], "source": [ "계산된숫자_로짓.argmax() # 부정적 영화평가에 대한 인공지능의 예측 <-- 이렇게 구해도 됩니다.. 왜??" ], "id": "cell-61" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 입력정보에 영화에 대한 긍정적 평가에 해당하는 텍스트를 넣는다면?" ], "id": "a2e9f4ff-110f-46fa-aa5e-3b713a9f9be6" }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [], "source": [ "입력정보_원시텍스트 = \"This was a masterpiece.\"\n", "정리된숫자_토큰화된자료 = 토크나이저(입력정보_원시텍스트,return_tensors='pt')\n", "정리된숫자_토큰화된자료" ], "id": "cell-63" }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [], "source": [ "인공지능(**정리된숫자_토큰화된자료)" ], "id": "cell-64" }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [], "source": [ "계산된숫자_로짓 = 인공지능(**정리된숫자_토큰화된자료).logits.detach().numpy()\n", "계산된숫자_로짓" ], "id": "cell-65" }, { "cell_type": "code", "execution_count": 151, "metadata": {}, "outputs": [], "source": [ "출력정보_확률 = np.exp(계산된숫자_로짓)/np.exp(계산된숫자_로짓).sum() # 0일확률(=부정평가일확률), 1일확률(=긍정평가일확률)\n", "출력정보_확률" ], "id": "cell-66" }, { "cell_type": "code", "execution_count": 152, "metadata": {}, "outputs": [], "source": [ "출력정보_확률.argmax() # 긍정적 영화평가에 대한 인공지능의 예측 " ], "id": "cell-67" }, { "cell_type": "code", "execution_count": 154, "metadata": {}, "outputs": [], "source": [ "계산된숫자_로짓.argmax() # 긍정적 영화평가에 대한 인공지능의 예측" ], "id": "cell-68" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 아무숫자나 뱉어내는 듯 $\\to$ 멍청한 인공지능 (옹호: 멍청한건 당연함.\n", "아직 학습전이니까)\n", "\n", "`-` 인공지능에 대한 이해1: 인공지능은 “정리된숫자”를 입력으로 하고\n", "일련의 계산을 거쳐서 “계산된숫자”를 출력해주는 함수라 생각할 수 있음.\n", "\n", "`-` 인공지능에 대한 이해2: 인공지능은 (1) 많은숫자들과 (2) 고유의\n", "계산방식을 가지고 있음.\n", "\n", "- 인공지능이 내부에 자체적으로 저장하고 있는 숫자들 “파라메터”라고\n", " 부름.\n", "- 인공지능은 나름의 법칙에 따라 “데이터”와 “파라메터”의 숫자들을\n", " 연산함. 즉 인공지능은 자체적으로 데이터와 파라메터를 어떻게 계산할지\n", " 알고있는데, 이러한 고유의 계산방식을 “아키텍처”라고 말함.\n", "\n", "`-` 인공지능에 대한 이해3: 두개의 인공지능이 서로 다른 고유의 계산방식을\n", "가지고 있다면 두 인공지능은 “다른 모델” 임.\n", "\n", "`-` 인공지능에 대한 이해3’: 동일한 생성방식으로 만들어진 인공지능들은\n", "모두 같은 모델임. 예를들면 아래의 인공지능1,2는 같은 모델임\n", "\n", "``` python\n", "인공지능1 = transformers.AutoModelForSequenceClassification.from_pretrained(\n", " \"distilbert/distilbert-base-uncased\", num_labels=2\n", ")\n", "인공지능2 = transformers.AutoModelForSequenceClassification.from_pretrained(\n", " \"distilbert/distilbert-base-uncased\", num_labels=2\n", ")\n", "```\n", "\n", "`-` 인공지능에 대한 이해4: 두 인공지능이 같은모델이라고 해도, 항상 같은\n", "결과를 주는건 아님. 파라메터에 따라 다른 결과를 줄 수도 있음. (예를들면\n", "위의 인공지능1,2는 같은 모델이지만 다른 파라메터를 가지므로 다른 결과를\n", "줌)\n", "\n", "## B. 2단계\n", "\n", "> 미니배치의 이해\n", "\n", "`-` 예비학습" ], "id": "9b150d02-51b2-4db9-9e7d-01d46e7004e8" }, { "cell_type": "code", "execution_count": 156, "metadata": {}, "outputs": [], "source": [ "arr = np.array([[1,2],[2,3],[3,4]])\n", "arr" ], "id": "cell-78" }, { "cell_type": "code", "execution_count": 159, "metadata": {}, "outputs": [], "source": [ "arr / arr.sum(axis=1).reshape(-1,1)" ], "id": "cell-79" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 예비개념1: 인공지능은 사실 영화평을 하나씩 하나씩 처리하지 않는다.\n", "덩어리로 처리한다.\n", "\n", "`-` 예비개념2: 그렇다고 해서 인공지능이 25000개를 모두 덩어리로\n", "처리하는건 아니다 $\\to$ 16개씩 혹은 32개씩 묶어서 작은덩어리를 만든 후\n", "처리한다.\n", "\n", "- 16, 32와 같은 숫자를 `batch_size` 라고 한다.\n", "- 16개, 32개로 모인 작은덩어리를 미니배치라고 한다.\n", "\n", "`-` 16개의 입력정보를 한번에 처리" ], "id": "2fc748b6-070c-4452-8ffb-287a47bb8552" }, { "cell_type": "code", "execution_count": 175, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][:16]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓) / np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "출력정보들_확률" ], "id": "cell-83" }, { "cell_type": "code", "execution_count": 177, "metadata": {}, "outputs": [], "source": [ "계산된숫자들_로짓.argmax(axis=1) # 인공지능의 예측" ], "id": "cell-84" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 기억할 것: `정리된숫자들_토큰화된자료` 는 모두 길이가 512임. (그렇게\n", "되도록 패딩함)" ], "id": "345c105b-8e25-4e6f-ad35-ff6b87346cce" }, { "cell_type": "code", "execution_count": 182, "metadata": {}, "outputs": [], "source": [ "정리된숫자들_토큰화된자료['input_ids'].shape, 정리된숫자들_토큰화된자료['attention_mask'].shape" ], "id": "cell-86" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 실제 단어수" ], "id": "d1a17b82-d649-478f-91ee-7e5b00aa9710" }, { "cell_type": "code", "execution_count": 190, "metadata": {}, "outputs": [], "source": [ "정리된숫자들_토큰화된자료['attention_mask'].sum(axis=1)" ], "id": "cell-88" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 패딩된단어수" ], "id": "94f06a61-d8e6-4343-813a-c64391b24407" }, { "cell_type": "code", "execution_count": 191, "metadata": {}, "outputs": [], "source": [ "512-정리된숫자들_토큰화된자료['attention_mask'].sum(axis=1)" ], "id": "cell-90" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 이러한 변환이 필요한 이유? 인공지능은 항상 `(n,m)` 차원으로 정리된\n", "숫자들만 입력으로 받을 수 있음.\n", "\n", "- 왜? 사실 인공지능은 행렬계산을 하도록 설계되어있음.\n", "- 그래서 할수없이 padding을 하거나 truncation을 하는 것임. (실제로는\n", " 행렬이 아니지만 억지로 행렬을 만들기 위해서)\n", "\n", "## C. 3단계\n", "\n", "> 동적패딩을 이해하자.\n", "\n", "`-` 만약에 `batch_size=4`로 설정하여 처리한다면?" ], "id": "fde55c3a-9154-4263-a236-7cfb55a45815" }, { "cell_type": "code", "execution_count": 202, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][:4]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓) / np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "출력정보들_확률" ], "id": "cell-95" }, { "cell_type": "code", "execution_count": 203, "metadata": {}, "outputs": [], "source": [ "계산된숫자들_로짓.argmax(axis=1) # 인공지능의 예측 " ], "id": "cell-96" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` `정리된숫자들_토큰화된자료['input_ids']` 의 차원은 어떠할까? (4,512)" ], "id": "fb12a1e1-b32b-4dac-8e75-3769c5a8f969" }, { "cell_type": "code", "execution_count": 204, "metadata": {}, "outputs": [], "source": [ "정리된숫자들_토큰화된자료['input_ids'].shape, 정리된숫자들_토큰화된자료['attention_mask'].shape" ], "id": "cell-98" }, { "cell_type": "markdown", "metadata": {}, "source": [ "- 끝의 차원이 512가 아니라 363이다.. 왜??\n", "\n", "`-` 덩어리의 상태에 따라서 유동적으로 패딩 $\\to$ 이렇게 해도 잘 돌아감" ], "id": "2454a5fa-cfdc-436d-bfaa-30e14d4a5063" }, { "cell_type": "code", "execution_count": 209, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][:4]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "인공지능(**정리된숫자들_토큰화된자료)" ], "id": "cell-101" }, { "cell_type": "code", "execution_count": 210, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][4:8]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "인공지능(**정리된숫자들_토큰화된자료)" ], "id": "cell-102" }, { "cell_type": "code", "execution_count": 211, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][8:12]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "인공지능(**정리된숫자들_토큰화된자료)" ], "id": "cell-103" }, { "cell_type": "code", "execution_count": 212, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][12:16]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "인공지능(**정리된숫자들_토큰화된자료)" ], "id": "cell-104" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 싹다 maxlen=512로 가정하고 패딩해서 돌린결과와 비교 $\\to$ 같음 $\\to$\n", "동적패딩이 효율적" ], "id": "1bf5633d-9adc-4c75-9ff9-5da03e0cb352" }, { "cell_type": "code", "execution_count": 213, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][:16]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "인공지능(**정리된숫자들_토큰화된자료)" ], "id": "cell-106" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## D. 4단계\n", "\n", "> 손실(=loss)의 개념을 이해하자\n", "\n", "`-` `정리된숫자들_토큰화된자료`에서 `labels`를 추가 전달하면,\n", "`인공지능(**정리된숫자들_토큰화된자료)`의 결과로 `loss`가 추가계산됨." ], "id": "859f7d81-7a95-4f6e-8fdd-61ee96c2f294" }, { "cell_type": "code", "execution_count": 222, "metadata": {}, "outputs": [], "source": [ "입력정보들_원시텍스트 = 데이터['train'][:4]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "#데이터['train'][:4]['label'] # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor([0,0,0,0]) # 정답입력\n", "인공지능(**정리된숫자들_토큰화된자료)" ], "id": "cell-110" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 정리를 해보자." ], "id": "53915e20-326e-4406-92ed-b8db63bde9e5" }, { "cell_type": "code", "execution_count": 240, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "실제정답: [0, 0, 0, 0]\n", "인공지능의예측: [1 1 1 1]\n", "인공지능의확신정도: [0.5217618 0.5278467 0.5195052 0.5339033]\n", "손실(loss): 0.746100" ] } ], "source": [ "입력정보들_원시텍스트 = 데이터['train'][:4]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "print(f'실제정답: {데이터['train'][:4]['label']}') # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor([0,0,0,0]) # 정답입력\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓)/np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "print(f'인공지능의예측: {계산된숫자들_로짓.argmax(axis=1)}')\n", "print(f'인공지능의확신정도: {출력정보들_확률.max(axis=1)}')\n", "print(f'손실(loss): {인공지능(**정리된숫자들_토큰화된자료).loss.item():.6f}')" ], "id": "cell-112" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` loss는 작을수록 주어진 데이터에 대한 정답을 잘 맞추고 있다고 볼 수\n", "있음. (그렇지만 학습이 잘 되었다는걸 보장하지는 못함)\n", "\n", "**텍스트0-텍스트3**" ], "id": "a1c739c3-f599-45bd-8eaa-0f3aa6b2658b" }, { "cell_type": "code", "execution_count": 244, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "텍스트0 -- 텍스트3\n", "실제정답: [0, 0, 0, 0]\n", "인공지능의예측: [1 1 1 1]\n", "인공지능의확신정도: [0.5217618 0.5278467 0.5195052 0.5339033]\n", "손실(loss): 0.746100" ] } ], "source": [ "print(\"텍스트0 -- 텍스트3\")\n", "입력정보들_원시텍스트 = 데이터['train'][:4]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "print(f'실제정답: {데이터['train'][:4]['label']}') # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor(데이터['train'][:4]['label']) # 정답입력\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓)/np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "print(f'인공지능의예측: {계산된숫자들_로짓.argmax(axis=1)}')\n", "print(f'인공지능의확신정도: {출력정보들_확률.max(axis=1)}')\n", "print(f'손실(loss): {인공지능(**정리된숫자들_토큰화된자료).loss.item():.6f}')" ], "id": "cell-115" }, { "cell_type": "markdown", "metadata": {}, "source": [ "**텍스트12498-텍스트12501**" ], "id": "ee306fc9-a8b3-48d6-8dab-17f890211e32" }, { "cell_type": "code", "execution_count": 247, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "텍스트12498 -- 텍스트12501\n", "실제정답: [0, 0, 1, 1]\n", "인공지능의예측: [1 1 1 1]\n", "인공지능의확신정도: [0.52731967 0.5243837 0.51578873 0.5351162 ]\n", "손실(loss): 0.694952" ] } ], "source": [ "print(\"텍스트12498 -- 텍스트12501\")\n", "입력정보들_원시텍스트 = 데이터['train'][12498:12502]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "print(f'실제정답: {데이터['train'][12498:12502]['label']}') # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor(데이터['train'][12498:12502]['label']) # 정답입력\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓)/np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "print(f'인공지능의예측: {계산된숫자들_로짓.argmax(axis=1)}')\n", "print(f'인공지능의확신정도: {출력정보들_확률.max(axis=1)}')\n", "print(f'손실(loss): {인공지능(**정리된숫자들_토큰화된자료).loss.item():.6f}')" ], "id": "cell-117" }, { "cell_type": "markdown", "metadata": {}, "source": [ "**텍스트12502-텍스트12506**" ], "id": "565c3c34-dc96-45d7-8720-2a64904b5d09" }, { "cell_type": "code", "execution_count": 248, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "텍스트12502 -- 텍스트12506\n", "실제정답: [1, 1, 1, 1]\n", "인공지능의예측: [1 1 1 1]\n", "인공지능의확신정도: [0.52180934 0.51908445 0.521884 0.5197189 ]\n", "손실(loss): 0.652730" ] } ], "source": [ "print(\"텍스트12502 -- 텍스트12506\")\n", "입력정보들_원시텍스트 = 데이터['train'][12502:12506]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "print(f'실제정답: {데이터['train'][12502:12506]['label']}') # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor(데이터['train'][12502:12506]['label']) # 정답입력\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓)/np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "print(f'인공지능의예측: {계산된숫자들_로짓.argmax(axis=1)}')\n", "print(f'인공지능의확신정도: {출력정보들_확률.max(axis=1)}')\n", "print(f'손실(loss): {인공지능(**정리된숫자들_토큰화된자료).loss.item():.6f}')" ], "id": "cell-119" }, { "cell_type": "markdown", "metadata": {}, "source": [ "`-` 똑같이 틀려도 오답에 대한 확신이 강할수록 loss가 크다." ], "id": "2014457c-778f-40a6-b069-d7324a9fcb99" }, { "cell_type": "code", "execution_count": 250, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "텍스트0 -- 텍스트1\n", "실제정답: [0, 0]\n", "인공지능의예측: [1 1]\n", "인공지능의확신정도: [0.5217617 0.5278467]\n", "손실(loss): 0.744049" ] } ], "source": [ "print(\"텍스트0 -- 텍스트1\")\n", "입력정보들_원시텍스트 = 데이터['train'][:2]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "print(f'실제정답: {데이터['train'][:2]['label']}') # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor(데이터['train'][:2]['label']) # 정답입력\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓)/np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "print(f'인공지능의예측: {계산된숫자들_로짓.argmax(axis=1)}')\n", "print(f'인공지능의확신정도: {출력정보들_확률.max(axis=1)}')\n", "print(f'손실(loss): {인공지능(**정리된숫자들_토큰화된자료).loss.item():.6f}')" ], "id": "cell-121" }, { "cell_type": "code", "execution_count": 251, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "텍스트1 -- 텍스트2\n", "실제정답: [0, 0]\n", "인공지능의예측: [1 1]\n", "인공지능의확신정도: [0.5278467 0.5195052]\n", "손실(loss): 0.741695" ] } ], "source": [ "print(\"텍스트1 -- 텍스트2\")\n", "입력정보들_원시텍스트 = 데이터['train'][1:3]['text']\n", "정리된숫자들_토큰화된자료 = 토크나이저(입력정보들_원시텍스트,truncation=True,return_tensors='pt',padding=True)\n", "print(f'실제정답: {데이터['train'][1:3]['label']}') # 정답확인\n", "정리된숫자들_토큰화된자료['labels'] = torch.tensor(데이터['train'][1:3]['label']) # 정답입력\n", "계산된숫자들_로짓 = 인공지능(**정리된숫자들_토큰화된자료).logits.detach().numpy()\n", "출력정보들_확률 = np.exp(계산된숫자들_로짓)/np.exp(계산된숫자들_로짓).sum(axis=1).reshape(-1,1)\n", "print(f'인공지능의예측: {계산된숫자들_로짓.argmax(axis=1)}')\n", "print(f'인공지능의확신정도: {출력정보들_확률.max(axis=1)}')\n", "print(f'손실(loss): {인공지능(**정리된숫자들_토큰화된자료).loss.item():.6f}')" ], "id": "cell-122" }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **$\\star\\star\\star$ 학습이 가능한 이유 (대충 아이디어만)**\n", ">\n", "> `1`. 랜덤으로 하나의 인공지능을 생성한다. (아래의 코드로 가능)\n", ">\n", "> ``` python\n", "> 인공지능 = 인공지능생성기()\n", "> ```\n", ">\n", "> `2`. 하나의 미니배치를 선택한다.\n", ">\n", "> `3`. 인공지능의 파라메터중 하나의 숫자를 선택한다. 예를들면 아래와\n", "> 같은 상황이 있다고 하자.\n", ">\n", "> ``` python\n", "> 인공지능.classifier.weight\n", "> ```\n", ">\n", "> Parameter containing:\n", "> tensor([[-0.0234, 0.0279, 0.0242, ..., 0.0091, -0.0063, -0.0133],\n", "> [ 0.0087, 0.0007, -0.0099, ..., 0.0183, -0.0007, 0.0295]],\n", "> requires_grad=True)\n", ">\n", "> 하나의 숫자 `-0.0234`를 선택한다.\n", ">\n", "> `4`. `-0.0234`의 값을 아주 조금 변화시킨다. 예를들면 `-0.0233`,\n", "> `-0.0235` 와 같은 숫자로 바꾼다. 2에서 고정된 미니배치에 대하여\n", "> `-0.0234`, `-0.0233`, `-0.0235` 에 대한 loss를 계산해보고 비교한다.\n", ">\n", "> - `-0.0234`이 최저 loss라면? 값을 안바꾸는게 좋겠음.\n", "> - `-0.0233`이 최저 loss라면?? 값을 `-0.0233`으로 바꿈.\n", "> - `-0.0235`이 최저 loss라면?? 값을 `-0.0235`으로 바꿈.\n", ">\n", "> `5`. 다음은 다른 모든 파라메터에 대하여 3-4을 반복한다. (과정을\n", "> 반복할수록 loss는 작아지겠죠, 즉 인공지능은 정답을 잘 맞추겠죠)\n", ">\n", "> `6`. 다른 미니배치에 대하여 2-5를 반복한다.\n", "\n", "`-` 인공지능의 학습은 마법같은 신비한 현상이 아니고, 극한의 노가다를\n", "통해 얻어지는 산물일 뿐이다." ], "id": "b0e2fc5f-61c3-447e-b013-5a41591e18d2" } ], "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "name": "python3", "display_name": "Python 3 (ipykernel)", "language": "python" }, "language_info": { "name": "python", "codemirror_mode": { "name": "ipython", "version": "3" }, "file_extension": ".py", "mimetype": "text/x-python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.4" } } }