{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "rwxGnsA92emp" }, "source": [ "##### Copyright 2018 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-14T22:26:08.717080Z", "iopub.status.busy": "2022-12-14T22:26:08.716538Z", "iopub.status.idle": "2022-12-14T22:26:08.720890Z", "shell.execute_reply": "2022-12-14T22:26:08.720280Z" }, "id": "CPII1rGR2rF9" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "JtEZ1pCPn--z" }, "source": [ "# 사용자 정의 학습: 자세히 둘러보기" ] }, { "cell_type": "markdown", "metadata": { "id": "GV1F7tVTN3Dn" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
TensorFlow.org에서보기 Google Colab에서 실행하기 GitHub에서 소그 보기 노트북 다운로드하기
" ] }, { "cell_type": "markdown", "metadata": { "id": "LDrzLFXE8T1l" }, "source": [ "이 튜토리얼은 펭귄을 종별로 *분류*하기 위한 사용자 정의 훈련 루프를 사용하여 머신러닝 모델을 학습시키는 방법을 보여줍니다. 이 노트북에서는 TensorFlow를 사용하여 다음을 수행합니다.\n", "\n", "1. 데이터세트 가져오기\n", "2. 간단한 선형 모델 구축하기\n", "3. 모델 훈련하기\n", "4. 모델의 효과 평가하기\n", "5. 훈련된 모델을 사용하여 예측하기\n", "\n", "##  TensorFlow 프로그래밍\n", "\n", "이 튜토리얼은 다음 TensorFlow 프로그래밍 작업을 보여 줍니다.\n", "\n", "- [TensorFlow 데이터세트 API](https://www.tensorflow.org/datasets/overview#load_a_dataset)를 활용한 데이터 가져오기\n", "- [Keras API](https://www.tensorflow.org/guide/keras/)로 모델 및 레이어 구축하기\n" ] }, { "cell_type": "markdown", "metadata": { "id": "Zx7wc0LuuxaJ" }, "source": [ "## 펭귄 분류 문제\n", "\n", "조류학자가 펭귄을 자동으로 분류하는 방법을 찾고 있다고 가정해 봅시다. 머신러닝은 통계적으로 펭귄을 분류할 수 있는 다양한 알고리즘을 제공합니다. 예를 들어, 정교한 머신러닝 프로그램이라면 사진을 통해 펭귄을 분류할 수 있을 겁니다. 이 튜토리얼에서 빌드하는 모델은 조금 더 간단합니다. 튜토리얼에서는 체중, 펭귄날개 길이, 부리, 특히 [펭귄 부리](https://en.wikipedia.org/wiki/Beak#Culmen)의 길이와 너비 측정을 기준으로 펭귄을 분류합니다.\n", "\n", "18종의 펭귄이 있지만 이 튜토리얼에서는 다음 세 종의 펭귄만 분류하려고 합니다.\n", "\n", "- 턱끈 펭귄\n", "- 젠투 펭귄\n", "- 아델리 펭귄\n", "\n", "\n", " \n", " \n", "
\"Petal
그림 1. 턱끈 펭귄, 젠투 펭귄, 아델리 펭귄(@allison_horst 의 작품, CC BY-SA 2.0).
\n", "\n", "다행히 연구팀에서 이미 체중, 오리발 길이, 부리 치수 및 기타 데이터가 포함된 [334마리의 펭귄 데이터세트](https://allisonhorst.github.io/palmerpenguins/)를 만들고 공유했습니다. 이 데이터세트는 [펭귄](https://www.tensorflow.org/datasets/catalog/penguins) TensorFlow 데이터세트로도 편리하게 사용할 수 있습니다. " ] }, { "cell_type": "markdown", "metadata": { "id": "1J3AuPBT9gyR" }, "source": [ "## 설정하기\n", "\n", "펭귄 데이터세트용 `tfds-nightly` 패키지를 설치합니다. `tfds-nightly` 패키지는 TFDS(TensorFlow 데이터세트)의 Nightly 출시 버전입니다. TFDS에 대한 자세한 내용은 [TensorFlow 데이터세트 개요](https://www.tensorflow.org/datasets/overview)를 참조하세요." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:08.725015Z", "iopub.status.busy": "2022-12-14T22:26:08.724426Z", "iopub.status.idle": "2022-12-14T22:26:13.028216Z", "shell.execute_reply": "2022-12-14T22:26:13.026937Z" }, "id": "4XXWn1eDZmET" }, "outputs": [], "source": [ "!pip install -q tfds-nightly" ] }, { "cell_type": "markdown", "metadata": { "id": "DtGeMicKRGzU" }, "source": [ "그런 다음 Colab 메뉴에서 **런타임 > 런타임 다시 시작**을 선택하여 Colab 런타임을 다시 시작합니다.\n", "\n", "런타임을 우선적으로 다시 시작하지 않은 경우 이 튜토리얼의 나머지 부분을 진행하지 마세요." ] }, { "cell_type": "markdown", "metadata": { "id": "G9onjGZWZbA-" }, "source": [ "TensorFlow 및 기타 필수 Python 모듈을 가져옵니다. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:13.033874Z", "iopub.status.busy": "2022-12-14T22:26:13.033154Z", "iopub.status.idle": "2022-12-14T22:26:15.904888Z", "shell.execute_reply": "2022-12-14T22:26:15.904177Z" }, "id": "jElLULrDhQZR" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 22:26:14.069508: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 22:26:14.069611: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 22:26:14.069620: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "TensorFlow version: 2.11.0\n", "TensorFlow Datasets version: 4.7.0+nightly\n" ] } ], "source": [ "import os\n", "import tensorflow as tf\n", "import tensorflow_datasets as tfds\n", "import matplotlib.pyplot as plt\n", "\n", "print(\"TensorFlow version: {}\".format(tf.__version__))\n", "print(\"TensorFlow Datasets version: \",tfds.__version__)" ] }, { "cell_type": "markdown", "metadata": { "id": "3Px6KAg0Jowz" }, "source": [ "## 데이터세트 가져오기\n", "\n", "기본 [펭귄/처리됨](https://www.tensorflow.org/datasets/catalog/penguins) TensorFlow 데이터세트는 이미 정리되고 정규화되었으며 모델을 빌드할 준비가 완료되었습니다. 처리된 데이터를 다운로드하기 전에 단순화된 버전을 미리 보기하여 원래의 펭귄 조사 데이터에 익숙해지세요.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "qnX1-aLors4S" }, "source": [ "### 데이터 미리 보기\n", "\n", "TensorFlow 데이터세트 [`tdfs.load`](https://www.tensorflow.org/datasets/api_docs/python/tfds/load) 메서드를 사용하여 펭귄 데이터세트의 간소화된 버전(`penguins/simple`)을 다운로드합니다. 이 데이터세트에는 344개의 데이터 레코드가 있습니다. 처음 5개의 레코드를 [`DataFrame`](https://www.tensorflow.org/datasets/api_docs/python/tfds/as_dataframe) 객체로 추출하여 이 데이터세트에 있는 값의 샘플을 검사합니다." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:15.909115Z", "iopub.status.busy": "2022-12-14T22:26:15.908354Z", "iopub.status.idle": "2022-12-14T22:26:20.858069Z", "shell.execute_reply": "2022-12-14T22:26:20.857285Z" }, "id": "FQvb_JYdrpPm" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " body_mass_g culmen_depth_mm culmen_length_mm flipper_length_mm island \\\n", "0 4200.0 13.9 45.500000 210.0 0 \n", "1 4650.0 13.7 40.900002 214.0 0 \n", "2 5300.0 14.2 51.299999 218.0 0 \n", "3 5650.0 15.0 47.799999 215.0 0 \n", "4 5050.0 15.8 46.299999 215.0 0 \n", "\n", " sex species \n", "0 0 2 \n", "1 0 2 \n", "2 1 2 \n", "3 1 2 \n", "4 1 2 \n", "FeaturesDict({\n", " 'body_mass_g': float32,\n", " 'culmen_depth_mm': float32,\n", " 'culmen_length_mm': float32,\n", " 'flipper_length_mm': float32,\n", " 'island': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", " 'sex': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", " 'species': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", "})\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 22:26:20.787197: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n" ] } ], "source": [ "ds_preview, info = tfds.load('penguins/simple', split='train', with_info=True)\n", "df = tfds.as_dataframe(ds_preview.take(5), info)\n", "print(df)\n", "print(info.features)" ] }, { "cell_type": "markdown", "metadata": { "id": "kQhzD6P-uBoq" }, "source": [ "번호가 매겨진 줄은 데이터 레코드로, 한 줄당 한 개의 *[예](https://developers.google.com/machine-learning/glossary/#example)*가 있습니다.\n", "\n", "- 처음 여섯 개의 필드는 예제의 *[특성](https://developers.google.com/machine-learning/glossary/#feature)*을 표시하는 특성입니다. 여기에는 펭귄 측정치를 나타내는 숫자가 표시됩니다.\n", "- 마지막 열은 *[레이블](https://developers.google.com/machine-learning/glossary/#label)*이며 이는 예측하려는 값을 나타냅니다. 이 데이터세트에서 정수값 0, 1, 2는 펭귄 종 이름에 상응합니다." ] }, { "cell_type": "markdown", "metadata": { "id": "CCtwLoJhhDNc" }, "source": [ "데이터세트에서 펭귄 종의 레이블은 구축 중인 모델에서 더 쉽게 작업할 수 있도록 숫자로 표시됩니다. 이 숫자는 다음 펭귄 종에 상응합니다.\n", "\n", "- `0`: 아델리 펭귄\n", "- `1`: 턱끈 펭귄\n", "- `2`: 젠투 펭귄\n", "\n", "펭귄 종의 이름을 이 순서로 포함하는 목록을 만듭니다. 이 목록을 사용하여 분류 모델의 출력을 해석합니다." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:20.862718Z", "iopub.status.busy": "2022-12-14T22:26:20.862038Z", "iopub.status.idle": "2022-12-14T22:26:20.865766Z", "shell.execute_reply": "2022-12-14T22:26:20.865111Z" }, "id": "sVNlJlUOhkoX" }, "outputs": [], "source": [ "class_names = ['Adélie', 'Chinstrap', 'Gentoo']" ] }, { "cell_type": "markdown", "metadata": { "id": "iav9kEgxpY0s" }, "source": [ "특성과 레이블에 관한 더 자세한 내용은 [머신러닝 단기 집중 과정의 ML 용어 섹션](https://developers.google.com/machine-learning/crash-course/framing/ml-terminology)을 참조하세요." ] }, { "cell_type": "markdown", "metadata": { "id": "PD33PxSmCrtL" }, "source": [ "### 전처리된 데이터세트 다운로드하기\n", "\n", "이제 `tf.data.Dataset` 객체 목록을 반환하는 `tfds.load` 메서드를 사용하여 전처리된 펭귄 데이터세트(`penguins/processed`)를 다운로드합니다. `penguins/processed` 데이터세트의 경우 자체 테스트 세트가 함께 제공되지 않으므로 80:20의 분할 비율의 훈련 세트와 테스트 세트로 [전체 데이터세트를 분할](https://www.tensorflow.org/datasets/splits)합니다. 나중에 테스트 데이터세트를 사용하여 모델을 확인합니다." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:20.869510Z", "iopub.status.busy": "2022-12-14T22:26:20.868961Z", "iopub.status.idle": "2022-12-14T22:26:22.034991Z", "shell.execute_reply": "2022-12-14T22:26:22.034166Z" }, "id": "EVV96zIYYAi8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FeaturesDict({\n", " 'features': Tensor(shape=(4,), dtype=float32),\n", " 'species': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", "})\n", "Test dataset sample: \n", " features species\n", "0 [0.6545454, 0.22619048, 0.89830506, 0.6388889] 2\n", "1 [0.36, 0.04761905, 0.6440678, 0.4027778] 2\n", "2 [0.68, 0.30952382, 0.91525424, 0.6944444] 2\n", "3 [0.6181818, 0.20238096, 0.8135593, 0.6805556] 2\n", "4 [0.5527273, 0.26190478, 0.84745765, 0.7083333] 2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Train dataset sample: \n", " features species\n", "0 [0.49818182, 0.6904762, 0.42372882, 0.4027778] 0\n", "1 [0.48, 0.071428575, 0.6440678, 0.44444445] 2\n", "2 [0.7236364, 0.9047619, 0.6440678, 0.5833333] 1\n", "3 [0.34545454, 0.5833333, 0.33898306, 0.3472222] 0\n", "4 [0.10909091, 0.75, 0.3559322, 0.41666666] 0\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 22:26:21.858180: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n", "2022-12-14 22:26:22.013960: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n" ] } ], "source": [ "ds_split, info = tfds.load(\"penguins/processed\", split=['train[:20%]', 'train[20%:]'], as_supervised=True, with_info=True)\n", "\n", "ds_test = ds_split[0]\n", "ds_train = ds_split[1]\n", "assert isinstance(ds_test, tf.data.Dataset)\n", "\n", "print(info.features)\n", "df_test = tfds.as_dataframe(ds_test.take(5), info)\n", "print(\"Test dataset sample: \")\n", "print(df_test)\n", "\n", "df_train = tfds.as_dataframe(ds_train.take(5), info)\n", "print(\"Train dataset sample: \")\n", "print(df_train)\n", "\n", "ds_train_batch = ds_train.batch(32)" ] }, { "cell_type": "markdown", "metadata": { "id": "xX2NfLyQOK1y" }, "source": [ "이 버전의 데이터세트는 4개의 정규화된 특성과 종 레이블로 데이터를 축소하여 처리되었음을 알 수 있습니다. 이 형식에서 데이터는 추가 처리 없이 모델을 훈련하는 데 빠르게 사용할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.039396Z", "iopub.status.busy": "2022-12-14T22:26:22.038733Z", "iopub.status.idle": "2022-12-14T22:26:22.183711Z", "shell.execute_reply": "2022-12-14T22:26:22.182913Z" }, "id": "iDuG94H-C122" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[0.49818182 0.6904762 0.42372882 0.4027778 ]\n", " [0.48 0.07142857 0.6440678 0.44444445]\n", " [0.7236364 0.9047619 0.6440678 0.5833333 ]\n", " [0.34545454 0.5833333 0.33898306 0.3472222 ]\n", " [0.10909091 0.75 0.3559322 0.41666666]\n", " [0.6690909 0.63095236 0.47457626 0.19444445]\n", " [0.8036364 0.9166667 0.4915254 0.44444445]\n", " [0.4909091 0.75 0.37288135 0.22916667]\n", " [0.33454546 0.85714287 0.37288135 0.2361111 ]\n", " [0.32 0.41666666 0.2542373 0.1388889 ]\n", " [0.41454545 0.5952381 0.5084746 0.19444445]\n", " [0.14909092 0.48809522 0.2542373 0.125 ]\n", " [0.23636363 0.4642857 0.27118644 0.05555556]\n", " [0.22181818 0.5952381 0.22033899 0.3472222 ]\n", " [0.24727273 0.5595238 0.15254237 0.25694445]\n", " [0.63272727 0.35714287 0.88135594 0.8194444 ]\n", " [0.47272727 0.15476191 0.6440678 0.4722222 ]\n", " [0.6036364 0.23809524 0.84745765 0.7361111 ]\n", " [0.26909092 0.5595238 0.27118644 0.16666667]\n", " [0.28 0.71428573 0.20338982 0.5416667 ]\n", " [0.10545454 0.5714286 0.33898306 0.2847222 ]\n", " [0.18545455 0.5952381 0.10169491 0.33333334]\n", " [0.47272727 0.16666667 0.7288136 0.6388889 ]\n", " [0.45090908 0.1904762 0.7118644 0.5972222 ]\n", " [0.49454546 0.5 0.3559322 0.25 ]\n", " [0.6363636 0.22619048 0.7457627 0.5694444 ]\n", " [0.08727273 0.5952381 0.2542373 0.05555556]\n", " [0.52 0.22619048 0.7457627 0.5555556 ]\n", " [0.5090909 0.23809524 0.7288136 0.6666667 ]\n", " [0.56 0.22619048 0.779661 0.625 ]\n", " [0.6363636 0.3452381 0.89830506 0.8333333 ]\n", " [0.15636364 0.47619048 0.20338982 0.04166667]], shape=(32, 4), dtype=float32)\n", "tf.Tensor([0 2 1 0 0 1 1 1 0 1 1 0 0 0 0 2 2 2 0 0 0 0 2 2 1 2 0 2 2 2 2 0], shape=(32,), dtype=int64)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 22:26:22.169381: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n" ] } ], "source": [ "features, labels = next(iter(ds_train_batch))\n", "\n", "print(features)\n", "print(labels)" ] }, { "cell_type": "markdown", "metadata": { "id": "E63mArnQaAGz" }, "source": [ "배치에서 일부 특성을 플롯하여 클러스터를 시각화할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.188240Z", "iopub.status.busy": "2022-12-14T22:26:22.187523Z", "iopub.status.idle": "2022-12-14T22:26:22.344114Z", "shell.execute_reply": "2022-12-14T22:26:22.343395Z" }, "id": "me5Wn-9FcyyO" }, "outputs": [ { "data": { "image/png": "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KioKX375ZYM7QERERNRQNl+Wys3NxbPPPov58+dXW//SSy/h1KlT2Lp1K+Li4rBkyRKMGTPGbkGJiIiIrGHzZSmDwYCUlBR06dKl2vr09HSEhYWhoKAAR48exYABA1BUVGTXsPbAy1JERETNj0MvS+n1euzcubPG+p07d0Kv1wOouqX7yv8TERERKcnmy1KzZs3C448/jpSUFAwYMAAA8Ntvv+G9997DCy+8AADYsmULQkND7RqUiIiIyBo2X5YCgI8++ghvvvkm0tLSAADdu3fHrFmzMGHCBABAaWmp5e6ppoaXpYiIiJofWz6/G1TcNGcsboiIiJofWz6/bb4sdUV5eTmys7OrPQoBADp06NDQQxIRERE1ms3FzbFjxzBlypQag4qvPC3cbDbbLRwRERGRrWwubiZPngwXFxd88803CAoKqnW2YiIiIiK12Fzc7N27FykpKejRo4cj8hARERE1is3z3PTq1Qu5ubmOyEJERETUaDYXNy+//DKee+45bN++HRcuXEBhYWG1hYiIiEhNNt8KrtFU1UPXjrVpLgOKeSs4ERFR8+PQW8G3bdvW4GBEREREjmZzcTNkyBBH5CAiIiKyC5vH3ADAzz//jEcffRSDBg3C2bNnAQAffPABduzYYddwRERERLayubj573//i+HDh6NVq1ZITU2FyWQCABQUFGDp0qV2D0hERERkC5uLm5deegmrVq3C6tWr4erqalk/ePBgpKam2jUcERERka1sLm7S0tJw22231VhvMBhw8eJFe2QiIiIiajCbi5vAwECkp6fXWL9jxw506tTJLqGIiIiIGsrm4mbatGl46qmnsHv3bkiShHPnzuGjjz7C7Nmz8cQTTzgiIxEREZHVbL4VfM6cOZBlGXfccQcuXbqE2267DTqdDrNnz8asWbMckZGIiIjIajbPUHxFeXk50tPTUVxcjF69ekGv1yM7Oxvt2rWzd0a74gzFREREzY9DZyi+ws3NDb169bK83rdvH/r379/kH79AREREzq1Bk/gRERERNVUNPnNDRNQYlbKM7X+cwOGcHLhptbj9hk7o1sZP7VhE5ARY3BCR4v537ixmffs1skpK4KLRQBYCr+z8GcNCbsDrw0fBW6dTOyIRNWNWFzf79++vd3taWlqjwxCR8zuedwGTvvgM5ZfH51XKsmXbT6f+wLSvP8f6ceMhSZJa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gCzL6NChA2bOnIk5c+bUus8rr7yCv//979iyZQtuvvlmm96vpc5zQ0RE1JzZ8vmt+uMXYmNjER0djfDwcERERCAhIQElJSWIiYkBAEyaNAnBwcGIj48HALz88stYsGABPv74Y4SEhFjG5nh6esLT01O1fhAREVHToHpxM378eOTk5GDBggXIzMxEaGgoEhMTLYOMMzIyql0uefvtt1FeXo6//OUv1Y4TFxeHhQsXKhmdiIiImiDVL0spjZeliIiImp9m9/gFIiIiInthcUNEREROhcUNERERORUWN0RERORUWNwQERGRU2FxQ0RERE6FxQ0RERE5FdUn8SNyBLPZjH3bDiH3bB58Awzod0dvuLjy252IqCXgT3tyOj9v3I2Vf1uDC+fyLesMbb3x1+WTcOfEISomIyIiJbC4Iaey88vfsPiB5cA1824X5BTileg3IWSBu6KHqpKNiIiUwTE35DRkWcbbsevqbfPu//0blRWVygQiIiJVsLghp3F09zFknsyucdbmagW5RUj5br9yoYiISHEsbshp5GcVWNcu86JjgxARkapY3JDT8AtubVW7Nla2IyKi5onFDTmNbuGd0b5bECRJqrONb6AP+t/RW8FURESkNBY35DQkScKMfz4GSKizwJnxjynQumgVTkZEREpicUNOJfyuvvj7phfQrktgtfX+HdtiwWezMeSBgSolIyIipUhCiHruLXE+hYWFMBgMKCgogLe3t9pxyEGEEDianI7cMxfgG2BAr0HdodGwliciaq5s+fzmJH7klCRJQs/IrkBkV7WjEBGRwvirLBERETkVFjdERETkVFjcEBERkVNhcUNEREROhcUNERERORUWN0RERORUWNwQERGRU2FxQ0RERE6FxQ0RERE5FRY3RERE5FT4+AVqkHJTBba8vw3fvLMVmSez4eXriaiJt2HMjBHwDfBROx4REbVgfHAm2ay0pAxz7lqCw7/+DgkSrnwLabQaeLX2xOs/LYaxe7DKKYmIyJnY8vmt+mWplStXIiQkBHq9HpGRkUhOTq6z7aFDhzBu3DiEhIRAkiQkJCQoF5Qs1r7wMY4mpwMCuLo2ls0yivKKsfiB19DCamYiImpCVC1uNmzYgNjYWMTFxSE1NRV9+/bF8OHDkZ2dXWv7S5cuoVOnTli2bBkCAwMVTksAUFpcim/X/ADZLNe6XTbL+OPg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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.scatter(features[:,0],\n", " features[:,2],\n", " c=labels,\n", " cmap='viridis')\n", "\n", "plt.xlabel(\"Body Mass\")\n", "plt.ylabel(\"Culmen Length\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "LsaVrtNM3Tx5" }, "source": [ "## 간단한 선형 모델 구축하기\n", "\n", "### 왜 모델을 사용해야하는가?\n", "\n", "*[모델](https://developers.google.com/machine-learning/crash-course/glossary#model)*은 특성과 레이블 간의 관계입니다. 펭귄 분류 문제의 경우, 모델은 체질량과 펭귄날개 및 펭귄 부리 측정치와 예측된 펭귄 종 간의 관계를 정의합니다. 일부 간단한 모델은 몇 줄의 대수로 설명할 수 있지만, 복잡한 머신러닝 모델에는 요약하기 어려운 매개변수가 많습니다.\n", "\n", "머신러닝을 사용하지 *않고* 4가지 특성과 펭귄 종 간의 관계를 확인할 수 있을까요? 즉, 기존 프로그래밍 기술(예: 여러 개의 조건문)을 사용하여 모델을 만들 수 있을까요? 특정 종에 대한 체질량과 펭귄 부리 측정치 간의 관계를 확인할 수 있을 만큼 충분히 오랫동안 데이터세트를 분석한 경우 가능할 수도 있습니다. 그러나 이것은 더 복잡한 데이터세트에서는 어렵거나 불가능할 수도 있습니다. 좋은 머신러닝 접근 방식이라면 적절한 모델을 제시해 줍니다. 적절한 머신러닝 모델 형식에 충분한 대표 예제를 제공하면 프로그램이 관계를 파악해 줍니다.\n", "\n", "### 모델 선정\n", "\n", "훈련할 모델의 종류를 선택해야 합니다. 많은 형식의 모델이 있으며 좋은 모델을 선택하려면 경험이 필요합니다. 이 튜토리얼에서는 신경망을 사용하여 펭귄 분류 문제를 해결합니다. [*신경망*](https://developers.google.com/machine-learning/glossary/#neural_network)은 특성과 레이블 간의 복잡한 관계를 찾을 수 있으며, 하나 이상의 [*숨겨진 레이어*](https://developers.google.com/machine-learning/glossary/#hidden_layer)로 구성된 고도로 구조화된 그래프입니다. 각 숨겨진 레이어는 하나 이상의 [*신경*](https://developers.google.com/machine-learning/glossary/#neuron)으로 구성됩니다. 신경망에는 여러 범주가 있으며, 이 프로그램은 조밀하거나 [*완전히 연결된 신경망*](https://developers.google.com/machine-learning/glossary/#fully_connected_layer)을 사용합니다. 즉, 한 레이어의 신경은 이전 레이어의 *모든* 신경에서 입력 연결을 받습니다. 예를 들어, 그림 2는 입력 레이어, 2개의 숨겨진 레이어 및 출력 레이어로 구성된 조밀한 신경망을 보여줍니다.\n", "\n", "\n", " \n", " \n", "
그림 2. 특성, 숨겨진 레이어, 예측으로 구성된 신경망
\n", "\n", "그림 2의 모델을 훈련하고 레이블이 지정되지 않은 예제를 제공하면, 이 펭귄이 주어진 펭귄 종일 가능성에 대한 3가지 예측값이 생성됩니다. 이 예측을 [*추론*](https://developers.google.com/machine-learning/crash-course/glossary#inference)이라고 합니다. 이 예제에서 출력 예측값의 합계는 1.0입니다. 그림 2에서 이 예측은 *아델리 펭귄*의 경우 `0.02`, *턱끈 펭귄*의 경우 `0.95`, *젠투 펭귄*의 경우 `0.03`입니다. 즉, 모델은 95% 확률로 레이블이 지정되지 않은 예제 펭귄이 *턱끈* 펭귄이라고 예측합니다." ] }, { "cell_type": "markdown", "metadata": { "id": "W23DIMVPQEBt" }, "source": [ "### 케라스를 사용한 모델 생성\n", "\n", "TensorFlow의 `tf.keras` API는 모델과 레이어를 생성하는 데 주로 사용됩니다. Keras가 모든 구성 요소 연결에 대한 복잡성을 처리해 주기 때문에 모델을 구축하고 실험하는 데 용이합니다.\n", "\n", "`tf.keras.Sequential` 모델은 레이어의 선형 스택입니다. 이 생성자는 레이어 인스턴스 목록을 취하는데, 아래의 경우, 각 10개의 노드를 갖는 두 개의 `tf.keras.layers.Dense` 레이어 및 3개의 노드를 갖는 출력 레이어로 구성되어 레이블 예측을 보여주고 있습니다. 첫 번째 레이어의 `input_shape` 매개변수는 데이터세트의 특성 수에 해당하며 필수적입니다." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.348013Z", "iopub.status.busy": "2022-12-14T22:26:22.347732Z", "iopub.status.idle": "2022-12-14T22:26:22.409312Z", "shell.execute_reply": "2022-12-14T22:26:22.408565Z" }, "id": "2fZ6oL2ig3ZK" }, "outputs": [], "source": [ "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(10, activation=tf.nn.relu, input_shape=(4,)), # input shape required\n", " tf.keras.layers.Dense(10, activation=tf.nn.relu),\n", " tf.keras.layers.Dense(3)\n", "])" ] }, { "cell_type": "markdown", "metadata": { "id": "FHcbEzMpxbHL" }, "source": [ "*[활성화 함수](https://developers.google.com/machine-learning/crash-course/glossary#activation_function)*는 각 레이어의 노드에서 출력 형상을 결정합니다. 이러한 비선형성이 중요한데, 활성화 함수가 없는 모델은 단일 레이어와 마찬가지이기 때문입니다. `tf.keras.activations`가 많이 있지만, 숨겨진 레이어에서는 주로 [ReLU](https://developers.google.com/machine-learning/crash-course/glossary#ReLU) 함수가 사용됩니다.\n", "\n", "숨겨진 레이어와 신경의 이상적인 수는 문제와 데이터세트에 따라 다릅니다. 머신러닝의 여러 측면과 마찬가지로 신경망의 최상의 형태를 고르기 위해서는 지식과 실험이 모두 필요합니다. 경험상 숨겨진 레이어와 신경의 수를 늘리면 일반적으로 더 강력한 모델이 생성되며 이를 효과적으로 훈련하려면 더 많은 데이터가 필요합니다." ] }, { "cell_type": "markdown", "metadata": { "id": "2wFKnhWCpDSS" }, "source": [ "### 모델 사용하기\n", "\n", "이 모델이 특성의 배치에 대해 수행하는 작업을 간단히 살펴봅시다." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.414074Z", "iopub.status.busy": "2022-12-14T22:26:22.413393Z", "iopub.status.idle": "2022-12-14T22:26:22.752584Z", "shell.execute_reply": "2022-12-14T22:26:22.751919Z" }, "id": "xe6SQ5NrpB-I" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "predictions = model(features)\n", "predictions[:5]" ] }, { "cell_type": "markdown", "metadata": { "id": "wxyXOhwVr5S3" }, "source": [ "여기에서 각 예제는 각 클래스에 대한 [로짓](https://developers.google.com/machine-learning/crash-course/glossary#logits)을 반환합니다.\n", "\n", "이러한 로짓을 각 클래스의 확률로 변환하려면 [softmax](https://developers.google.com/machine-learning/crash-course/glossary#softmax) 함수를 사용하세요." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.756488Z", "iopub.status.busy": "2022-12-14T22:26:22.755866Z", "iopub.status.idle": "2022-12-14T22:26:22.762998Z", "shell.execute_reply": "2022-12-14T22:26:22.762387Z" }, "id": "_tRwHZmTNTX2" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.nn.softmax(predictions[:5])" ] }, { "cell_type": "markdown", "metadata": { "id": "uRZmchElo481" }, "source": [ "클래스에서 `tf.math.argmax`를 사용하면 예측된 클래스 인덱스가 제공됩니다. 그러나 모델은 아직 훈련되지 않았으므로 좋은 예측을 하지 않습니다." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.766715Z", "iopub.status.busy": "2022-12-14T22:26:22.766121Z", "iopub.status.idle": "2022-12-14T22:26:22.772449Z", "shell.execute_reply": "2022-12-14T22:26:22.771781Z" }, "id": "-Jzm_GoErz8B" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Prediction: [2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]\n", " Labels: [0 2 1 0 0 1 1 1 0 1 1 0 0 0 0 2 2 2 0 0 0 0 2 2 1 2 0 2 2 2 2 0]\n" ] } ], "source": [ "print(\"Prediction: {}\".format(tf.math.argmax(predictions, axis=1)))\n", "print(\" Labels: {}\".format(labels))" ] }, { "cell_type": "markdown", "metadata": { "id": "Vzq2E5J2QMtw" }, "source": [ "## 모델 훈련하기\n", "\n", "*[훈련하기](https://developers.google.com/machine-learning/crash-course/glossary#training)*는 모델이 점차 최적화될 때 또는 모델이 데이터세트를 학습하는 머신러닝 단계입니다. 이 단계의 목표는 훈련 데이터세트의 구조에 대해 충분히 학습하여 보이지 않는 데이터를 예측하는 것입니다. 훈련 데이터세트에 대해 너무 많이 배우면 예측이 관측한 데이터에 대해서만 작동하고 일반화할 수 없습니다. 이런 문제를 과대적합이라고 하며, 이는 문제를 해결하는 방법을 이해하는 대신 답을 암기하는 것과 같습니다.\n", "\n", "펭귄 분류 문제는 [*감독 머신러닝*](https://developers.google.com/machine-learning/glossary/#supervised_machine_learning)의 예입니다. 모델은 레이블이 포함된 예제로 훈련됩니다. [*비감독 머신러닝*](https://developers.google.com/machine-learning/glossary/#unsupervised_machine_learning)에서는 예제에 레이블이 포함되지 않습니다. 대신 모델은 일반적으로 특성 사이에서 패턴을 찾습니다." ] }, { "cell_type": "markdown", "metadata": { "id": "RaKp8aEjKX6B" }, "source": [ "### 손실 함수와 경사 함수 정의하기\n", "\n", "훈련 및 평가 단계 모두에서 모델 [*손실*](https://developers.google.com/machine-learning/crash-course/glossary#loss)을 계산해야 합니다. 이것은 모델의 예측이 원하는 레이블에서 얼마나 떨어져 있는지, 즉 모델의 성능이 얼마나 안 좋은지를 측정하는 것으로, 그 값을 최소화하거나 최적화해야 합니다.\n", "\n", "모델의 손실은 `tf.keras.losses.categorical_crossentropy` 함수를 사용해 계산합니다. 이 함수는 모델의 클래스 확률 예측과 원하는 레이블을 입력으로 받아 예의 평균 손실을 반환합니다." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.775977Z", "iopub.status.busy": "2022-12-14T22:26:22.775479Z", "iopub.status.idle": "2022-12-14T22:26:22.779022Z", "shell.execute_reply": "2022-12-14T22:26:22.778398Z" }, "id": "QOsi6b-1CXIn" }, "outputs": [], "source": [ "loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.782543Z", "iopub.status.busy": "2022-12-14T22:26:22.781914Z", "iopub.status.idle": "2022-12-14T22:26:22.799435Z", "shell.execute_reply": "2022-12-14T22:26:22.798740Z" }, "id": "tMAT4DcMPwI-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loss test: 1.077925682067871\n" ] } ], "source": [ "def loss(model, x, y, training):\n", " # training=training is needed only if there are layers with different\n", " # behavior during training versus inference (e.g. Dropout).\n", " y_ = model(x, training=training)\n", "\n", " return loss_object(y_true=y, y_pred=y_)\n", "\n", "l = loss(model, features, labels, training=False)\n", "print(\"Loss test: {}\".format(l))" ] }, { "cell_type": "markdown", "metadata": { "id": "3IcPqA24QM6B" }, "source": [ "모델을 최적화하기 위해 사용되는 *[그래디언트](https://developers.google.com/machine-learning/crash-course/glossary#gradient)*를 계산하기 위해 `tf.GradientTape` 컨텍스트를 사용합니다." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.803438Z", "iopub.status.busy": "2022-12-14T22:26:22.802820Z", "iopub.status.idle": "2022-12-14T22:26:22.806993Z", "shell.execute_reply": "2022-12-14T22:26:22.806250Z" }, "id": "x57HcKWhKkei" }, "outputs": [], "source": [ "def grad(model, inputs, targets):\n", " with tf.GradientTape() as tape:\n", " loss_value = loss(model, inputs, targets, training=True)\n", " return loss_value, tape.gradient(loss_value, model.trainable_variables)" ] }, { "cell_type": "markdown", "metadata": { "id": "lOxFimtlKruu" }, "source": [ "### 옵티마이저 생성\n", "\n", "[*옵티마이저*](https://developers.google.com/machine-learning/crash-course/glossary#optimizer)는 계산된 경사를 모델의 매개변수에 적용하여 `loss` 함수를 최소화합니다. 손실 함수를 곡면에 비유한다면(그림 3 참조) 곡면에서 가장 낮은 지점을 찾는 것과 같다고 할 수 있습니다. 경사는 가장 가파른 상승 방향을 가리키므로 반대 방향으로 이동하여 내려가야 합니다. 각 배치의 손실과 경사를 반복적으로 계산하여 훈련을 통해 모델을 조정합니다. 모델은 점차 손실을 최소화하기 위해 가중치와 바이어스의 최상의 조합을 찾습니다. 손실이 낮을수록 모델의 예측값은 더 좋아집니다.\n", "\n", "\n", " \n", " \n", "
\"Optimization
그림 3. 3D 공간에서 시간에 걸쳐 시각화한 최적화 알고리즘.
(출처: Stanford class CS231n, MIT License, 이미지 제공: Alec Radford)
\n", "\n", "TensorFlow에는 훈련에 사용할 수 있는 많은 최적화 알고리즘이 있습니다. 이 튜토리얼에서는 [*확률적 경사하강법*](https://developers.google.com/machine-learning/crash-course/glossary#gradient_descent)(SGD) 알고리즘을 구현하는 `tf.keras.optimizers.SGD`를 사용합니다. `learning_rate` 매개변수는 경사 아래로 반복할 때마다 수행할 단계 크기를 설정합니다. 이 비율은 더 나은 결과를 얻기 위해 일반적으로 조정하는 [*하이퍼 매개변수*](https://developers.google.com/machine-learning/glossary/#hyperparameter)입니다." ] }, { "cell_type": "markdown", "metadata": { "id": "XkUd6UiZa_dF" }, "source": [ "[*학습률*](https://developers.google.com/machine-learning/glossary#learning-rate)이 `0.01`인 최적화 도구를 인스턴스화합니다. 스칼라 값은 각 훈련 반복에서 기울기를 곱한 값입니다." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.810535Z", "iopub.status.busy": "2022-12-14T22:26:22.810188Z", "iopub.status.idle": "2022-12-14T22:26:22.817116Z", "shell.execute_reply": "2022-12-14T22:26:22.816424Z" }, "id": "8xxi2NNGKwG_" }, "outputs": [], "source": [ "optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)" ] }, { "cell_type": "markdown", "metadata": { "id": "pJVRZ0hP52ZB" }, "source": [ "그런 다음 이 개체를 사용하여 단일 최적화 단계를 계산합니다." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:22.820959Z", "iopub.status.busy": "2022-12-14T22:26:22.820424Z", "iopub.status.idle": "2022-12-14T22:26:23.253246Z", "shell.execute_reply": "2022-12-14T22:26:23.252545Z" }, "id": "rxRNTFVe56RG" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Step: 0, Initial Loss: 1.077925682067871\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:6 out of the last 6 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:6 out of the last 6 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Step: 1, Loss: 1.0767297744750977\n" ] } ], "source": [ "loss_value, grads = grad(model, features, labels)\n", "\n", "print(\"Step: {}, Initial Loss: {}\".format(optimizer.iterations.numpy(),\n", " loss_value.numpy()))\n", "\n", "optimizer.apply_gradients(zip(grads, model.trainable_variables))\n", "\n", "print(\"Step: {}, Loss: {}\".format(optimizer.iterations.numpy(),\n", " loss(model, features, labels, training=True).numpy()))" ] }, { "cell_type": "markdown", "metadata": { "id": "7Y2VSELvwAvW" }, "source": [ "### 훈련 루프\n", "\n", "여기까지 모두 마쳤다면 모델을 훈련할 준비가 되었습니다! 훈련 루프는 더 나은 예측을 할 수 있도록 데이터세트 예제를 모델에 제공합니다. 다음 코드 블록은 이러한 훈련 단계를 설정합니다.\n", "\n", "1. 각 *epoch* 반복. Epoch는 데이터세트를 통과시키는 횟수입니다.\n", "2. 하나의 Epoch 내에서 *특성*(`x`)과 *레이블*(`y`)이 포함된 훈련 `Dataset`의 각 예를 반복합니다.\n", "3. 예의 특성을 사용하여 예측을 수행하고 레이블과 비교합니다. 예측의 부정확성을 측정하고 이를 사용하여 모델의 손실 및 그래디언트를 계산합니다.\n", "4. `optimizer`를 사용하여 모델의 매개변수를 업데이트합니다.\n", "5. 시각화를 위해 몇가지 값들을 저장합니다.\n", "6. 각 epoch에 대해 반복합니다.\n", "\n", "`num_epochs` 변수는 데이터세트 모음을 반복하는 횟수입니다. 아래 코드에서 `num_epochs`가 201로 설정되어 있기에 이 훈련 루프는 201번 실행됩니다. 단순히 생각해도 모델을 더 오래 훈련한다고 해서 더 나은 모델이 보장되지는 않습니다. `num_epochs`는 조정할 수 있는 [*하이퍼 매개변수*](https://developers.google.com/machine-learning/glossary/#hyperparameter)입니다. 적절한 횟수의 선택에는 많은 경험과 직관이 필요합니다." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:23.257396Z", "iopub.status.busy": "2022-12-14T22:26:23.256778Z", "iopub.status.idle": "2022-12-14T22:26:55.566093Z", "shell.execute_reply": "2022-12-14T22:26:55.565040Z" }, "id": "AIgulGRUhpto" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 000: Loss: 1.071, Accuracy: 35.581%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 050: Loss: 0.688, Accuracy: 80.524%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 100: Loss: 0.437, Accuracy: 80.899%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 150: Loss: 0.319, Accuracy: 88.764%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 200: Loss: 0.231, Accuracy: 94.757%\n" ] } ], "source": [ "## Note: Rerunning this cell uses the same model parameters\n", "\n", "# Keep results for plotting\n", "train_loss_results = []\n", "train_accuracy_results = []\n", "\n", "num_epochs = 201\n", "\n", "for epoch in range(num_epochs):\n", " epoch_loss_avg = tf.keras.metrics.Mean()\n", " epoch_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()\n", "\n", " # Training loop - using batches of 32\n", " for x, y in ds_train_batch:\n", " # Optimize the model\n", " loss_value, grads = grad(model, x, y)\n", " optimizer.apply_gradients(zip(grads, model.trainable_variables))\n", "\n", " # Track progress\n", " epoch_loss_avg.update_state(loss_value) # Add current batch loss\n", " # Compare predicted label to actual label\n", " # training=True is needed only if there are layers with different\n", " # behavior during training versus inference (e.g. Dropout).\n", " epoch_accuracy.update_state(y, model(x, training=True))\n", "\n", " # End epoch\n", " train_loss_results.append(epoch_loss_avg.result())\n", " train_accuracy_results.append(epoch_accuracy.result())\n", "\n", " if epoch % 50 == 0:\n", " print(\"Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}\".format(epoch,\n", " epoch_loss_avg.result(),\n", " epoch_accuracy.result()))" ] }, { "cell_type": "markdown", "metadata": { "id": "Diep-ROEuKyl" }, "source": [ "또는 내장된 Keras [`Model.fit(ds_train_batch)`](https://www.tensorflow.org/api_docs/python/tf/keras/Model#fit) 메서드를 사용하여 모델을 훈련할 수 있습니다. " ] }, { "cell_type": "markdown", "metadata": { "id": "2FQHVUnm_rjw" }, "source": [ "### 시간에 따른 손실함수 시각화" ] }, { "cell_type": "markdown", "metadata": { "id": "j3wdbmtLVTyr" }, "source": [ "모델의 훈련 과정을 출력하는 것도 유용하지만 TensorFlow와 함께 제공되는 시각화 및 메트릭 도구인 [텐서보드](https://www.tensorflow.org/tensorboard)(TensorBoard)를 사용하여 훈련 과정을 시각화할 수 있습니다. 이 간단한 예제에서는 `matplotlib` 모듈을 사용하여 기본 차트를 만듭니다.\n", "\n", "이러한 차트를 해석하려면 어느 정도의 경험이 필요하지만, 일반적으로 *손실*은 감소하고 *정확성*이 증가하는 것을 확인하고자 합니다." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:55.570405Z", "iopub.status.busy": "2022-12-14T22:26:55.570078Z", "iopub.status.idle": "2022-12-14T22:26:55.847727Z", "shell.execute_reply": "2022-12-14T22:26:55.846992Z" }, "id": "agjvNd2iUGFn" }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+4AAAL8CAYAAAB+je+aAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAACX/0lEQVR4nOzdd3jV9f3+8fuck+RkJ2RPVhhBtozIBqXiFgdi1aKorVLRKrYV6rattKXyRQWl9YdbK4rWhYKKIorIRvYMIYvscbLHOef3R+BImjBO1jlJno/rOlc87896JQeVO+9lsNvtdgEAAAAAALdkdHUBAAAAAADg9AjuAAAAAAC4MYI7AAAAAABujOAOAAAAAIAbI7gDAAAAAODGCO4AAAAAALgxgjsAAAAAAG6M4A4AAAAAgBsjuAMAAAAA4MYI7gAAtJHbbrtN3bt3b9K1TzzxhAwGQ8sW1M415+cJAEB7QnAHAHR6BoPhnF5r1651dakucdttt8lgMCgwMFAVFRUNjh86dMjxM/rnP//p9P3Ly8v1xBNPdNqfLwAAZ+Ph6gIAAHC1N954o977119/XV9++WWD9n79+jXrOS+99JJsNluTrn3kkUc0d+7cZj2/OTw8PFReXq5PPvlEN9xwQ71jb731lry9vVVZWdmke5eXl+vJJ5+UJE2cOPGcr2vOzxMAgPaE4A4A6PRuueWWeu9//PFHffnllw3a/1d5ebl8fX3P+Tmenp5Nqk+qC84eHq7737bZbNaYMWP0n//8p0Fwf/vtt3X55Zfr/fffb5NaysrK5Ofn16yfJwAA7QlD5QEAOAcTJ07UgAEDtHXrVo0fP16+vr7605/+JEn66KOPdPnllysmJkZms1kJCQn685//LKvVWu8e/zsnOyUlxTG8/N///rcSEhJkNps1YsQIbd68ud61jc1xNxgMmj17tj788EMNGDBAZrNZ/fv316pVqxrUv3btWg0fPlze3t5KSEjQv/71L6fnzd900036/PPPVVRU5GjbvHmzDh06pJtuuqnRa4qKinT//fcrPj5eZrNZvXr10t///ndHT3lKSorCw8MlSU8++aRjyP0TTzzh+Jn5+/vryJEjuuyyyxQQEKCbb7650Z+nJNlsNj377LMaOHCgvL29FR4erksuuURbtmxxnPPll19q7NixCg4Olr+/v/r27ev4LAEAcEf0uAMAcI7y8/N16aWX6sYbb9Qtt9yiyMhISdKrr74qf39/zZkzR/7+/vr666/12GOPyWKxaMGCBWe979tvv62SkhLdddddMhgM+sc//qFrr71WycnJZ+1V/v777/XBBx/ot7/9rQICAvTcc8/puuuuU2pqqkJDQyVJ27dv1yWXXKLo6Gg9+eSTslqteuqppxyB+Vxde+21uvvuu/XBBx/o9ttvd9SemJio888/v8H55eXlmjBhgjIyMnTXXXepa9eu+uGHHzRv3jwdP35cixYtUnh4uF588UXNmjVL11xzja699lpJ0qBBgxz3qa2t1ZQpUzR27Fj985//POMohzvuuEOvvvqqLr30Ut15552qra3Vd999px9//FHDhw/Xnj17dMUVV2jQoEF66qmnZDabdfjwYa1fv96pnwUAAG2J4A4AwDnKysrS0qVLddddd9Vrf/vtt+Xj4+N4f/fdd+vuu+/WCy+8oL/85S8ym81nvG9qaqoOHTqkLl26SJL69u2rq6++WqtXr9YVV1xxxmv37dunvXv3KiEhQZI0adIkDR48WP/5z380e/ZsSdLjjz8uk8mk9evXKyYmRpJ0ww03OD1nPyAgQFdccYXefvtt3X777bLZbHrnnXc0a9asRs9fuHChjhw5ou3bt6t3796SpLvuuksxMTFasGCBHnzwQcXHx+v666/XrFmzNGjQoEanJ1RVVWnatGmaP3/+Gev75ptv9Oqrr+q+++7Ts88+62h/8MEHZbfbJdX1tldXV+vzzz9XWFiYU98/AACuwlB5AADOkdls1syZMxu0nxraS0pKlJeXp3Hjxqm8vFz79+8/632nT5/uCO2SNG7cOElScnLyWa+dPHmyI7RLdT3VgYGBjmutVqu++uorTZ061RHaJalXr1669NJLz3r//3XTTTdp7dq1ysrK0tdff62srKzTDpN/7733NG7cOHXp0kV5eXmO1+TJk2W1WrVu3bpzfu7pfjlwqvfff18Gg0GPP/54g2MnpwQEBwdLqpvewMJ2AID2guAOAMA5io2NlZeXV4P2PXv26JprrlFQUJACAwMVHh7u6DkuLi4+6327du1a7/3JEF9YWOj0tSevP3ltTk6OKioq1KtXrwbnNdZ2NifnmS9fvlxvvfWWRowYcdr7HDp0SKtWrVJ4eHi91+TJkx21nQsPDw/FxcWd9bwjR44oJiZGISEh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NeHh4frwww9VWVmp/Px8xcTEaO7cuerZs+dpn2M2m2U28x83AAAAuBerza5nvzqo5785LLtdig320bThcbru/DjFh/i6ujwALuJW42i8vLw0bNgwrVmzxtFms9m0Zs0ajRo16ozXent7KzY2VrW1tXr//fd19dVXt3a5AAAAQIvJK63SjJc36rmv60L7TUldtebBCbp/ch9CO9DJuVWPuyTNmTNHt956q4YPH66RI0dq0aJFKisr08yZMyVJM2bMUGxsrObPny9J2rhxozIyMjRkyBBlZGToiSeekM1m0x//+EdXfhsAAADooFbtztK/1x1RefXp11RqiixLpYrKa+TjadLT1w7QNUPjWvT+ANovtwvu06dPV25urh577DFlZWVpyJAhWrVqlWPButTUVBlPmddTWVmpRx55RMnJyfL399dll12mN954Q8HBwS76DgAAANARVdfa9LfP9+vl9Udb7Rm9Ivz14s3nq3dkQKs9A0D743b7uLsC+7gDAADgTDKLKnTP29u0PbVIknTn2B6a0De8RZ/hYTRqaNdgeXuaWvS+ANxTu93HHQAAAHAnZVW1+nRnpv72+X4Vltco0NtDz9wwRL84L/LsFwNACyG4AwAAAKew2+3allqodzen69OdmSo7MZd9QGygXrx5GAvFAWhzBHcAAAB0eDabXRuS8/XeljR9tS9HlTWnX1jOrrpt2U7qHuqrG0bE6/YxPRjGDsAlCO4AAABol2qtNm1Izle2peqM56UWlOv9renKKKo453v7epl02cBo3TA8XiO6d5HBYGhuuQDQZAR3AAAAtCvJuaV6b2u63t+arpySM4f2UwWYPXTVkBhdNyxOscE+Zzw3yMeT3nUAboPgDgAAALdXWlWrz3Ye17tb0rTlWKGjvYuvpwbFBetMHeK+XiZN6R+lKf2jCOMA2iWCOwAAANxCda1NGUUVOnW34ixLpT7YlqHPdh1X+YlF4owGaWLfCN0wPE4XJkbKy8PoqpIBoE0Q3AEAAOBSezKL9d6WdH24I0NF5TWnPa9nmJ+mDY/XtefHKjLQuw0rBADXIrgDAACg1VXWWPX2xlRlWyodbTa7XT8cydeeTIujzcfTJE/Tz+PevTxMuigxQjeMiNP5XVkkDkDnRHAHAABAqzqWX6bfvrWtXkA/lafJoIvPi9L1w+M0vne4TEbCOQCciuAOAACA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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))\n", "fig.suptitle('Training Metrics')\n", "\n", "axes[0].set_ylabel(\"Loss\", fontsize=14)\n", "axes[0].plot(train_loss_results)\n", "\n", "axes[1].set_ylabel(\"Accuracy\", fontsize=14)\n", "axes[1].set_xlabel(\"Epoch\", fontsize=14)\n", "axes[1].plot(train_accuracy_results)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "Zg8GoMZhLpGH" }, "source": [ "## 모델 유효성 평가\n", "\n", "이제 모델이 훈련되었으므로 성능에 대한 통계를 얻을 수 있습니다.\n", "\n", "*평가*는 모델이 얼마나 효과적으로 예측을 수행하는지 알아보는 것을 의미합니다. 펭귄 분류에서 모델의 효과를 확인하려면 측정 정보를 모델에 전달하고 해당 모델이 펭귄 종을 예측하도록 요청합니다. 그런 다음 모델의 예측을 실제 레이블과 비교합니다. 예를 들어, 입력 예제의 절반에서 올바른 종을 선택한 모델의 [*정확성*](https://developers.google.com/machine-learning/glossary/#accuracy)은 `0.5`입니다. 그림 4는 약간 더 효과적인 모델을 보여줍니다. 5개 예측 중 4개는 80% 정확성으로 정확합니다.\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", "
샘플 특성레이블모델 예측
5.93.04.31.511
6.93.15.42.122
5.13.31.70.500
6.0 3.4 4.5 1.6 12
5.52.54.01.311
그림 4. 정확성 80%의 펭귄 분류기
" ] }, { "cell_type": "markdown", "metadata": { "id": "z-EvK7hGL0d8" }, "source": [ "### 테스트 세트 설정하기\n", "\n", "모델 평가는 모델 훈련과 유사합니다. 가장 큰 차이점은 예제가 훈련 세트가 아닌 별도의 *[테스트 세트](https://developers.google.com/machine-learning/crash-course/glossary#test_set)*에서 나온다는 것입니다. 모델의 효과를 공정하게 평가하려면 모델을 평가하는 데 사용되는 예가 모델 훈련에 사용된 예와 달라야 합니다.\n", "\n", "펭귄 데이터세트에는 별도의 테스트 데이터세트가 없으므로 이전 데이터세트 다운로드 섹션에서 원본 데이터세트를 테스트 및 훈련 데이터세트로 분할했습니다. 평가를 위해 `ds_test_batch` 데이터세트를 사용합니다." ] }, { "cell_type": "markdown", "metadata": { "id": "HFuOKXJdMAdm" }, "source": [ "### 테스트 데이터 세트를 사용한 모델 평가\n", "\n", "훈련 단계와 달리 모델은 테스트 데이터의 단일 [epoch](https://developers.google.com/machine-learning/glossary/#epoch)만 평가합니다. 다음 코드는 테스트 세트의 각 예제를 반복하고 모델의 예측값을 실제 레이블과 비교합니다. 이 비교는 전체 테스트세트에서 모델의 정확성을 측정하는 데 사용됩니다." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:55.852333Z", "iopub.status.busy": "2022-12-14T22:26:55.851615Z", "iopub.status.idle": "2022-12-14T22:26:56.069022Z", "shell.execute_reply": "2022-12-14T22:26:56.068225Z" }, "id": "Tw03-MK1cYId" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test set accuracy: 94.030%\n" ] } ], "source": [ "test_accuracy = tf.keras.metrics.Accuracy()\n", "ds_test_batch = ds_test.batch(10)\n", "\n", "for (x, y) in ds_test_batch:\n", " # training=False is needed only if there are layers with different\n", " # behavior during training versus inference (e.g. Dropout).\n", " logits = model(x, training=False)\n", " prediction = tf.math.argmax(logits, axis=1, output_type=tf.int64)\n", " test_accuracy(prediction, y)\n", "\n", "print(\"Test set accuracy: {:.3%}\".format(test_accuracy.result()))" ] }, { "cell_type": "markdown", "metadata": { "id": "Fel8ql2qzGlK" }, "source": [ "`model.evaluate(ds_test, return_dict=True)` keras 함수를 사용하여 테스트 데이터세트의 정확성 정보를 가져올 수도 있습니다. " ] }, { "cell_type": "markdown", "metadata": { "id": "HcKEZMtCOeK-" }, "source": [ "예를 들어 마지막 배치를 검사하여 모델 예측이 일반적인 상황에서 정확한지 관찰할 수 있습니다.\n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:56.073660Z", "iopub.status.busy": "2022-12-14T22:26:56.072806Z", "iopub.status.idle": "2022-12-14T22:26:56.080584Z", "shell.execute_reply": "2022-12-14T22:26:56.079841Z" }, "id": "uNwt2eMeOane" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.stack([y,prediction],axis=1)" ] }, { "cell_type": "markdown", "metadata": { "id": "7Li2r1tYvW7S" }, "source": [ "## 훈련된 모델로 예측하기\n", "\n", "모델을 훈련하고 이 모델이 펭귄 종을 분류하는 데 훌륭함을 \"증명\"했지만 완벽하지는 않습니다. 이제 훈련된 모델을 사용하여 [*레이블이 없는 예제*](https://developers.google.com/machine-learning/glossary/#unlabeled_example)에 대한 예측을 수행해 보겠습니다. 즉, 특성은 포함하지만 레이블은 포함하지 않는 예제입니다.\n", "\n", "실제로 레이블이 없는 예제는 앱, CSV 파일, 데이터 피드 등 다양한 소스로부터 제공될 수 있습니다. 이 튜토리얼에서는 레이블을 예측하기 위해 레이블이 없는 3가지 예를 수동으로 제공합니다. 레이블 번호는 다음과 같이 표시됩니다.\n", "\n", "- `0`: 아델리 펭귄\n", "- `1`: 턱끈 펭귄\n", "- `2`: 젠투 펭귄" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:26:56.084556Z", "iopub.status.busy": "2022-12-14T22:26:56.083911Z", "iopub.status.idle": "2022-12-14T22:26:56.097959Z", "shell.execute_reply": "2022-12-14T22:26:56.097264Z" }, "id": "kesTS5Lzv-M2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Example 0 prediction: Adélie (78.5%)\n", "Example 1 prediction: Gentoo (98.3%)\n", "Example 2 prediction: Chinstrap (76.2%)\n" ] } ], "source": [ "predict_dataset = tf.convert_to_tensor([\n", " [0.3, 0.8, 0.4, 0.5,],\n", " [0.4, 0.1, 0.8, 0.5,],\n", " [0.7, 0.9, 0.8, 0.4]\n", "])\n", "\n", "# training=False is needed only if there are layers with different\n", "# behavior during training versus inference (e.g. Dropout).\n", "predictions = model(predict_dataset, training=False)\n", "\n", "for i, logits in enumerate(predictions):\n", " class_idx = tf.math.argmax(logits).numpy()\n", " p = tf.nn.softmax(logits)[class_idx]\n", " name = class_names[class_idx]\n", " print(\"Example {} prediction: {} ({:4.1f}%)\".format(i, name, 100*p))" ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "custom_training_walkthrough.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "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.9.16" } }, "nbformat": 4, "nbformat_minor": 0 }