{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "DweYe9FcbMK_" }, "source": [ "##### Copyright 2019 The TensorFlow Authors.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-14T21:07:02.786582Z", "iopub.status.busy": "2022-12-14T21:07:02.786194Z", "iopub.status.idle": "2022-12-14T21:07:02.790586Z", "shell.execute_reply": "2022-12-14T21:07:02.789958Z" }, "id": "AVV2e0XKbJeX" }, "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": "sUtoed20cRJJ" }, "source": [ "# CSV 데이터 로드하기" ] }, { "cell_type": "markdown", "metadata": { "id": "1ap_W4aQcgNT" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
TensorFlow.org에서 보기Google Colab에서 실행하기GitHub에서 소스 보기노트북 다운로드하기
" ] }, { "cell_type": "markdown", "metadata": { "id": "C-3Xbt0FfGfs" }, "source": [ "이 튜토리얼은 TensorFlow에서 CSV 데이터를 사용하는 방법에 대한 예제를 제공합니다.\n", "\n", "다음과 같이 두 가지 주요 내용이 있습니다.\n", "\n", "1. **Loading the data off disk**\n", "2. **Pre-processing it into a form suitable for training.**\n", "\n", "이 튜토리얼은 로딩에 중점을 두며 전처리에 대한 몇 가지 빠른 예를 제공합니다. 전처리 측면에 대해 자세히 알아보려면 [전처리 레이어 작업](https://www.tensorflow.org/guide/keras/preprocessing_layers) 가이드 및 [Keras 전처리 레이어를 사용하여 구조화된 데이터 분류](../structured_data/preprocessing_layers.ipynb) 튜토리얼을 확인하세요.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "fgZ9gjmPfSnK" }, "source": [ "## 설정하기" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:02.794323Z", "iopub.status.busy": "2022-12-14T21:07:02.793864Z", "iopub.status.idle": "2022-12-14T21:07:04.885471Z", "shell.execute_reply": "2022-12-14T21:07:04.884780Z" }, "id": "baYFZMW_bJHh" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 21:07:04.071551: 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 21:07:04.071675: 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 21:07:04.071686: 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" ] } ], "source": [ "import pandas as pd\n", "import numpy as np\n", "\n", "# Make numpy values easier to read.\n", "np.set_printoptions(precision=3, suppress=True)\n", "\n", "import tensorflow as tf\n", "from tensorflow.keras import layers" ] }, { "cell_type": "markdown", "metadata": { "id": "1ZhJYbJxHNGJ" }, "source": [ "## 인메모리 데이터" ] }, { "cell_type": "markdown", "metadata": { "id": "ny5TEgcmHjVx" }, "source": [ "작은 크기의 CSV 데이터세트를 사용하여 TensorFlow 모델을 훈련시키는 가장 간단한 방법은 이를 메모리에 pandas Dataframe 또는 NumPy 배열로 로드하는 것입니다.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "LgpBOuU8PGFf" }, "source": [ "비교적 간단한 예는 [전복 데이터세트](https://archive.ics.uci.edu/ml/datasets/abalone)입니다.\n", "\n", "- 데이터세트의 크기가 작습니다.\n", "- 모든 입력 특성은 모두 제한된 범위의 부동 소수점 값입니다.\n", "\n", "다음은 [Pandas `DataFrame`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html)에 데이터를 다운로드하는 방법입니다." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:04.890013Z", "iopub.status.busy": "2022-12-14T21:07:04.889584Z", "iopub.status.idle": "2022-12-14T21:07:04.941113Z", "shell.execute_reply": "2022-12-14T21:07:04.940455Z" }, "id": "IZVExo9DKoNz" }, "outputs": [ { "data": { "text/html": [ "
\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
LengthDiameterHeightWhole weightShucked weightViscera weightShell weightAge
00.4350.3350.1100.3340.13550.07750.09657
10.5850.4500.1250.8740.35450.20750.22506
20.6550.5100.1601.0920.39600.28250.370014
30.5450.4250.1250.7680.29400.14950.260016
40.5450.4200.1300.8790.37400.16950.230013
\n", "
" ], "text/plain": [ " Length Diameter Height Whole weight Shucked weight Viscera weight \\\n", "0 0.435 0.335 0.110 0.334 0.1355 0.0775 \n", "1 0.585 0.450 0.125 0.874 0.3545 0.2075 \n", "2 0.655 0.510 0.160 1.092 0.3960 0.2825 \n", "3 0.545 0.425 0.125 0.768 0.2940 0.1495 \n", "4 0.545 0.420 0.130 0.879 0.3740 0.1695 \n", "\n", " Shell weight Age \n", "0 0.0965 7 \n", "1 0.2250 6 \n", "2 0.3700 14 \n", "3 0.2600 16 \n", "4 0.2300 13 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abalone_train = pd.read_csv(\n", " \"https://storage.googleapis.com/download.tensorflow.org/data/abalone_train.csv\",\n", " names=[\"Length\", \"Diameter\", \"Height\", \"Whole weight\", \"Shucked weight\",\n", " \"Viscera weight\", \"Shell weight\", \"Age\"])\n", "\n", "abalone_train.head()" ] }, { "cell_type": "markdown", "metadata": { "id": "hP22mdyPQ1_t" }, "source": [ "이 데이터세트에는 바다 고등류의 일종인 [전복](https://en.wikipedia.org/wiki/Abalone) 측정값 세트가 포함되어 있습니다.\n", "\n", "![an abalone shell](https://tensorflow.org/images/abalone_shell.jpg)\n", "\n", "[“전복 껍질”](https://www.flickr.com/photos/thenickster/16641048623/) ([Nicki Dugan Pogue](https://www.flickr.com/photos/thenickster/) 제공, CC BY-SA 2.0)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "vlfGrk_9N-wf" }, "source": [ "이 데이터 세트의 명목상 작업은 다른 측정값으로부터 나이를 예측하는 것이므로 다음과 같이 훈련을 위해 특성과 레이블을 분리합니다.\n" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:04.945632Z", "iopub.status.busy": "2022-12-14T21:07:04.944963Z", "iopub.status.idle": "2022-12-14T21:07:04.949282Z", "shell.execute_reply": "2022-12-14T21:07:04.948686Z" }, "id": "udOnDJOxNi7p" }, "outputs": [], "source": [ "abalone_features = abalone_train.copy()\n", "abalone_labels = abalone_features.pop('Age')" ] }, { "cell_type": "markdown", "metadata": { "id": "seK9n71-UBfT" }, "source": [ "이 데이터세트에서는 모든 특성을 동일하게 취급합니다. 다음과 같이 특성을 단일 NumPy 배열로 묶습니다." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:04.952513Z", "iopub.status.busy": "2022-12-14T21:07:04.952094Z", "iopub.status.idle": "2022-12-14T21:07:04.956905Z", "shell.execute_reply": "2022-12-14T21:07:04.956316Z" }, "id": "Dp3N5McbUMwb" }, "outputs": [ { "data": { "text/plain": [ "array([[0.435, 0.335, 0.11 , ..., 0.136, 0.077, 0.097],\n", " [0.585, 0.45 , 0.125, ..., 0.354, 0.207, 0.225],\n", " [0.655, 0.51 , 0.16 , ..., 0.396, 0.282, 0.37 ],\n", " ...,\n", " [0.53 , 0.42 , 0.13 , ..., 0.374, 0.167, 0.249],\n", " [0.395, 0.315, 0.105, ..., 0.118, 0.091, 0.119],\n", " [0.45 , 0.355, 0.12 , ..., 0.115, 0.067, 0.16 ]])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abalone_features = np.array(abalone_features)\n", "abalone_features" ] }, { "cell_type": "markdown", "metadata": { "id": "1C1yFOxLOdxh" }, "source": [ "다음으로, 회귀 모델로 나이를 예측합니다. 입력 텐서가 하나만 있으므로 여기에서는 `keras.Sequential` 모델이면 충분합니다." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:04.960146Z", "iopub.status.busy": "2022-12-14T21:07:04.959605Z", "iopub.status.idle": "2022-12-14T21:07:08.596334Z", "shell.execute_reply": "2022-12-14T21:07:08.595536Z" }, "id": "d8zzNrZqOmfB" }, "outputs": [], "source": [ "abalone_model = tf.keras.Sequential([\n", " layers.Dense(64),\n", " layers.Dense(1)\n", "])\n", "\n", "abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(),\n", " optimizer = tf.keras.optimizers.Adam())" ] }, { "cell_type": "markdown", "metadata": { "id": "j6IWeP78O2wE" }, "source": [ "해당 모델을 훈련하려면 특성과 레이블을 `Model.fit`로 전달합니다." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:08.601100Z", "iopub.status.busy": "2022-12-14T21:07:08.600417Z", "iopub.status.idle": "2022-12-14T21:07:12.357459Z", "shell.execute_reply": "2022-12-14T21:07:12.356751Z" }, "id": "uZdpCD92SN3Z" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 2:14 - loss: 93.1127" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 24/104 [=====>........................] - ETA: 0s - loss: 109.7707 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 97.8226 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 87.7201" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 97/104 [==========================>...] - ETA: 0s - loss: 76.3915" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 2s 2ms/step - loss: 73.6423\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 29.1383" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 26/104 [======>.......................] - ETA: 0s - loss: 22.3848" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 50/104 [=============>................] - ETA: 0s - loss: 18.3118" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 15.4082" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 97/104 [==========================>...] - ETA: 0s - loss: 14.0302" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 13.6555\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 4.6509" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 26/104 [======>.......................] - ETA: 0s - loss: 9.3496" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 51/104 [=============>................] - ETA: 0s - loss: 8.6804" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 76/104 [====================>.........] - ETA: 0s - loss: 8.6793" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "101/104 [============================>.] - ETA: 0s - loss: 8.5348" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 8.5453\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 13.5137" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 8.5626 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 50/104 [=============>................] - ETA: 0s - loss: 8.1565" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 75/104 [====================>.........] - ETA: 0s - loss: 8.3381" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "100/104 [===========================>..] - ETA: 0s - loss: 8.1647" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 8.0819\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 5.4423" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 7.5483" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 7.8818" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 7.7514" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 97/104 [==========================>...] - ETA: 0s - loss: 7.7699" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 7.6597\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 6/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 4.7200" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 26/104 [======>.......................] - ETA: 0s - loss: 7.0763" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 50/104 [=============>................] - ETA: 0s - loss: 7.3246" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 7.3244" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 96/104 [==========================>...] - ETA: 0s - loss: 7.3536" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 7.3031\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 7/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 6.5185" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 6.8842" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 6.6916" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 74/104 [====================>.........] - ETA: 0s - loss: 6.8969" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 98/104 [===========================>..] - ETA: 0s - loss: 7.0554" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 7.0281\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 8/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 10.4254" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 26/104 [======>.......................] - ETA: 0s - loss: 6.9310 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 50/104 [=============>................] - ETA: 0s - loss: 6.8337" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 74/104 [====================>.........] - ETA: 0s - loss: 7.0151" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 99/104 [===========================>..] - ETA: 0s - loss: 6.9158" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 6.8179\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 9/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 7.6630" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 7.5286" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 7.1790" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 6.7329" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 97/104 [==========================>...] - ETA: 0s - loss: 6.6448" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 6.6587\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 10/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 5.5434" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 26/104 [======>.......................] - ETA: 0s - loss: 6.6050" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 51/104 [=============>................] - ETA: 0s - loss: 6.9054" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 75/104 [====================>.........] - ETA: 0s - loss: 6.6799" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 99/104 [===========================>..] - ETA: 0s - loss: 6.5964" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 6.5618\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abalone_model.fit(abalone_features, abalone_labels, epochs=10)" ] }, { "cell_type": "markdown", "metadata": { "id": "GapLOj1OOTQH" }, "source": [ "지금까지 CSV 데이터를 사용하여 모델을 훈련하는 가장 기본적인 방법을 보았습니다. 다음으로 숫자 열을 정규화하기 위해 전처리를 적용하는 방법을 배웁니다." ] }, { "cell_type": "markdown", "metadata": { "id": "B87Rd1SOUv02" }, "source": [ "## 기본 전처리" ] }, { "cell_type": "markdown", "metadata": { "id": "yCrB2Jd-U0Vt" }, "source": [ "모델에 대한 입력을 정규화하면 좋습니다. Keras 전처리 레이어는 이 정규화를 모델에 빌드하는 편리한 방법을 제공합니다.\n", "\n", "`tf.keras.layers.Normalization` 레이어는 각 열의 평균과 분산을 미리 계산하고 이를 사용하여 데이터를 정규화합니다.\n", "\n", "먼저 레이어를 만듭니다." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:12.361719Z", "iopub.status.busy": "2022-12-14T21:07:12.361122Z", "iopub.status.idle": "2022-12-14T21:07:12.366235Z", "shell.execute_reply": "2022-12-14T21:07:12.365550Z" }, "id": "H2WQpDU5VRk7" }, "outputs": [], "source": [ "normalize = layers.Normalization()" ] }, { "cell_type": "markdown", "metadata": { "id": "hGgEZE-7Vpt6" }, "source": [ "그런 다음 `Normalization.adapt` 메서드를 사용하여 정규화 레이어를 데이터에 맞게 조정합니다.\n", "\n", "참고: `PreprocessingLayer.adapt` 메서드와 함께 훈련 데이터만 사용하고 검증 또는 테스트 데이터는 사용하지 마세요." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:12.369660Z", "iopub.status.busy": "2022-12-14T21:07:12.369407Z", "iopub.status.idle": "2022-12-14T21:07:12.709129Z", "shell.execute_reply": "2022-12-14T21:07:12.708276Z" }, "id": "2WgOPIiOVpLg" }, "outputs": [], "source": [ "normalize.adapt(abalone_features)" ] }, { "cell_type": "markdown", "metadata": { "id": "rE6vh0byV7cE" }, "source": [ "그런 다음 모델에서 정규화 레이어를 사용합니다." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:12.713715Z", "iopub.status.busy": "2022-12-14T21:07:12.713084Z", "iopub.status.idle": "2022-12-14T21:07:15.834868Z", "shell.execute_reply": "2022-12-14T21:07:15.834086Z" }, "id": "quPcZ9dTWA9A" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 1:14 - loss: 83.3195" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 23/104 [=====>........................] - ETA: 0s - loss: 107.1227 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 46/104 [============>.................] - ETA: 0s - loss: 100.7359" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 69/104 [==================>...........] - ETA: 0s - loss: 97.4894 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 92/104 [=========================>....] - ETA: 0s - loss: 94.2089" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 1s 2ms/step - loss: 92.5604\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 77.3618" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 24/104 [=====>........................] - ETA: 0s - loss: 68.4570" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 48/104 [============>.................] - ETA: 0s - loss: 64.9630" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 71/104 [===================>..........] - ETA: 0s - loss: 60.6215" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 94/104 [==========================>...] - ETA: 0s - loss: 55.9687" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 53.8474\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 33.5274" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 27.4030" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 23.7669" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 20.4905" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 96/104 [==========================>...] - ETA: 0s - loss: 17.7557" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 17.0539\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 6.0965" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 24/104 [=====>........................] - ETA: 0s - loss: 7.2913" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 47/104 [============>.................] - ETA: 0s - loss: 6.2434" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 71/104 [===================>..........] - ETA: 0s - loss: 6.1060" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 94/104 [==========================>...] - ETA: 0s - loss: 6.0415" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 5.9795\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 6.2070" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 5.3811" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 5.2210" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 72/104 [===================>..........] - ETA: 0s - loss: 5.3657" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 96/104 [==========================>...] - ETA: 0s - loss: 5.0429" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 5.0962\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 6/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 2.9896" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 5.7223" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 48/104 [============>.................] - ETA: 0s - loss: 5.3740" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 72/104 [===================>..........] - ETA: 0s - loss: 5.0233" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 96/104 [==========================>...] - ETA: 0s - loss: 5.0526" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 5.0296\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 7/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 4.0672" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 4.5018" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 5.0191" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 72/104 [===================>..........] - ETA: 0s - loss: 5.0742" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 96/104 [==========================>...] - ETA: 0s - loss: 5.0585" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 4.9844\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 8/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 8.0486" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 25/104 [======>.......................] - ETA: 0s - loss: 5.0970" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49/104 [=============>................] - ETA: 0s - loss: 5.1916" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 73/104 [====================>.........] - ETA: 0s - loss: 4.9701" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 98/104 [===========================>..] - ETA: 0s - loss: 5.0033" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 4.9694\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 9/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 9.3212" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 24/104 [=====>........................] - ETA: 0s - loss: 4.9169" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 48/104 [============>.................] - ETA: 0s - loss: 4.7689" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 72/104 [===================>..........] - ETA: 0s - loss: 4.9059" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 95/104 [==========================>...] - ETA: 0s - loss: 4.9345" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 4.9474\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 10/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/104 [..............................] - ETA: 0s - loss: 4.1141" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 24/104 [=====>........................] - ETA: 0s - loss: 4.1990" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 48/104 [============>.................] - ETA: 0s - loss: 4.3876" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 72/104 [===================>..........] - ETA: 0s - loss: 4.7943" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 96/104 [==========================>...] - ETA: 0s - loss: 4.8873" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "104/104 [==============================] - 0s 2ms/step - loss: 4.9429\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "norm_abalone_model = tf.keras.Sequential([\n", " normalize,\n", " layers.Dense(64),\n", " layers.Dense(1)\n", "])\n", "\n", "norm_abalone_model.compile(loss = tf.keras.losses.MeanSquaredError(),\n", " optimizer = tf.keras.optimizers.Adam())\n", "\n", "norm_abalone_model.fit(abalone_features, abalone_labels, epochs=10)" ] }, { "cell_type": "markdown", "metadata": { "id": "Wuqj601Qw0Ml" }, "source": [ "## 혼합 데이터 유형\n", "\n", "The \"Titanic\" dataset contains information about the passengers on the Titanic. The nominal task on this dataset is to predict who survived.\n", "\n", "![The Titanic](images/csv/Titanic.jpg)\n", "\n", "Image [from Wikimedia](https://commons.wikimedia.org/wiki/File:RMS_Titanic_3.jpg)\n", "\n", "The raw data can easily be loaded as a Pandas `DataFrame`, but is not immediately usable as input to a TensorFlow model.\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.838651Z", "iopub.status.busy": "2022-12-14T21:07:15.837967Z", "iopub.status.idle": "2022-12-14T21:07:15.897560Z", "shell.execute_reply": "2022-12-14T21:07:15.896903Z" }, "id": "GS-dBMpuYMnz" }, "outputs": [ { "data": { "text/html": [ "
\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", " \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", "
survivedsexagen_siblings_spousesparchfareclassdeckembark_townalone
00male22.0107.2500ThirdunknownSouthamptonn
11female38.01071.2833FirstCCherbourgn
21female26.0007.9250ThirdunknownSouthamptony
31female35.01053.1000FirstCSouthamptonn
40male28.0008.4583ThirdunknownQueenstowny
\n", "
" ], "text/plain": [ " survived sex age n_siblings_spouses parch fare class deck \\\n", "0 0 male 22.0 1 0 7.2500 Third unknown \n", "1 1 female 38.0 1 0 71.2833 First C \n", "2 1 female 26.0 0 0 7.9250 Third unknown \n", "3 1 female 35.0 1 0 53.1000 First C \n", "4 0 male 28.0 0 0 8.4583 Third unknown \n", "\n", " embark_town alone \n", "0 Southampton n \n", "1 Cherbourg n \n", "2 Southampton y \n", "3 Southampton n \n", "4 Queenstown y " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "titanic = pd.read_csv(\"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")\n", "titanic.head()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.900903Z", "iopub.status.busy": "2022-12-14T21:07:15.900636Z", "iopub.status.idle": "2022-12-14T21:07:15.904623Z", "shell.execute_reply": "2022-12-14T21:07:15.903975Z" }, "id": "D8rCGIK1ZzKx" }, "outputs": [], "source": [ "titanic_features = titanic.copy()\n", "titanic_labels = titanic_features.pop('survived')" ] }, { "cell_type": "markdown", "metadata": { "id": "urHOwpCDYtcI" }, "source": [ "데이터 유형과 범위가 다르기 때문에 단순히 특성을 NumPy 배열에 쌓아서 `keras.Sequential` 모델로 전달할 수 없습니다. 각 열을 개별적으로 처리해야 합니다.\n", "\n", "한 가지 옵션으로 데이터를 오프라인으로 전처리(원하는 도구 사용)하여 범주형 열을 숫자 열로 변환한 다음 처리된 출력을 TensorFlow 모델에 전달할 수 있습니다. 이 접근 방식의 단점은 모델을 저장하고 내보내는 경우 전처리가 함께 저장되지 않는다는 것입니다. Keras 전처리 레이어는 모델의 일부이기 때문에 이 문제를 피할 수 있습니다.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "Bta4Sx0Zau5v" }, "source": [ "이 예제에서는 [Keras 함수형 API](https://www.tensorflow.org/guide/keras/functional)를 사용하여 전처리 로직을 구현하는 모델을 빌드합니다. [하위 클래스화](https://www.tensorflow.org/guide/keras/custom_layers_and_models)하여 같은 작업을 수행할 수도 있습니다.\n", "\n", "함수형 API는 \"기호화된\" 텐서에서 작동합니다. 정상적인 \"즉시(eager)\" 텐서에는 값이 있습니다. 대조적으로 이러한 \"기호화된\" 텐서에는 값이 없습니다. 대신에 실행되는 작업을 추적하고 나중에 실행할 수 있는 계산 표현을 작성합니다. 다음은 간단한 예제입니다." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.908030Z", "iopub.status.busy": "2022-12-14T21:07:15.907678Z", "iopub.status.idle": "2022-12-14T21:07:15.921120Z", "shell.execute_reply": "2022-12-14T21:07:15.920516Z" }, "id": "730F16_97D-3" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a symbolic input\n", "input = tf.keras.Input(shape=(), dtype=tf.float32)\n", "\n", "# Perform a calculation using the input\n", "result = 2*input + 1\n", "\n", "# the result doesn't have a value\n", "result" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.924549Z", "iopub.status.busy": "2022-12-14T21:07:15.923957Z", "iopub.status.idle": "2022-12-14T21:07:15.930025Z", "shell.execute_reply": "2022-12-14T21:07:15.929443Z" }, "id": "RtcNXWB18kMJ" }, "outputs": [], "source": [ "calc = tf.keras.Model(inputs=input, outputs=result)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.933450Z", "iopub.status.busy": "2022-12-14T21:07:15.932907Z", "iopub.status.idle": "2022-12-14T21:07:15.941069Z", "shell.execute_reply": "2022-12-14T21:07:15.940477Z" }, "id": "fUGQOUqZ8sa-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.0\n", "5.0\n" ] } ], "source": [ "print(calc(1).numpy())\n", "print(calc(2).numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "rNS9lT7f6_U2" }, "source": [ "전처리 모델을 빌드하려면 먼저 CSV 열의 이름 및 데이터 유형과 일치하는 기호화된 `tf.keras.Input` 객체 세트를 빌드합니다." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.944427Z", "iopub.status.busy": "2022-12-14T21:07:15.943826Z", "iopub.status.idle": "2022-12-14T21:07:15.956910Z", "shell.execute_reply": "2022-12-14T21:07:15.956272Z" }, "id": "5WODe_1da3yw" }, "outputs": [ { "data": { "text/plain": [ "{'sex': ,\n", " 'age': ,\n", " 'n_siblings_spouses': ,\n", " 'parch': ,\n", " 'fare': ,\n", " 'class': ,\n", " 'deck': ,\n", " 'embark_town': ,\n", " 'alone': }" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "inputs = {}\n", "\n", "for name, column in titanic_features.items():\n", " dtype = column.dtype\n", " if dtype == object:\n", " dtype = tf.string\n", " else:\n", " dtype = tf.float32\n", "\n", " inputs[name] = tf.keras.Input(shape=(1,), name=name, dtype=dtype)\n", "\n", "inputs" ] }, { "cell_type": "markdown", "metadata": { "id": "aaheJFmymq8l" }, "source": [ "전처리 논리의 첫 번째 단계는 숫자 입력을 함께 연결하고 이를 정규화 레이어를 통해 실행하는 것입니다." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:15.959896Z", "iopub.status.busy": "2022-12-14T21:07:15.959675Z", "iopub.status.idle": "2022-12-14T21:07:16.186717Z", "shell.execute_reply": "2022-12-14T21:07:16.185945Z" }, "id": "wPRC_E6rkp8D" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "numeric_inputs = {name:input for name,input in inputs.items()\n", " if input.dtype==tf.float32}\n", "\n", "x = layers.Concatenate()(list(numeric_inputs.values()))\n", "norm = layers.Normalization()\n", "norm.adapt(np.array(titanic[numeric_inputs.keys()]))\n", "all_numeric_inputs = norm(x)\n", "\n", "all_numeric_inputs" ] }, { "cell_type": "markdown", "metadata": { "id": "-JoR45Uj712l" }, "source": [ "나중에 연결할 수 있도록 모든 기호화된 전처리 결과를 수집합니다." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.190577Z", "iopub.status.busy": "2022-12-14T21:07:16.190026Z", "iopub.status.idle": "2022-12-14T21:07:16.193778Z", "shell.execute_reply": "2022-12-14T21:07:16.193103Z" }, "id": "M7jIJw5XntdN" }, "outputs": [], "source": [ "preprocessed_inputs = [all_numeric_inputs]" ] }, { "cell_type": "markdown", "metadata": { "id": "r0Hryylyosfm" }, "source": [ "문자열 입력의 경우 `tf.keras.layers.StringLookup` 함수를 사용하여 문자열로부터 어휘의 정수 인덱스로 매핑합니다. 그런 다음 `tf.keras.layers.CategoryEncoding`을 사용하여 인덱스를 모델에 적합한 `float32` 데이터로 변환합니다.\n", "\n", "`tf.keras.layers.CategoryEncoding` 레이어의 기본 설정은 각 입력에 대해 원-핫 벡터를 생성하는 것입니다. `tf.keras.layers.Embedding`도 작동합니다. 이 주제에 대한 자세한 내용은 [전처리 레이어 작업](https://www.tensorflow.org/guide/keras/preprocessing_layers) 가이드 및 [Keras 전처리 레이어를 사용하여 구조화된 데이터 분류](../structured_data/preprocessing_layers.ipynb) 튜토리얼을 확인하세요." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.197228Z", "iopub.status.busy": "2022-12-14T21:07:16.196789Z", "iopub.status.idle": "2022-12-14T21:07:16.324988Z", "shell.execute_reply": "2022-12-14T21:07:16.324211Z" }, "id": "79fi1Cgan2YV" }, "outputs": [], "source": [ "for name, input in inputs.items():\n", " if input.dtype == tf.float32:\n", " continue\n", " \n", " lookup = layers.StringLookup(vocabulary=np.unique(titanic_features[name]))\n", " one_hot = layers.CategoryEncoding(num_tokens=lookup.vocabulary_size())\n", "\n", " x = lookup(input)\n", " x = one_hot(x)\n", " preprocessed_inputs.append(x)" ] }, { "cell_type": "markdown", "metadata": { "id": "Wnhv0T7itnc7" }, "source": [ "`inputs` 및 `preprocessed_inputs` 모음을 사용하여 전처리된 모든 입력을 함께 연결하고 전처리를 처리하는 모델을 빌드할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.329343Z", "iopub.status.busy": "2022-12-14T21:07:16.328769Z", "iopub.status.idle": "2022-12-14T21:07:16.580703Z", "shell.execute_reply": "2022-12-14T21:07:16.579775Z" }, "id": "XJRzUTe8ukXc" }, "outputs": [ { "data": { "image/png": "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HDly8+bNFRUVcsciJ/MfZhf/VaLt+MsGAAAAwHbYWdXM/H4Wabeurm7fvn15eXmfffbZ5s2bDx48KAhCWlra1q1bS0tLT506lZ+ff+zYsdzc3MWLFwuCkJ6evnr1aqkFd3d3o9Ho5uYm7aalpa1evTo0NFR63EytVlt9iC2wZMmSPXv27N+//8aNG8HBwWFhYVVVVS0aXVfIUoe6c+fOmTNn4uLi+vTpM378+F27dv3yyy9yByUD8x9mF/9Vou34ywYAAADAdthT1axRBoMhNjbWw8Nj/PjxgYGBFy5cMH1UU1OTlJTk6en58MMPx8XF7dix49atWy1tf9euXV5ez2dH5wAAIABJREFUXt9//327Rt1WWq1206ZNb7/99vDhwz09PdetW6fX69PS0lrRVCfOknXcuXOnpqbmm2++mTt3bq9evSZOnJiZmVlTUyN3XHLqmr9KtB1/2QAAAADYFCe5A2grJyenfv36Sdsqlcr830U+Pj7u7u7SdnBwcG1t7ZUrV0aMGNGi9o2/aq+A20VhYaHBYAgJCZF2XV1d1Wq19ChTS9lmlpKSktqrqY5z9+5d893bt28LgvDVV1/94x//MBqNgwYNGj58eH19vYOD3demW6pr/irRdp3+LxsAAAAA+2L3VTNHR0fTtiiK5h/V19ebthv8s8d812AwWGg/IiIiIiKirVG2t0b/FWcafvNHJ9hqlrRabTu21kH4t3RTuuavEm3X6f+yAQAAALAvdl81s6CkpKSystLDw0MQhIKCAoVCIS1V0717d9PbD2/evKnX602XNPgXvs0KCgpycnK6ePGitKy1Tqe7evXq888/L7R8dLaZpcTExI7uou0++eQT893u3bvX1NSMGTMmJibm6aeffueddwRB6II3mllmm/MNNqLT/2UDAAAAYF868z/p3dzcli9fXlFRkZ+fn5ycPHv27B49egiCMGzYsKKioiNHjlRWViYnJyuVStMl3t7excXF1dXVUVFRqampgq2ua6NSqWJiYtauXZufn6/VapcuXapUKqOjo4UWjk7o1Fmyjm7duimVyt/+9rebN28uLy//8ssvZ8yYYZ4umGO+wQL+sgEAAACwLUaraJeO4uPjTWFfunRp48aNpl2tVhsQECBtv/LKK0ajcevWrf3798/MzOzfv7+rq+uLL754+/ZtU1MLFizw8PAYMGBATk6O9A61+Ph4o9FYWloaGhrq4uIyZsyY8vJyo9G4e/duT0/Pq1evtj1+YzvlQaLT6V5//XVvb29nZ+fx48efO3fO9FHzR9fps9Shhg0bNmLEiLS0NCkJDcTHx0vp6vTMf5jz58+3u1+l7es6c8nYqf+y2bguNc0AAACAZhKNVlmbSRSt1JHJtm3bEhISfvjhB2t2el/Wz4NlZKktqqqqevbs2dSnGo3G9F9IbHO+2T7mUksx01qBaQYAAADcqzM/oQl0KAslMwAAAAAAYO8659sAoqOjN2/eLAiCKIparVZaEBoNkCVYE/MN1sFMAwAAANBeOue9ZmlpaaZnUPknU1PIEqyJ+QbrYKYBAAAAaC+ds2oGAAAAAAAAtAVVMwAA0KloNBoR6Bp4iQcAAB2qc65rBgAAurL4+HiqCbLj3awdjdwCANDRrFc1E0XRan3ZMvLQdaxcuXLlypVyR4FOgrmEjhYfHy93CAAAAIBtsV7VzGg0Wq0veyGKImm5V6cpLHKnA2B3uuytMV1wyAAAAMB9sa4ZAAAAAAAA0BBVMwAAAGuLjo4WRdHPz0/a3bBhw7Rp09qr8fZtrYvo0G+kIxoEAABWQNUMAADA2tLS0rZu3WraNRqNrV60ISEhYfTo0eZH2tLafaWkpCgUiitXrrSlkaysLOkVkFOnTjUP1d3dXTo+c+bMNkfaMu34jQhW/1IAAEAHsYmq2ahRo6T/Q0pPTzcd3LVr1+7du+ULqgXq6+ujoqLKysrMD3p5eUmDOnjwYOuatfe0CI1lpu1p6Rw65Zd7XwzQpnTBAbbX3x97zwNsU1xcXHZ2tm22ZqLT6WbNmpWRkWEwGNrYVHh4uNH4/9m717gmzvR//PcACcQgJshBERQth6BAq7KiQtfFBt1WUdqK7VKl+NuCUG2lYIXVugTFFaTQYrGCdhWsu7ZiCxa32oKtVVRs8YAHoHhoq1VRlICiJhDI/8H8N98sJCFAkknC5/2AVzKTmbnu656ZhCuTe+Q8Hu/AgQPKdztpa2tbtmxZeXn57t27B7iJAdJ5DvXUKQAAAKBXRlE1I4SsWbNGLpdHR0fTT3fs2FFSUhIREWGEX0WSHt+yWlhYLFmy5Pnnn5dKpYrX3Lt37+HDhwPckEmnhajKjE7SYh7UdS4xym/gtelczdBAggbqk8HOP0Z+HiaEZGdnUxR15MgR+mlfO9rsiUQiiqJsbGwOHz7s4eHB4/Hi4+MVPdje3p6YmOjs7MzhcEJCQs6fP99tEYFAYGFhER4erphYUVExduxYe3v7TZs2NTc3//nPf7a1tQ0NDVVUKuvr68PDw/l8vpub26pVqzo6OjRERT+tqqqi/teLL76oblVxcXFr1649deoU/corV650W5s27eqZCpUuXry4ePHizMzMgXcEzcnJacGCBevWrVNXTtJHjxAtOmUgPUK06BRd9QgAAADondwgNG9o8uTJdAWBdvv27WHDht24cUMxhcfjEUJSU1OVl6K/itR1pL148uTJ4sWLp0+fTgi5fPmy8qzFixf//e9/V55C/3umIcjBkBZ5j8wMMC2mIjU1tVvXKOu1c+VG07996lx10EAFNFDndHv+0XzkGvN5mHbu3LkpU6YQQr7//nvl6b12tOaGmxzNzSkrK7OyskpKShKLxUeOHKEo6ttvv6VnvfXWW+7u7mfOnLl///7y5csdHR1bWlroRSwtLZcuXdrU1FRSUjJ//nzFepKTk1taWoqLiwkhr7766qVLl27evOnl5fW3v/2NXuesWbMOHDggkUgaGhomT56ckZGhiGT79u1jxoxRRGVtbU0/PnnypOI94rvvvhs6dGh9fb2GVa1fvz4wMLBbGxVr09wudanQ4NixYyoPt5563a+8vb3b2tqefvppOzu7n3/+mZ6ofATpo0c0ZFJXPSLvrVN01SNmduQCAAAYIWO51kzZ3r17/fz8XF1dFVMG/lWkuu+TnZyclBfplYZvWRcsWFBYWCjX21eCJpoWov/MmIGenUuMpn910rloIBpo5A3UkjGfhwkhEokkKSnp448/7jkL5+FuZDJZQkICj8ebMWOGQCC4cOECIUQsFm/dunX16tUTJ06kr1SSSqX5+fn0Ip2dnWvWrHFwcAgPDy8tLVWs56233ho2bNiCBQvs7OwEAsH48eNdXFzmzJlz7tw5+jXffPPNnDlzrK2tPT09X3vttUOHDvUa3tSpU9PT0wkhzc3NUVFR2dnZ3t7e/VtVr+1SmQpD4nK5paWlbDY7PDy829WgeuoR0vdMDqoeAQAAAGXGWDWrqKjw8fFRnkIP/+Tv779o0aKGhoaei6xcubKkpOTQoUM3b9709fUVCoWtra0ikaisrKyzs/PgwYPV1dX79+8vKChQDGeTnJz8ww8/nDhxorGxcdKkSXPmzJFIJL3GFhAQEBoaqnLW+PHjr1+/Xl9f3/cWa8VE00L0nxkz0LNzidH0r046Fw1EA428gVoy5vMwISQlJSUlJcXZ2bnnLJyHu7GyslJUP/l8/oMHDwgh9fX1MpnMz8+Pns7hcDw8PBRVSxaL5ebm1nM9o0aNoh8PHTpUcftFOzs7ep2EkPLy8ilTpnC5XIqiEhMT+zTGXGxs7B/+8IeYmJiBrEpzu1SmwsDc3d337dt3+fLl6Oho5dqunnqEDKBTBkmPAAAAgIIxVs1u3rzp4ODQbWK/v4pU933yli1b1q1b5+HhMWzYsIyMjHv37u3bt28gYdMx37p1ayAr0cBE00L0nxkzoLJziSn0r5adiwaigUbeQC0Z83n40KFDdnZ2QqFQ5Vxt8tDZ2dnrVsyGpaWl4jFFUfQDldfiKeZaWKj4yKS8np5PCSF3794NDw+fOXPm7du35XL5Rx99pP0Vf//85z9PnjypuKtjv1eluV0qU2F4M2bMyM3N/fLLLzdu3KiYqI8eIQPI5KDqEQAAAKAZY9VMLBazWKye0/v3VaS675M7Ojrmzp1Lj9LKZrMlEkldXd1Awmaz2YSQ5ubmgaxEAxNNC9F/ZsyAus4lRt+/WnYuGogGGnkDtWS05+GmpqYdO3akpqaqe4E2edi9e/ewYcN8fX1feOGFmJiYdevWFRYWlpeX19XVPX78WHMA5sHHx8fKyurixYv0U4lEcvXqVUX39U9tbe3jx49jYmLs7OwIIe3t7VouePny5XfeeWfXrl3Dhw/vdVWaayv6aJc+vPnmmzExMWvXrj169Cg9RU+R969T+tQjRGOnmEqPAAAAACHEiukAVODz+SrvMEX++1XksmXLtP8qUsP3yVVVVYGBgboKm/60ZG9vr6sVdmOiaSH6z4wZ0NC5xLj7V8vORQPRQJrRNlBLRnsezsnJKS4upoc/p4WEhBBCfvrpp4CAAKJdHl5//fXk5OTbt29fu3bt1q1bt2/fPnnyJP3g8uXL7e3tLi4u48aNGzlypPIDT09PumRgBvh8fnx8/MaNG//whz+MHj1aJBKx2ey4uLiBrNPb25vNZufl5a1bt+7OnTtFRUXaLNXR0REZGbl06dLnnnuOniIUCj/99FN1q3J0dGxsbGxra3vnnXeefvrp5cuX67tderJly5a6urrKykr6qZ4i70en9LVHiMZOMaEeAQAAAGO81mzUqFEaBobQyVeRPj4+LBZL+yGWtUHH7OLiosN1KjPRtBD9Z8YMaO5cYsT9q2XnooFooJE3UEtGex7euHGj4i4/N27cIP+9hyZdMiNa54HD4YwbN04oFEZFRSUnJxcUFJSVlVVXV7e2tjY3N5eXlycnJwuFQj6ff/r06c2bN0dFRbm6utrb20+YMCE0NHTp0qUikWjbtm0VFRWXLl1qa2vrUyv6RC6X92/9eXl5YWFhUqmUoqiWlhaBQHD8+PG0tLTo6GhCSFZW1vz580NDQ0eOHFlTU1NeXj5s2DDlRfLy8lSux8rK6ubNm4sXL37//ffj4uLS0tKOHz/u6uo6cuTITz/99MCBA6NGjYqLi5s5c+alS5dsbW0JIXFxcTExMb/99htFUQkJCYq11dfX79q1q7q6+v3336f+69dff9WwqpdeemnEiBGOjo61tbWRkZEikUh5bdq0q2cqVJLJZBRFPfvss4QQT09PlT/c1lJpaSlFUT///DNFUYpB/Vgs1hdffKE8WpnOe4QQoi6TOuyRXjtFVz0CAAAAeqerm3FqpnlDkydPVtzPWy6X5+bmPvvss8ov8Pb2Vn7a3t4eHBxMCFG+Mfm4cePOnTvX3Nz89ttvK9/AW/nO60FBQYr7cyckJIwZM6aqqkoikfz000+enp4nTpygZx08eJDFYrW3t6sLWOU91/fv3z969Oiuri7FFHqAG0WQPQ2GtMh7ZGaAaTEVmm8G32vnyg3bvzrpXA0rQQPRQGNooFyL84/mI9f4z8Py/62aqctDXxuuWXNz88WLF8vLywsKClJTU2NjY4VC4fjx47lcLp/PHz9+vFAojI2NTU1NLSgoKC8vv3jxYltbW/+2pdDU1DRs2LD33nuvubm559yBNAd0CB2hb8gwAACAvhlj1ez27ds8Hu/333+Xy+UlJSWKAp/y/zl37txxc3NTTJFIJO+8846jo6O1tfWMGTPOnTsnl8s/+ugjxbJisZi+Rzgh5PXXX5fL5VKpNCkpycnJycbGxt/f/7PPPlOs/O233160aJHKULv9Nmf48OGKWVFRUX//+9+VX6zbqpmJpqVnZlA1k2vsXDkT/auTztWwEjQQDTSGBsoHXDUz5vMwbcaMGYo1jxo1Sl0e+trwflNZUBs3bhyLxeLz+ZMnT547d25sbGxGRkZRUVF5efnVq1c11wQVzpw5w+VybWxsOBxOQkLCnTt3DNAc6Ct0hL4hwwAAAPpmLFUz+iP+zp076Sn//Oc/Fy5c2NnZaYjg/tdPP/1E3wetT0sdP348ICBAIpEopigGix1I1czU0yLvkZmBp8VU9Fo1M7PO7XUlaKD+oIHq9OP80+u/oGaQB5UM/793c3NzdXX1V199VVBQkJycvHjxYrqgZmVlpa6g1tHRoVh8//79w4YNozvU2traxsbm9ddfv379OlPNMTNElX6sBx2hb8gwAACAvlFyre+APhAU1ecN/fvf/7a0tHzllVf0FJIOdXV10Z/s+zrAh3mnhfQ3M/1IixESiUSKv1oy+85FA40KGqiSNkeuWeahH6csPZHJZI2NjdevX//9999///13xYMbN27cu3fP2dl59OjRbm5ubW1thw8ffvLkiWJBNpttaWk5Z86c9PT0PXv2EONoziBnPPuVuUKGAQAA9M14q2aDAdKiknmkBR9kAUzRoD1yTaLhHR0dt27dunHjxo0bN3bv3n3w4MGebxZWVlZWVlZjxox57rnntmzZwkicoGAS+5VJQ4YBAAD0zYrpAAAAAAB6x2KxxowZM2bMGELI559/3rNkZmNjw2azJRJJa2vrhQsXmpqaHB0dmYgUAAAAAMwEqmYAAABgYn777Tf6AZfL7erqYrPZAQEBc+bMmT59+qRJkzZs2EAIQckMAAAAAAYIVTMAAAAwMS0tLWPHjp05c2ZISEhQUJC7u3u3F6SlpaWlpTERGnSHjtCr1NRUpkMAAAAwZ6iaAQwKv/zyy/jx43k8nqOj46hRo+hfObm4uDg5Obm6ujo5OTk5OVEUxXSYAABauXjxIpfL1fCC1NRUDPakbxhUi3FIPgAAgL4ZrmqGf8hVQlrMmBFe6dDY2NjY2HjhwgWmAwEwasZ25BqGaV2xorlkBgAAAACgEwaqmpnBLREB+kQkEhnbN8AvvfRSSUlJz+mWlpbW1tbr169PSEiwsLAwfGAAAAAAAAAARgi/0AQYFH7++Wcej8flch89eqQ8fciQIQKB4LPPPvP09GQqNgAAAAAAAAAjhOtKAMyTXC6/dOnSxx9//Oqrr7q4uMyePVssFitf9clisWxtbbOzs6urq1EyAwDQiQ8++GDevHlMRwEAAAAAuoGqGYBZuXbt2rZt26KiokaPHh0aGnrkyJGZM2eWl5f/+uuvJSUlbDabfpmtre306dNra2vj4uIwuB4AgK7I5XL9jUqRnp4+depUPa3c7Okqe+gFAACAQQW/0AQwbZ2dnfX19cePH6+oqPjuu++GDRsWFBQUHBy8bt06d3f3bi8ODg4+ePAgl8vNz8//y1/+wkS8AADmLDExMTExkekoAAAAAEA3cK0ZgOnp7Ow8ffp0bm7uwoULHR0d582bd/r06blz5549e/bq1au7du2KjY3tWTIjhMyZM2fevHlXr15FyQwAQOdEIhFFUTY2NsqPDx8+7OHhwePx4uPj6cvQ6It83d3di4qK3NzchgwZEhkZ2dbWRgiJjo6mKIq+lKmtrY2iKIqiSktL6aXWrl176tQpeuKVK1cYbSvD2tvbExMTnZ2dORxOSEjI+fPnSR+zh14AAAAAbaBqBmAaZDLZ6dOnMzMzw8LCnJycoqKiamtrIyIiGhoarl69WlBQEBUV5ebmpnklb7zxxpdffung4GCYmAEABhWRSFRWVqb8uLOz8+DBg9XV1fv37y8oKKioqCCE5Ofnb9++vamp6ccff6ypqTlx4kRlZWVSUhIhpLCwcP369fQabG1t5XI5l8uln+bn569fvz4wMJD+EaiHhwcTTTQWK1euLCkpOXTo0M2bN319fYVCYWtra5+yh14AAAAAbaBqBmC8elbKrl27FhUV1dDQcOnSpYKCgoiIiD6VwKys8KNsAADDkclkCQkJPB5vxowZAoHgwoULilnt7e2ZmZn29vbPPPNMYmLizp07Hzx40Nf179mzx8HB4ZdfftFp1MZOLBZv3bp19erVEydOtLe337Rpk1Qqzc/P78eq0AsAAACgGf6FBjAujx8/PnPmDD1OWVVVlbe3d1BQUFRU1K5du/h8PtPRAQBAH1hZWbm6utKP+Xy+ckXG2dnZ1taWfuzr69vR0XHlypVJkyb1af3y/9JVwCahvr5eJpP5+fnRTzkcjoeHB/0jzb5CLwAAAIBmqJoBMO/Ro0cnT56srKw8fvz4yZMnBQKBUCh8++239+3bN2zYMKajAwCAfrK0tFQ87nbD4q6uLsXjbgUX5acymUzD+iMjIyMjIwcapalRWZ9SpFf77BH0AgAAAPQGVTMAZrS1tVVVVVVUVFRWVl68eNHX1zc4ODg5OTkoKIjD4TAdHQAA6Nfdu3dbWlp4PB4hpLa2lsVi0YNkDR06tLW1lX7N7du3pVKpYpFudbdBy8fHx8rK6uLFi/SA/RKJ5OrVqwsXLiR9zx56AQAAADTDuGYAhvPgwYOKioqUlJSAgAAXFxeRSEQIEYlEjY2NlZWVGRkZQqEQJTMAgMGAy+WuWbOmubm5pqYmJydnyZIldnZ2hBB/f/+GhoZjx461tLTk5OSw2WzFIo6Ojo2NjW1tbTExMXl5eWSwjqjF5/Pj4+M3btxYU1MjFouTk5PZbHZcXBzpY/YIegEAAAB6g6oZgH7dvXu3rKyMrpS5urpmZmba2NhkZGQ0NTUpKmU2NjZMhwkAAAMlEonCwsKkUilFUcuXL1c8bmlpEQgEx48fT0tLi46Opl/M5/NDQkImTZo0bdq06dOnZ2dn09NDQkKWLVs2b968SZMmzZ49m8Vivfjii/S3LC+99NKIESMcHR1ra2vpnwRaWloOzhG1srKy5s+fHxoaOnLkyJqamvLycnpAgz5lj6AXAAAAoDcU3uMBdK6xsfHYsWP0OGWXL1+eMmWKUCgMCgoKDAxksVhMRwcAYOYUV/IyHId6n3zySXp6+q+//sp0IANi/HnWzAx6wdS7AAAAwPhhXDMA3bh16xZ948vKysp79+5NmTIlODi4oKBg4sSJFha4qBMAAAAAAADAxKBqBtB/ikpZRUXFo0eP/vCHPwQHB8fGxk6aNAmjBQMAgEpxcXEFBQWEEIqixGIxPRQ9GBh6AQAAALSBqhlA31y7do3+6eU333zT3t4eHBwcFBSEShkAAGgpPz8/Pz+f6SgGO/QCAAAAaANVM4DeXbt2jf7p5ZEjR2QyWXBwsFAofPvttydMmMB0aAAAAAAAAACgFwaqmuEaHOgTxm9S0dXVVVdXR//68vvvv7ezswsKCgoODk5LSxs7diyzsQEAAAAAAACAARjuWjPG6yC6QlG48ah+MVVj7ezsrK+vpytlhw8f5vF4QUFBQqEwKytrzJgxjIQEAAAAAAAAAEwxUAHInCpN5tQW42TIDMtkspqaGnqcsoqKCj6fLxQKg4KCZs6c6erqapgYAABAt0QiUVpaGtNRABhCamqqSCRiOgoAAACzhXHNYNChK2X0OGXHjx8fOXJkcHBwRETExx9/7ODgwHR0AACgAyglGBidbeTcwJBwAAAAfUPVDAaFJ0+enD59mr6grKqqytvbOygoKCoqqqioyN7enunoAAAAAAAAAMDomEzVbOXKlUVFRffu3SOEdHR0WFmZTOTAlEePHp09e5aulJ08eVIgEAQFBcXGxhYXF/N4PKajAwAAAAAAAACjZsF0AFo5depUTk7OsWPH5HK5XC433ZJZZWUl9V/BwcH62ER6evrUqVMNuUWj0tbWVlFRIRKJQkNDnZ2dExISxGLx22+/fevWrerq6tzc3IiICJTMAAAAAAAAAKBXplE1a2pqYrPZAoGA6UAGKjg4WC6XDx8+PCsrq7Ky0iy3aHgPHz6sqKhISUkJDg52dXUViUQSiSQ5OfnevXvV1dUZGRlhYWF2dnZMhwkAAOZjz549n3/+OdNRaKWrqysmJoa+Wt+kmVDOiRmlHQAAYJAzgaqZSCQKCwuTSqX0BVOEkPr6+vDwcD6f7+bmtmrVqo6ODsUrKYqysbE5fPiwQCCwsLAIDw9vb29PTEx0cnLicDghISHnz59ntDX/QzlgDw8PHo8XHx9P3z4yLi6Ooih3d/eioiI3N7chQ4ZERka2tbURQqKjoymKoi8oa2tro9NSWlpKL7V27dpTp07RE69cuaI5AJWZVKyToqgDBw4QQjw8POhgCCEq86ky83pNXVNTU1lZWUpKSkBAwKhRozIzM21sbEQi0Z07dyorKzMyMoRCoY2NjV5jAACAwWnHjh0lJSURERGlpaX022VYWJjy3Z9tbW3p6YsWLTJ8eNnZ2RRFHTlyhH5qYWGxZMmS559/XiqVGj4YXTHynBMzTTsAAACYRtWsrKzM2tqa/nkmIWTFihUxMTGNjY3ffffdd999l5OTo/xKmUxWXFxcWVn55ZdfEkKSk5N/+OGHEydONDY2Tpo0ac6cORKJhMn2KKED7uzsPHjwYHV19f79+wsKCioqKggh+fn527dvb2pq+vHHH2tqak6cOFFZWZmUlEQIKSwsXL9+Pb0GW1tbuVzO5XLpp/n5+evXrw8MDKRz5eHhoTkAlZm0tbVtbm62trYuLi6eO3cuIeTSpUuTJ0/+5ZdfiJp8qsy8zt25c0dRKfPw8Ni8ebONjU1GRsa9e/fKy8tFIpFQKLS2ttbHpgEAAGiNjY2JiYk5OTn0V0RyuZzH4x04cCAtLU3xmra2tmXLlpWXl+/evdvA4dXU1Ozdu7fbxOnTp/v4+PzjH/8wcDC6YuQ5J2aadgAAACAmUTXr6ZtvvpkzZ461tbWnp+drr7126NAh5bmdnZ1r1qxxcHAIDw/fuXPnli1b1q1b5+HhMWzYMLrCsm/fPqYiV0kmkyUkJPB4vBkzZggEggsXLihmtbe3Z2Zm2tvbP/PMM4mJiTt37nzw4IEON60uk3w+f+7cuTt27KCflpaWzp07l6IosVisIZ/KmaevfRu427dvFxcXr1ixIiAgwMvLa/PmzXw+/8MPP1SulLHZbJ1sCwAAoFd79+718/NzdXVVTHFyclqwYMG6devKyspULkJfpu3s7KzuMu1u15sTNVd290oikSQlJX388cc9Zy1YsKCwsFD54iwToqucE6QdAAAA+sgkq2bl5eVTpkzhcrkURSUmJnYbM4LFYrm5udGP6+vrOzo66IoPRVFsNlsikdTV1TERtVpWVlaKD4J8Pl+5Lubs7Gxra0s/9vX17ejo6PVHl32iIZNRUVHffvvtzZs3CSE7d+6MiooiveVTOfMDVFRUtGTJkqeeeuqZZ54YQ9SkAAAgAElEQVTZu3evp6fnzp07W1paysvLk5OTg4ODWSyWTjYEAADQJxUVFT4+PspTKIoqLCz09/dftGhRQ0NDz0VWrlxZUlJy6NChmzdv+vr6CoXC1tZWDdebk/5eKZ+SkpKSkuLs7Nxz1vjx469fv15fX9+vRjNMVzknGi/zJ0g7AAAA9GB6VbO7d++Gh4fPnDnz9u3bcrn8o48+6vYNnoXF/zWKnlVVVSVXsmHDBkMHrZGlpaXiMT1wm0JXV5ficbdmKj+VyWT92K7mTD7//PN8Pr+oqOjGjRtSqXTcuHGkt3wqZ36Avvnmm8DAwAMHDty5c6e4uHj58uV+fn7dkgMAAGB4N2/edHBw6DaRy+WWlpay2ezw8PCHDx8qzxKLxVu3bl29evXEiRPt7e03bdoklUrz8/PpuSqvN9d8Zbc6hw4dsrOzEwqFKufSMd+6dat/rWaWbnNOkHYAAADQmulVzWprax8/fhwTE0PfFbG9vV3Di318fFgsllHdAaBP7t6929LSQj+ura1lsVj0UGVDhw6lvzIlhNy+fVt5oFktS0sCgUBzJlks1quvvlpYWFhYWKgYWNdg+fz3v/8dFxfX7YtlAAAAxonFYpXXO7u7u+/bt+/y5cvR0dHK30LV19fLZDI/Pz/6KYfD8fDwULyTqrzevB9Xyjc1Ne3YsSM1NVXdC+jRDJqbm/vWWuOg25wTpB0AAAC0ZnpVM29vbzabnZeX9/DhwytXrhQVFWl4MZ/PX7Zs2YYNG06dOiWVSqurq728vE6ePGmwaAeIy+WuWbOmubm5pqYmJydnyZIldIXL39+/oaHh2LFjLS0tOTk5ygN7OTo6NjY2trW1xcTE5OXlaVh5r5lcvHjx5cuX8/LyIiIi6Cmmnk8AAIAB4vP5ipt3dzNjxozc3Nwvv/xy48aNiokqx7RSfMWl8nrzflwpn5OTU1xcbGVlRVEUPVpCSEgIRVHV1dX0C+jvxuzt7bVuqBHRbc4J0g4AAABaM4GqmUgkCgsLk0qlFEUtX7585MiRn3766YEDB0aNGhUXFzdz5sxLly7Rg3/l5eUpXqkoGGVmZi5YsGDevHk8Hu+vf/3r+vXrp02bxlRbKisrKYq6f//+u+++GxwcrBxwS0uLQCA4fvx4WlpadHQ0/Xo+nx8SEjJp0qRp06ZNnz49Ozubnh4SErJs2bJ58+ZNmjRp9uzZLBbrxRdfFIlEhJCXXnppxIgRjo6OtbW1kZGRyluklPz6668aMkmbMmWKQCAQCoV0qY6mMp8qMw8AAGB+Ro0a1W1AVWVvvvlmTEzM2rVrjx49Sk/x8fGxsrK6ePEi/VQikVy9elVxGZRK/biye+PGjYpCz40bNwgh33//vVwuDwgIoF9Ax+zi4qL9Oo2HAXJOkHYAAABQSW4QBtuQARisLdu3bx8zZoxhtqVOXFzcN998Y+CNmtPeAgAAhpeampqamqqnlefm5j777LPKU7y9vZWftre3BwcHE0LKy8vpKW+99da4cePOnTvX3Nz89ttvOzo6trS0yOXysrIya2trxYJBQUGKsBMSEsaMGVNVVSWRSH766SdPT88TJ07I5fKDBw+yWKz29nYNESqXbxT2798/evTorq6u/ra7F6aScznSDgAAAH1hAteaAVNaW1svXLigboBbAACAQWjhwoUXLlyg7zFdWlpKUdTPP/9MUZTiPowsFuuLL75Qvql0VlbW/PnzQ0NDR44cWVNTU15ePmzYMM3Xm6u7Uv7gwYOvvPKKhhtJ/+lPf1L8VFAxdBch5IsvvoiOjjbR++roKufkf3+XgLQDAABAryi5qqEfdL8ZykAbMgDDtCUuLq6goIB+LBaLeTyevreobOXKldnZ2U5OTtu2bZs/f74hN03Ma28BAADDo4csoP/qw44dO7755ps9e/bo8ObR2qiurt6wYcOnn36qPJyCNk6cOLFixYrKykpra2s9xWauOSeDO+0AAACAa82MVH5+vuKCQAOXzAgh77//vlwuv3PnjuFLZgAAAEbu//2//zd//vzi4mIDbzcgIKCkpKSvtZuurq4dO3YcPHhQf7UbA2Aq52Rwpx0AAACsmA4AAAAAwMRERkYyHYK2LCwsPvnkE6aj0AETyjkxo7QDAAAMcrjWDAAAAAAAAAAAoDtUzQAAAAAAAAAAALoz3C80zen+QebUFgAAAAAAAAAA6MlwVTPcFZHg7pDaQVESAAAAAAAAABiHuwEAAACAuUlLS0tLS2M6ikEHOTe81NRUpkMAAAAwZwa69AnXWNGQB20gSwAAAGBIFRUVSUlJw4cPz87OnjhxItPhAAAAgLHA3QAAAAAAYFATCoVnz56Njo6eM2fOwoULf/vtN6YjAgAAAKNgYlWzDz74YN68eUxHAQAAAABmxcLCIioq6vLly+PHj588eXJKSsrDhw+ZDgoAAAAYZmJVM7lcrtff7qWnp0+dOlV/62eWrlpn3lkCAACAQYvL5YpEonPnzonF4vHjx2/btq2zs5PpoAAAAIAxJlY1S0xMLCsrYzoKAAAAADBbrq6uBQUFJSUl//rXv/z9/b/++mumIwIAAABmmFLVTCQSURRlY2PT7enhw4c9PDx4PF58fDx9JVpcXBxFUe7u7kVFRW5ubkOGDImMjGxrayOEREdHUxRFXyrV1tZGURRFUaWlpfRSa9euPXXqFD3xypUrzLW1d+3t7YmJic7OzhwOJyQk5Pz586SPrRsMWQIAAADon4CAgB9++CEjI2PFihWhoaEXLlxgOiIAAAAwNBOrmilfaEY/7ezsPHjwYHV19f79+wsKCioqKggh+fn527dvb2pq+vHHH2tqak6cOFFZWZmUlEQIKSwsXL9+Pb0GW1tbuVzO5XLpp/n5+evXrw8MDKR/B+rh4WHwJvbBypUrS0pKDh06dPPmTV9fX6FQ2Nra2qfWDYYsAQAAAAxEWFhYbW1tRETE7Nmzly5deufOHaYjAgAAAMMxpaqZSjKZLCEhgcfjzZgxQyAQKH8N2N7enpmZaW9v/8wzzyQmJu7cufPBgwd9Xf+ePXscHBx++eUXnUY9UGKxeOvWratXr544caK9vf2mTZukUml+fn4/VmXGWQIAAAAYOBaLFRsbe/HiRT6fP2HCBJFIJJFImA4KAAAADMHkq2ZWVlaurq70Yz6fr1zxcXZ2trW1pR/7+vp2dHT04+eE8v/SSbS6Ul9fL5PJ/Pz86KccDsfDw4P+kWZfmXGWAAAAAHTF3t4+IyPj5MmTtbW1Xl5eu3btwicfAAAAs2fyVTNLS0vFY4qilGd1dXUpHnf7WKP8VCaTaVh/ZGTk/fv3x40bN9BAdUrlpzRF87VvHTHrLAEAAADolqen5969e/fu3Zufnx8YGHjs2DGmIwIAAAA9MvmqmQZ3795taWmhH9fW1rJYLHoQrqFDh7a2ttLTb9++LZVKFYt0q7sZLR8fHysrq4sXL9JPJRLJ1atX6UvP+to6M84SAAAAgD5MnTr1+PHj7777blRUVFhY2NWrV5mOCAAAAPTCnKtmXC53zZo1zc3NNTU1OTk5S5YssbOzI4T4+/s3NDQcO3aspaUlJyeHzWYrFnF0dGxsbGxra4uJicnLyyPGOmIXn8+Pj4/fuHFjTU2NWCxOTk5ms9lxcXGkj60jZp0lAAAAAD2hKCoiIqK2tjY4ODgwMHDFihWKryEBAADAbJhS1UwkEoWFhUmlUoqi6uvr8/LyFE9bWloEAsHx48fT0tKio6Pp1/P5/JCQkEmTJk2bNm369OnZ2dn09JCQkGXLls2bN2/SpEmzZ89msVgvvviiSCQihLz00ksjRoxwdHSsra2NjIwkhFhaWhrniF1ZWVnz588PDQ0dOXJkTU1NeXn5sGHDSB9bR8w9SwAAAAD6w+FwkpOT6+vrCSFeXl6ZmZnt7e1MBwUAAAA6Qxmm0kFRBtqQwieffJKenv7rr78acqO9MnweNEOWAAAAAHSirq5u1apVDQ0N6enpERERTIcDAAAAOmBK15oBAAAAABgnHx+fsrKyLVu2pKenz5w58+zZs0xHBAAAAANlnteaxcXFFRQU0I/FYjGPxzPYpjUzqquokCUAAAAAnevq6tq9e3dKSkpwcHBWVtaYMWOYjggAAAD6yTyrZkYLedAGsgQAAACm7tGjR1lZWXl5eW+88cbq1avpuy0BAACAacEvNAEAAAAAdIzL5YpEonPnzonF4gkTJmzbtq2zs5PpoAAAAKBvcK2ZQSEP2kCWAAAAwJxUV1cnJSU1NTW9//77L7zwAtPhAAAAgLZQNTMo5EEbyBIAAACYn7KyssTERHd395ycHD8/P6bDAQAAgN4ZrmpmgK2A2UDVDAAAAMxPR0fHzp07RSJRWFjYunXrnJ2dmY4IAAAANMG1ZkxCWlRCWgAAAMCMicXizMzMTz75ZPny5SkpKTY2NkxHBAAAAKrhbgAAAAAAAIbD5/MzMjJOnjxZW1vr5eW1a9cufF8IAABgnHCtGZOQFpWQFgAAABgkqqqqkpKSOjo6srOzn332WabDAQAAgP+BqhmTkBaVkBYAAAAYPORy+b59+1atWuXr6/vhhx8+9dRTTEcEAAAA/z+j+IVmQEAARVEURRUWFiom7tmz5/PPP2cuqD7o6uqKiYm5d++e8kQHBwe6URUVFf1bramnhajKzMDTAgAAAGBOKIqKiIiora0NDg6eOnXqihUrWlpamA4KAAAACDGSqhkhZM2aNXK5PDo6mn66Y8eOkpKSiIiI0tJSusgSFhamfP2Rra0tPX3RokWGjzY3N5fFYl25coV+amFhsWTJkueff14qlSpec+/evYcPHw5wQyadFqIqMzpJCwAAAICZ4XA4ycnJdXV1hBAvL6/MzEzlD5YAAADACGOpmilrbGxMTEzMycmxsLAIDw+Xy+U8Hu/AgQNpaWmK17S1tS1btqy8vHz37t2GjE0ikURFRe3du1cmkylPnz59uo+Pzz/+8Q/9bdoU00IMkhkAAAAA8+Dg4JCbm/vDDz9UVlb6+/sXFxczHREAAMCgZoxVs7179/r5+bm6uiqmODk5LViwYN26dWVlZSoXaW9vT0xMdHZ25nA4ISEh58+fJ4SIRCKKomxsbA4fPuzh4cHj8eLj4xVXZtGLODk5KS/Sq4sXLy5evDgzM7PnrAULFhQWFupvQC4TTQvRf2YAAAAAzImPj09ZWdmWLVvS09Nnzpx55swZpiMCAAAYpIyxalZRUeHj46M8hR7by9/ff9GiRQ0NDT0XWblyZUlJyaFDh27evOnr6ysUCltbW0UiUVlZWWdn58GDB6urq/fv319QUKAYTis5OfmHH344ceJEY2PjpEmT5syZI5FIeo0tICAgNDRU5azx48dfv369vr6+7y3Wiommheg/MwAAAADmRygUnj17Njo6eu7cuQsXLvztt9+YjggAAGDQMcaq2c2bNx0cHLpN5HK5paWlbDY7PDy828BYYrF469atq1evnjhxor29/aZNm6RSaX5+Pj1XJpMlJCTweLwZM2YIBIILFy7Qi2zZsmXdunUeHh7Dhg3LyMi4d+/evn37BhI2HfOtW7cGshINTDQtRP+ZAQAAADBLFhYWUVFRly9fHj9+/OTJk1NSUh48eMB0UAAAAIOIMVbNxGIxi8XqOd3d3X3fvn2XL1+Ojo5W/rlffX29TCbz8/Ojn3I4HA8PD8VPC62srBS/auTz+fRHjfr6+o6Ojrlz59Jj57PZbIlEQg+/2m9sNpsQ0tzcPJCVaGCiaSH6zwwAAACAGeNyuSKR6Ny5c2Kx2MvLKzc3t7Ozk+mgAAAABgVjrJrx+fyOjg6Vs2bMmJGbm/vll19u3LhRMVHlgFkURdEPLC0te06kF6mqqpIr2bBhw0DCbm9vJ4TY29sPZCUamGhaiP4zAwAAAGD2XF1dCwoKDhw4UFJS4ufn95///IfpiAAAAMyfMVbNRo0ade/ePXVz33zzzZiYmLVr1x49epSe4uPjY2VldfHiRfqpRCK5evWq4horlXx8fFgslpZD3WuJjtnFxUWH61Rmomkh+s8MAAAAwCAREBBw5MiRzMzMhISE0NBQepANAAAA0BNjrJoJhULNI8dv2bJl+vTpik8JfD4/Pj5+48aNNTU1YrE4OTmZzWbHxcVpWAOfz1+2bNmGDRtOnTollUqrq6u9vLxOnjxJzz106BCbzVZ3YZc6tbW1o0ePFggEfVpKeyaaFqL/zAAAAAAMKmFhYbW1tREREaGhoVFRUXfu3GE6IgAAAPNkjFWzhQsXXrhw4ebNm4SQ0tJSiqJ+/vlniqIU93lksVhffPGFm5ubYpGsrKz58+eHhoaOHDmypqamvLx82LBheXl5YWFhUqmUoqiWlhaBQHD8+PG0tLTo6GhCSGZm5oIFC+bNm8fj8f7617+uX79+2rRp9NoOHjz4yiuvqBxETCaTURT17LPPEkI8PT2Vh+f/4osvoqOjFb92RFoU9J0ZAAAAgMGGxWLFxsbW1dW5uLhMmDBBJBJpc99zAAAA6BNK5ehXut8MpWlDAQEBp0+fJoTs3LmTrt3s2LHjm2++2bNnj4WFoet61dXVGzZs+PTTT21tbbVf6sSJEytWrKisrLS2tqanODg43L9/nxBSXl4uFApVLmX2aSE9MjPwtAAAAACAssuXL69Zs6aqquq999574403DP9BEQAAwFwZRdVMpX//+9+WlpavvPKKnkLSoa6urtjY2IyMjG7XWPXKvNNC+psZVM0AAAAA+qqqqiopKam9vT07O/uPf/wj0+EAAACYA+Otmg0GSItKSAsAAABAP8jl8n379q1atcrX1/fDDz986qmnmI4IAADAtOH6bQAAAAAAc0BRVERERG1tbXBw8NSpU5cuXarhDuwAAADQK1TNAAAAAADMB4fDSU5Orqurs7GxGT9+fGZmplQqZTooAAAAk4SqGQAAAACAuXFwcMjNzT169GhlZaW/v39xcTHTEQEAAJgejGvGJKRFJaQFAAAAQIcqKiqSkpKGDBmSk5Mzbdo0psMBAAAwGYarmhlgK2A2UDUDAAAA0KGurq7du3enpKQEBwdv2rTJ3d2d6YgAAABMAC7qAQAAAAAYFB49epSVlZWXl/fGG2+sXr3azs6O6YgAAACMGsY1AwAAAAAYFLhcrkgkOnfunFgs9vLyys3N7ezsZDooAAAA44VrzQAAAAAABp3Tp08nJSXdvXs3Kytrzpw5TIcDAABgjFA1AwAAAAAYpMrKyhITE93d3bOzs/39/ZkOBwAAwLjgF5oAAAAAAINUWFhYbW1tRETErFmzoqKi7ty5w3REAAAARgRVMwAAAACAwYvFYsXGxtbV1bm4uEyYMEEkEj158oTpoAAAAIwCqmYAAAAAAIMdn8/PyMg4efJkbW2tt7f3tm3burq6mA4KAACAYRjXDAAAAAAA/k9VVVVSUlJ7e3t2dvYf//hHpsMBAABgDKpmAAAAAADwP+Ry+b59+5KTkydMmPDhhx8+9dRTTEcEAADAAPxCEwAAAAAA/gdFUREREZcuXQoODp46derSpUvv3bvHdFAAAACGhqoZAAAAAACowOFwkpOT6+rqbGxsxo8fn5mZKZVKmQ4KAADAcFA1AwAAAAAAtRwcHHJzc48ePVpZWenn51dcXMx0RAAAAAaCcc0AAAAAAEArFRUVK1eu5HA4OTk506ZNYzocAAAA/ULVDAAAAAAAtNXV1bV79+6//e1vQUFBmzZtcnd3ZzoiAAAAfcEvNAEAAAAAQFsWFhZRUVENDQ2TJ08ODAxMSUl58OAB00EBAADoBapmAAAAAADQN1wuNzk5+cyZM2Kx2NPTMzc3t7Ozk+mgAAAAdAy/0AQAAAAAgP47ffp0UlLS3bt3s7Ky5syZw3Q4AAAAOoOqGQAAAAAADFRFRUVCQsLIkSOzs7P9/f2ZDgcAAEAHDFQ1oyjKAFsBs4FirtnAsQ8mAeccYyASidLS0piOAmDwSk1NFYlEA1xJR0fHzp07//73v8+aNWvTpk0jRozQRWgAAACMsTLYlszgfxKKwqV5hoA6i5nBUaNbOBHpHM45xkMn/7QDU+i+Qw+aKF11HIvFio2NjYiIyMzM9PX1Xb58eXJyMofD0cnKAQAADA93AwAAAAAAAJ3h8/kZGRlnzpy5du2at7f3tm3burq6mA4KAACgP1A1AwAAAAAAHRs9evSuXbuKi4uLiooCAwOPHj3KdEQAAAB9hqoZAAAAAADoRWBgYGVl5apVq6Kjo8PCwq5cucJ0RAAAAH2AqhkAmKQPPvhg3rx5ul1nXFwcRVHu7u6MLG4k9JHYfjOPlAIwq7GxkaIoiqI+++wzeopRHeagmXl0H0VRERER9fX1QqFw2rRpS5cubWpqYjooAAAAraBqZjiVlZXUfwUHB+tjE+np6VOnTjXkFgF0rtturI5cLtf5oPj5+fnbt29navGBk8lkaWlpXl5eHA7HxcVlyZIlVVVVirkGS6wOzzyMpxRMl5Y7/GAwYsQIuVzu7OysmKKP86c2Hjx4sGbNGm9vbxsbGxcXF6FQWFBQ0NLSonkpI+lK5TObMisr/d5Zy3i6b+DYbPaKFSvq6+ttbGwmTJiQmZkplUqZDgoAAKAXqJoZTnBwsFwuHz58eFZWVmVlpVluEcBgEhMTy8rKmI7CuKSlpW3btm3nzp1isfjs2bOjRo2aNm1aW1tbn1Yy8MTizANg5Bg5f96/f3/q1KnV1dV79+598OBBTU3NokWL3n333ZSUFANH0j/KZza5EoFAYOBITP3tb/jw4bm5uUePHj19+rSfn19xcTHTEQEAAGhiMlWzAwcO+Pn5cTiciRMnfvnll4rp7e3tiYmJTk5OHA4nJCTk/PnzhBBfX1/6C8C8vLzCwkLFY+bCV0EkElEUZWNjc/jwYQ8PDx6PFx8fT395qPhRUlFRkZub25AhQyIjI+l/faOjoymKor90bWtro5tWWlpKL7V27dpTp07RE3sdNqK+vj48PJzP57u5ua1ataqjo0OxQoqiDhw4QAjx8PBQ/nmUymwrN0QgEFhYWISHh+sxcWBGeh7XPXdjlTuYYiLReCgRQlpaWhYsWDBkyBB3d/fPP/98xIgRFEWtXLlSywjpfd7Z2Vl5n9cwXeH3339XHE0BAQEaDlt1B3s/VFRUREREBAUF2djYODs7p6ene3l50bP6kVg95da0UgrGQ7GH8Hi80NDQH374gZ7e872MqHlDVPkWRjTuySp3y57HjlAo1Pzuqa45Gt5Pex5x6jKg7thRtGvcuHHKRRYDHOYqvfPOO83NzaWlpU8//TSbzXZ0dIyOjs7KylK8wES78uLFi9pkUmX3aTjvadN9Bus7fRAIBHv37v344483bNgwbdq0kydPMh0RAACAGnKDGOCGWltbORzOt99+K5VK6+vrPTw8mpqa6FkJCQmTJk26fPlyS0tLYmKiq6vrkydP5HJ5fHy8p6dnW1tbZ2fnnDlzGhoaGG8FTflbyrKyMisrq6SkJLFYfOTIEYqivv32W3rW9u3bhwwZ8uabb96/f//s2bNubm6xsbH0rPXr1wcGBipWyOVyS0pKVM7quUVls2bNOnDggEQiaWhomDx5ckZGhlwub25utra2Li4upl8jkUgmT57c1dVFP1WX7bKyMktLS3qUipKSkvnz5w8kRQbbLcEANPSmuuO6526scgcrKyuztrZWvEDdofTaa695enpevHjx3r17MTExNjY2e/bs0RDw9u3bx4wZo3j61ltvubu7nzlz5v79+8uXL3d0dGxpadEwXbF4V1fX8uXL8/Pz6fVoOGw1HOx9TenChQsnTJhw69YtlXP7kVj5AHKr7sxjWikFQ0pNTU1NTVU396233ho7duyZM2ckEsmRI0dGjhxJT1f5XiZXtcOrewvTsCer2y17Hjua3z170vB+qu6IU5cBdUEq2tXU1BQTE8PlchXt0tVhrn0PPnr0iM1mJyYmqltWbiJdqXxm++mnn1577TXlwPrafeqikmvdfTp8+9N8AOpPZ2dnUVGRi4tLRETEL7/8YvgAAAAANDONqll9fT0h5NChQ92mNzc3s1isAwcO0E/b29ttbGw+/fRTuVz++PFjgUAQExOTlZVVUFAwkK0r6KNqRgi5ceMG/dTHxyc7O5t+vH37disrq4cPH9JPP/jgAxaL1draKtdd1UxZTk7On/70J/rxyy+//Pzzz9OPP/vsM8VHKA3Zphty/fr1PiRCPfwHa0409Ka641plcafnDtbt3waVh9Ldu3ctLCx27NhBT29ubiaEaF81a25utrKy2rZtG/308ePHdnZ2GRkZ6qYrFpfJZG+88UZRUZG6RnUr8ag72FXSkNLLly/7+Piw2ew5c+Z8+OGH165dU57bj8TKB5BblWcek0spGJKGf9rv379vZWW1fft2zWtQfi/rtoeoewvTsCdr2C1VHjvq3j176vX9tOcRpy4D6oLs1q47d+4oH6G6Osy70dCDNTU1hJC8vDx1y3ZjtF05fPhw5e+ee1bNtO8+DVFp3306fPtjqmpGa2try8jIcHJySk5O1nC6BgAAMDzT+IWml5fXnDlz/vznPwsEgqysLLFYTE+vr6/v6OiYO3cufS09m82WSCR1dXWEEA6H869//auoqOj777+PjY1lNHxNrKysXF1d6cd8Pv/BgweKWc7Ozra2tvRjX1/fjo4O3d6ru7y8fMqUKVwul6KoxMTEe/fu0dOjoqK+/fbbmzdvEkJ27twZFRVFT9eQbUIIi8Vyc3PTYXhg9tQd1yr1uoOpPJQaGhq6urrGjx+vmN7tHx7N6uvrZTKZn58f/ZTD4Xh4eJw/f17ddPqpTCZ77bXXPv/88z/+8Y9abkhXB7uHh8eFCxe++uqrcePGFRQUPPXUU6+99lp7e7uGRbQ5cnWYW5NLKRiJn3/+WSaT+fr69pyl7r2sG3VvYRr2ZM27Zc9jR927p8nM1K0AACAASURBVPbB0HNVHnHqMqAuyG7tcnJy4vF46uJRt9EBnkJ7oihKw1xT6Urla816hqd992mIqk/dZ5i+0zcul5ucnHzmzBmxWOzp6Zmbm9vZ2cl0UAAAAISYyrhmFEWVlZX95z//GTdu3Jo1a3x8fK5fv04IkcvlhJCqqirlQuCGDRvopdzd3V1dXX/66Sf6OzrjZGlpqXjc7dNkV1eX4rH8f2+WpPxUJpP1Y7t3794NDw+fOXPm7du35XL5Rx99pFjn888/z+fzi4qKbty4IZVKx40bp7xRddm2sDCNfQmMh7rjWqVedzCVh5K8x13G+vQpvOfi9MrVTacf3L17d9GiRVOnTl28eLG6o7jbYavhYO8rS0vL2bNnb968uba29vvvv//iiy927Nih4fXaHLk6zK0pphSMgbpO1PBepnINPd/CNOzJmnfLnseOundP7YOh52p5xGkOsud05dX2pI9TqDIPDw9ra+urV6+qe4EpdmVAQMDu3bu7TdS++zRE1afu03ffGdKoUaMKCgq+/vrrkpISPz+///znP0xHBAAAYCJVM0IIRVEvvPDC119/ffXq1Y6ODvqKdB8fHxaL1XPQaNry5cv37NkzYcKEv/71r4YNVjfu3r2ruB17bW0ti8Xy8PAghAwdOrS1tZWefvv2beWbdmv+FldBIBDU1tY+fvw4JibGzs6OEKJ8NQqLxXr11VcLCwsLCwsXLVqkmK452wD9oPK41nI31oa3t7eFhUVtbS39tKmpSXFMacPHx8fKykox0rNEIrl69aqfn5+66fRTFxeXuXPnFhYW1tXVZWRk0BM1HLZE/cHeV3PnzlU+QmfMmDF69OjGxkb6qQ4TS/qVW4FAYHIpBSPRbQ9R0PBe1m2HV/cWpmFP1rxb9qTu3VNlc/r6fqouA+qC7NYusVh8//597TdHG+ApVBl9X45//etfT548UZ6+aNEiOlcm2pVaUtl9GqIaePfpsO8Mb/LkyUeOHNm8eXNycnJoaCg+eQIAALNMo2pWVVUVHBx848aNjo6OO3futLe30/f55vP5y5Yt27Bhw6lTp6RSaXV1tZeXF30Xnl27dvn6+k6ZMqWoqOj48eNbt25luhF9xuVy16xZ09zcXFNTk5OTs2TJEvqjpL+/f0NDw7Fjx1paWnJycthstmIRR0fHxsbGtra2mJgYzfcM9fb2ZrPZeXl5Dx8+vHLlSlFRkfLcxYsXX758OS8vLyIiQjFRQ7YB+kHdca39btwrR0fHv/zlLxkZGbW1tffv31+7di2Xy9V+cT6fHx8fv3HjxpqaGrFYnJyczGaz4+Li1E1XXtbFxWXbtm0ikej06dNE42FL1B/s/fD222+fP39eKpU2NTXl5ORcu3Zt1qxZimzoKrGkv7k1xZSCMVDsIefOnZNKpQcPHhw1atSjR480vJd12+HVvYVp2JO12S27UfnuqbI5fX0/VZcBdUEqt6u5uTk5OVlx00ztDfAU2k1OTo6jo+OLL75YU1PT3t7++++/p6SkfPvttyKRiGj8WGLMXUkIEQqFii8n1FHZfWw2W11UA+8+3fYdI4RC4dmzZyMiImbNmhUVFdVrkgEAAPRF2wHQBmaAG5LJZPn5+U8//TSHwxk3btyHH36omCWVSpOSkpycnGxsbPz9/T/77DO5XD5//ny6dWKx+PXXX6cfz549m9lWHDt2TJH2oKCgjz76SPFULBZ7e3vTj19//XX5fwfALi4uHjNmDIfDefXVVxUjW8vl8uXLl/N4vLFjx5aXl9Mfg+gBXJuamgIDA21sbKZPn37//n3lLSqjB5H9/PPPPTw8hg4d+txzzyUkJBBCuFyuYhMCgSAyMrJbE1RmW7kh9E8qBshguyUYgIbeVHdcd9uNVe5gqampionLli3TcCiJxeKXX37ZxsZm7NixX331lYODg+LOaD0tXbpUeVVyuVwikbzzzjuOjo7W1tYzZsw4d+4c/UqV09esWaN8alWOUK7+sNV8sPcppb///vt777339NNPc7lce3v7oKCg0tJSxdy+Jraurk7zaUpdbjWfeUwrpWBImgcjl0ql9B7C4XCmTp2q+IGeuveybju8XM1bmFzjWULlbqn5XU/lu6fK5mh+P+15xKnLgLpjStGu0aNHf/bZZ87OzoSQpKQknRzm/ehBuVz+4MGDlJSUp556is1mjxw58i9/+cvPP/+smGvkXanuzEYIUfyqtK/dp67vtOw+Hb79adN9TKHrhsOHD09NTX38+DHT4QAAwKCjejQZnVM3bI1pMWQrPvnkk/T09F9//dUwm+spPj7+xRdfVFylYkjmsbcAzah6s62tzc7O7scffwwICGA6lv/T14PdqFKqYFS5NY+UDkL0NUf0X6YMfE9m8N1T33pNjjH0oAK6Upk22TCq7uvp+vXr77333pEjR95777033ngDw+kCAIDB4C0HVGhtbb1w4YJQKGQ6EICBiouL27x58+PHj5uamhISEiZMmPDMM88wHZSZQG7BPOhwTza/d0/TOszRlcpMq+96NXr06F27dhUXFxcVFQUGBh49epTpiAAAYLBA1cwYxcXFxcTE/PbbbxRFGXj01pUrV1IU5eXl9e677+J7PDADa9eura6uHjdunEAgaGpq+uqrr6ysrAghlCqGD4/Bg33g1OWWWSadUmCETvZkde+eRnKq6TfjPMzV0WtXmhzT6jstBQYGVlZWrlq1Kjo6Oiws7MqVK0xHBAAA5g+/0OwD82iF8UOezQl6U+eQUp1DSo2Ekf9ADHqFHjRpptV97e3tW7duTU9Pf+mll9LT0x0dHZmOCAAAzJYJf4cGAAAAAACDDZvNXrFiRX19vY2NzYQJEzIzM6VSKdNBAQCAeULVDAAAAAAATMzw4cNzc3OPHj16+vRpPz+/4uJipiMCAAAzhKoZAAAAAACYJIFAsHfv3o8//njDhg3Tpk07ceIE0xEBAIBZMdy4ZgbYCpgNjDFkNnDsg0nAOccYiESitLQ0pqMAGLxSU1NNZVwzlbq6unbv3v23v/0tKCho06ZN7u7uTEcEAADmwHA308H/JARjTmsHdRYzg31+gHDe0Decc4yHqf/TPtiY1vjxoJkZ9KOFhUVUVNTLL7+cl5cXGBi4ZMmS1atX29nZMR0XAACYNvxCEwAAAAAAzAGXy01OTj5z5oxYLPb09MzNze3s7GQ6KAAAMGGomgEAAAAAgPkYNWpUQUHB119/XVJS4ufnd+DAAaYjAgAAU4WqGQAAAAAAmJvJkycfOXJk8+bNKSkpoaGh58+fZzoiAAAwPSZWNfvggw/mzZvHdBQAYFxwZgAAfcN5BsBECYXCs2fPRkREzJo1KyoqqrGxkemIAADAlJhY1Uwul+t1VOz09PSpU6fqb/3M0lXrzDtLYIr0embADq8BzioweOATyGCAc5q5YrFYsbGxdXV1Li4uvr6+IpHoyZMnTAcFAACmwcSqZomJiWVlZUxHAQD/p7W1lekQcGYAMA3GcLroN5xnAEwdn8/PyMg4c+bMtWvXvLy8tm3b1tXVxXRQAABg7EypaiYSiSiKsrGx6fb08OHDHh4ePB4vPj6e/h44Li6Ooih3d/eioiI3N7chQ4ZERka2tbURQqKjoymKor8AbGtroyiKoqjS0lJ6qbVr1546dYqeeOXKFeba2rv29vbExERnZ2cOhxMSEkKP1NCn1g2GLIEBODk5zZ49e9++fRKJhJEAlM8Mg/y0MBAqTykEZxXQqfDwcD8/v48++ujOnTtMx9I3+ARiivBJCVQaPXr0rl279u3bt2vXrsDAwKNHjzIdEQAAGDe5QehqQ2VlZdbW1spPrayskpKSxGLxkSNHKIr69ttv6Vnbt28fMmTIm2++ef/+/bNnz7q5ucXGxtKz1q9fHxgYqFgJl8stKSlROUvndJjwt956y93d/cyZM/fv31++fLmjo2NLS4u8j60z+yyBAdBnEi6Xa2Nj8/LLLx86dKijo0N5rgFiUD4zmNxpoVeGyaG6U4rcLM4qmuGcYzBTpkwhhAwZMsTa2nrKlCmFhYWK3Uwul6empqampjIXXS9M/ROIPhh5l5nxJyV9MPLe1Ieurq69e/eOHTt27ty5ly9fZjocAAAwUqZ0rZlKMpksISGBx+PNmDFDIBBcuHBBMau9vT0zM9Pe3v6ZZ55JTEzcuXPngwcP+rr+PXv2ODg4/PLLLzqNeqDEYvHWrVtXr149ceJEe3v7TZs2SaXS/Pz8fqzKjLMEhvTo0SOJRPLll18uXLiQx+MtXLiwoqJCrs8xgDQYnKeFgdDhKYUgydCbx48fS6XSH3/8cfny5SNGjAgJCdm1a9ejR4+YjqvPcKoxZvikBL2iKCoiIqK+vl4oFE6bNm3p0qVNTU1MBwUAAEbHiukABsrKysrV1ZV+zOfzlT/HODs729ra0o99fX07OjquXLkyadKkPq1fUV/UVcA6UV9fL5PJ/Pz86KccDsfDw6N/t9M2zixlZmbqalVgSHK5nD4Gv/jii6+//prD4RBCzp8/7+/vb8gwBudpYSB0eEohpplknHMM4/79+8pP6V+6HTly5Kefflq6dOnYsWMnT57c2dlpaWnJUIB9g1ONMTP7T0qgK2w2e8WKFYsWLVq3bt2ECROSkpISEhKsra2ZjgsAAIyFyVfNlD9bUxSlPEt5gM9uH1OUn8pkMg3rj4yMjIyMHGiUuqbyU5ei+dq3jhhrlsRisQ7XBoPN4DwtDITmUwoxi7OKZjjnGEZnZyfTIegSTjXGzOw/KYFuDR8+PDc3Nz4+/u9//7ufn9+GDRsWLFjQ7bgGAIDByeSrZhrcvXu3paWFx+MRQmpra1ksloeHByFk6NChitt43b59WyqVKhYxlXdHHx8fKyurixcv0sPQSiSSq1evLly4kPS9dcaZpYyMDH1vAnRF+SIdiqKGDh3a2dn5wgsvxMbGPvfccxYWFga+0Ewz49zhGafhlELM5ayiGc45hvH999//+uuviqe2trYymWzq1KlLlix5+eWXs7KyyP+WokyXKR4FZsbsPymBPggEgr179x4+fDgpKSknJyc7O3v69OlMBwUAAAwz+XHNNOByuWvWrGlubq6pqcnJyVmyZImdnR0hxN/fv6Gh4dixYy0tLTk5OWw2W7GIo6NjY2NjW1tbTExMXl4eMdZxKPh8fnx8/MaNG2tqasRicXJyMpvNjouLI31sHTHrLIEh0XcDeOmll/bu3dvS0rJ3716hUGiE/zZgh1dJwymF4KwCuqa4G0BeXl5jY+P3338fFRXF5XKZjkuXcBQwDp+UoN+ee+65M2fOxMfHR0RELFy4ULnWDwAAg5EubinQO51sKDU1VRF2XV3dRx99pHgqFou9vb3px6+//rpcLt++ffuYMWOKi4vHjBnD4XBeffXVhw8fKla1fPlyHo83duzY8vJy+pM6fdugpqamwMBAGxub6dOn379/Xy6Xf/755/b29levXh14/HKd3qlNIpG88847jo6O1tbWM2bMOHfunGKW9q0z+yyBAbDZ7FmzZhUXFz958qTnXAP0pvKZYdmyZSZ3WuiVYY4IDacUuemfVTTDOcdg/vSnP/n6+m7evLmxsbHnXGO+hZ8ZfALRB2PuMrlZf1LSByPvTUa0tbVlZGQ4OTklJye3trYyHQ4AADCDkhtkXFKKMtCGFD755JP09HRj+3bI8HnQDFmCgWttbR02bJi6uUbVm8a5w/fKqHLYK1NMsmll2KRpPl2IRCLFX5NmikdB/5hNl2mA3oSbN2+uW7fu/2PvzuOauPP/gc9gCJcKETlEqQiUQ0WroFVLPdpgD/FoK9qVo7otiPVAURe+pZagWKFW1NVWQdcD7apoKxVaXYn3rXjggXjRrSeCEEDABCLz+2N+O5uFJHIkmZnk9fyDR/KZZPKe9+eY5MMc2dnZX3311cyZMwUCY76+DQAANGfMZ2gCgAFo+Q0MAKAKwwUA8E737t3T09P379+fnZ3t5+eXm5vLdkQAAGBQxjlrFh0dHRkZ+eeff5IkWVlZyXY4HIUsgUlBgzcAJBkAvcCYoDaBMXDgwCNHjqxZsyY+Pj4oKOjq1atsRwQAAAZinLNm69evZ85Bpe95BM0hS2BS0OANAEkGQC8wJqhNaEIsFl++fDkkJOS9996LiIgoKSlhOyIAANA745w1AwAAAAAA0C1zc/OoqKjCwkIXF5e+fftKJJIXL16wHRQAAOgRZs0AAAAAAABaSiQSpaSkXLp0qbi42MvLKyMjo7Gxke2gAABALzBrBgAAAAAA0DqvvfZaZmbmnj17MjMzBw8efOzYMbYjAgAA3SMpijLEx5CkAT4FjIZhmiUYAPo+8ALGHC6QSCRJSUlsRwFguhITEyUSCdtR8BJFUXv27ImLi+vTp8/KlSs9PT3ZjggAAHRGYLBPwm+S5kjSQLOW/IJ5FiODRq5bGDd0DmMOd+BHO3/RFYfq4y/UXXuQJBkSEjJ+/Ph169YNHTr0448/Tk5OdnBwYDsuAADQAZyhCQAAAAAA0C5CoTAmJqaoqMjS0rJPnz6pqakKhYLtoAAAoL0wawYAAAAAAKAD9vb2q1evPnHixMWLF/38/Hbv3o0jxAEAeA2zZgAAAAAAADrj7e2dlZW1bt26pUuXDhs27PTp02xHBAAAbcSJWbOAgACSJEmS3LJlC1O4Y8eOXbt2sRdUKzQ2NkZGRj579ky1sGvXrvRGSaXStq2W72kh1GWm/WkBE8ejLqB2ZOAaHuWT4ElKge/QKfiORzWI6jN677777qVLl2bMmBESEjJp0qQ//viD7YgAAKDVODFrRhBEQkICRVFTp06ln27atGnv3r0hISHZ2dn0JMvYsWNVD2/u2LEjXR4WFmb4aFevXm1ubn737l36qZmZ2bRp0z744APVixc8e/bs+fPn7fwgXqeFUJcZnaQFTBaXu0BL2j/XMPkkCAIpBSC4PcgQ6BQtwM0aLCkpWbhwoaurq5WVVZ8+fTIyMuhyVJ8pMDMzi4iIuH37tr+//5AhQ+Lj46urq9kOCgAAWoMyCO0f5O/vT08P0Z48eWJra/vgwQOmxM7OjiCIxMRE1XfNnDkzLy9P15G+wosXL8LDw4cNG0YQxJ07d1QXhYeHf/PNN6ol9PSQliBNIS1Us8y0My3ALzqsTc52gVa1//bTVUqb55NCSoFViYmJTdqegXF2kKEM3inagPXqozhcg6GhoYGBgcXFxTU1NWvXriUI4vDhw8xSLlQfxY0aNHoPHz6MiopydHRctWpVQ0MD2+EAAECLcOVYM1VZWVl+fn49evRgShwdHSdOnLh48eKcnBy1b6mvr4+NjXVycrKysho1atTVq1cJgpBIJCRJWlpaHjp0yNPT087ObsaMGdR//t9Iv8XR0VH1La90/fr18PDw1NTU5osmTpy4ZcsWSm/X++RpWgj9ZwZMBGe7AE/bf/N8EkgpmDZdDTIEOgVLOLubIAji22+/7dWrl42NzYwZMwQCwb1795hFqD7T0b179/T09P3792dnZ/v5+eXm5rIdEQAAvBoXZ82kUqmvr69qCX1tr379+oWFhd2+fbv5WxYsWLB3794DBw48evSob9++YrG4qqpKIpHk5OS8fPly//79+fn5v/76a3p6OnM5rbi4uGPHjp0+fbqkpGTgwIFjxoyRy+WvjC0gICAoKEjtot69e9+/f7+oqKj1W9wiPE0Lof/MgIngbBfgaftvnk8CKQXTpqtBhiAIdApWcHY3sX379rfffpuiqNLS0qSkpJ49e3700UfMUlSfqRk4cOCRI0fWrFkTHx8fFBTUwolXAABgCxdnzR49etS1a9cmhTY2NtnZ2UKhcMKECU0ujCWTydatW/fVV18NGDCgS5cu3333nUKhWL9+Pb1UqVTOnTvXzs5uxIgRPj4+165do9/yww8/LF682NPT09bWNiUl5dmzZ3v27GlP2HTMjx8/bs9KtOBpWgj9ZwZMBE+7AGfbv9p8EkgpmDDdDjIEOoXBcXw3ERIS4uTklJ2dvWfPHnt7e6Yc1WeaxGLx5cuXQ0JC3nvvvYiIiJKSErYjAgAA9bg4ayaTyczNzZuXu7m57dmz586dO1OnTlU9jr2oqEipVPr5+dFPraysPD09mf/bCAQC5lh9kUhEX4CzqKiooaEhODiYviKsUCiUy+U3b95sT9hCoZAgiIqKivasRAuepoXQf2bARPC0C3C2/WvKJ4GUgqnS7SBDoFMYHMd3E3v27KmoqJg9e3ZgYGBeXh5TjuozWebm5lFRUTdv3nRxcenbt69EInnx4gXbQQEAQFNcnDUTiUQNDQ1qF40YMWL16tW//PLLsmXLmEK1V4IgSZJ+0KFDh+aF9FvOnj2reo23pUuXtifs+vp6giC6dOnSnpVowdO0EPrPDJgInnYBzrZ/LfkkkFIwSbodZAh0CoPj/m5CJBJ98cUXYrE4OTmZKUT1mTg7O7uUlJRLly4VFxd7eXllZGQ0NjayHRQAAPwXF2fNunfv/uzZM01Lv/zyy8jIyEWLFh0/fpwu8fX1FQgE169fp5/K5fJ79+4x/zlUy9fX19zcXLfXEaBjdnFx0eE6VfE0LYT+MwMmgqddgLPtX3s+CaQUTI8BBhkCnUKfOLubcHd3V50HEQqFtbW1zFNUHxAE8dprr2VmZv7888+ZmZmDBw8+duwY2xEBAMD/x8VZM7FYrP2SqD/88MOwYcPoC0wQBCESiWbMmLFs2bKCggKZTBYXFycUCqOjo7WsQSQSzZw5c+nSpefOnVMoFPn5+V5eXmfOnKGXHjhwQCgUajkKQ63CwsLXXnvNx8enVe9qOZ6mhdB/ZsBEsNsFjK/9vzKfBFIKJsYAgwyBTqFPnN1NVFRUzJkzp6SkpKamZvv27dnZ2RMmTGCWovqAMXjw4BMnTsTFxU2bNi0oKOjGjRtsRwQAAARBGYT2D/L3909ISGCePnnyxM7O7uHDhxRF7d27lwk1Ly+Pec3Tp09dXV2ZErlcPm/ePAcHBwsLixEjRly5coWiqDVr1jDvlclk3t7e9OPPPvuMoiiFQjF//nxHR0dLS8t+/frt3LmTWfmcOXPCwsLUhtrky5C9vT2zKCIi4ptvvlF9MX3RWdWwTTAtzTPTzrQAv+iwNtntArpq/+2nq5Sq5pNCSoEDEhMTExMTWQxAV4MMxf9O0QasVx/F4d3EmTNnPvroo27dutnY2PTu3Xv58uUvX75klnKh+ihu1CAwFArFqlWrunbtGhUVVVpaynY4AAAmjSuzZvTXkc2bN9Ml//jHPyZNmqT6lcJgLly4QN9lqVXvOnXqVEBAgFwuZ0qYuyO1Z9aM72mhmmWm/WkBftFtbbLVBXTV/nVChyk1giFFJzDmcAQXfrSjU7QZF6qPwm6iHThSg6Dq2bNnc+bMcXBwSElJ4UIjAQAwTSSl7kqoOkeSrf6gf/7znx06dJg8ebKeQtKhxsbGqKiolJSU5vc7186400K0NTNtSAtwls5rk0ddoM0jg3a6TSmP8knwJKXQZhKJhPnLInSKtuFI9RG8qkHuVB/BpRqEJm7durVo0aLz588vXrw4PDxc9ZYjAABgANydNTMFSItaSIsxQW3qHFKqc0gpR+BHO6+h+vgONchxhw4dWrBggYWFRVpa2rBhw9gOBwDAhHDxbgAAAAAAAABAe/fddy9evPjll1+GhIRMmjTpjz/+YDsiAABTgVkzAAAAAAAATjMzM4uIiLhz546/v/+gQYNiYmKqqqrYDgoAwPhh1gwAAAAAAIAHrK2t4+LiCgoK5HK5l5fX6tWrlUol20EBABgzzJoBAAAAAADwRvfu3dPT0/fv35+dne3n57d79262IwIAMFqGuxuAAT4FjAauzG000PeBFzDmcIFEIklKSmI7CgDTlZiYiLsB8JFUKp07d263bt2+//77/v37sx0OAICxwY3DAAAAAAD45+XLl1euXJFKpVKp9MKFC4MGDQoODh4/frybmxvboYFBNTQ0bN68OTExMSgo6LvvvnN2dmY7IgAA44FZMwAAAAAAfisvLz98+LBUKv3999+FQqFYLBaLxe+//36nTp3YDg0MpLKyMiUlZePGjV988cXXX3/dsWNHtiMCADAGmDUDAAAAADAexcXFOTk5ubm59AFo9AzawIEDcdkEU3D//v2vv/76yJEjixYt+uKLL8zMcBlrAIB2wawZAAAAAIARqqurO336tFQq3bdvX0VFxejRo8eOHSsWi0UiEduhgX6dP38+NjZWLpevWLFixIgRbIcDAMBjmDUDAAAAADByxcXF9BXQ8vLyPDw8xGJxcHDwsGHDcCySsaIoas+ePfHx8e7u7qtWrerTpw/bEQEA8BJmzQAAAAAATIVSqTx79mxubq5UKv3zzz9HjRolFovHjBnTvXt3tkMD3auvr1+3bl1ycvLHH3+cnJzs4ODAdkQAADyDWTMAAAAAAFP09OnT48eP0xdB69atG33+5vDhw4VCIduhgS6Vl5cvXrx4x44d8+fPnzt3roWFBdsRAQDwBmbNAAAAAABM2suXL69cuUKfwknfQyA4OHj8+PFubm5shwY6c+vWrUWLFp07d27JkiXh4eG4OwQAQEtg1gwAAAAAAP6/8vLyw4cPS6XS33//XSgU0rfgfP/99zt16sR2aKADhw4dWrBggYWFRVpa2rBhw9gOBwCA6zBrBgAAAAAAahQXF9Pnb545c+aNN96gT+EcOHAgDlPitcbGxu3bt//f//3fW2+9lZqa2qtXL7YjAgDgLsyaAQAAAACANnV1dadPn5ZKpfv27auoqBg+fHhwcPDYsWNFIhHboUEb1dXVrVmzZvny5aGhoYsXL7a1tWU7IgAALsKsGQAAAAAAtFRxcTF9BbS8vDwPDw/6FM6RI0cKBAK2Q4NWe/z4cVJSUnZ29ldffTVz5kxUIgBAE5g1AwAAAACAVlMqlWfPns3NzZVKpX/+KLH5eQAAIABJREFU+eeoUaPEYvGYMWO6d+/OdmjQOpcuXVqwYMGTJ08WL14cEhLCdjgAAByCWTMAAAAAAGiXp0+fHj9+nL4Imkgkos/ffPvtty0sLNgODVpKKpXOmzfP2dn5+++/79+/P9vhAABwAmbNAAAAAABAN16+fHnlyhX6FM4LFy4MGjRILBaPGzfO19eX7dDg1RoaGjZv3pyYmBgUFJSamtqtWze2IwIAYBlmzQAAAAAAQPfKy8sPHz4slUp///13oVBIXwHt/fff79SpE9uhgTaVlZUpKSkbN2784osvvv76644dO7IdEQAAazBrBgAAAAAA+lVcXEyfv3nmzJk33nhj7NixYrF44MCBJEmyHRqo9+DBg4SEhCNHjixatOjzzz/v0KED2xEBALAAs2YAAAAAAGAgdXV1p0+flkql+/btq6ioGD58OH0RNJFIxHZooMb58+fnz5//4sWLFStWjBgxgu1wAAAMzUCzZvgnErQKJnN5B30cjBLGIn2QSCRJSUlsRwEALZWYmCiRSPS08uLiYvoKaHl5eR4eHvQpnCNHjhQIBHr6RGibnJycuXPnuru7r1q1qk+fPmyHAwBgOIabNTO+3x5GuVFcgMTyEWqNdagCnUNK9YT++a2/H+HANahxXjNY9SmVyrNnz+bm5kql0j///HPUqFFisfjDDz/s0aOHvj8aWqi+vn7dunXJyckff/zxkiVLHB0d2Y4IAMAQzNgOAAAAAAAATJpAIAgMDExJScnPz79+/XpISMjJkyf79evn4eERExMjlUoVCgXbMZo6oVAYExNTVFQkEon69euXmpqKSgEAU4BZMwAAAAAA4AonJ6eQkJDMzMyysrKsrCwXF5fU1FQnJ6egoKDU1NSbN2+yHaBJs7e3T0lJOXbs2MWLF728vDIzM3FcNgAYN8yaAQAAAAAA53To0MHf3z8uLi4vL+/evXtRUVHFxcWjR4/28PCYPn367t27q6ur2Y7RRHl7e2dlZW3evHnlypVDhw49deoU2xEBAOgLL2fNoqOjSZJ0c3NjOxAA0LuVK1eOGzdOt+ts5xhimkOQPiqizUyzCgC0KykpIUmSJMmdO3fSJZzqtqBbJljd9vb2ISEh6enpDx48yMvL6927d0ZGhouLS2BgYGpq6sWLF3HEk+G98847Fy9enD9/fmho6KRJk/744w+2IwIA0D1ezpqtX79+w4YNbEfRRidPniT/IzAwUE+fkpycPGTIEAN/KECrNGmlmlAUpfPvwe0cQww5BK1evdrc3Pzu3bvtWYlSqUxKSvLy8rKysnJxcZk2bdrZs2eZpYapCN2OQrzeC4ButbABmwJnZ2eKopycnJgSfYyfDJ2MTrTq6uqEhARvb29LS0sXFxexWJyenl5ZWan9XRypetXBTZW+bwFp4OrmGnd395iYmLy8vNLSUolEIpPJwsPDu3XrNmnSpMzMTJlMxnaAJsTMzCwkJKSwsNDf33/QoEExMTFVVVVsBwUAoEu8nDXjtcDAQIqi7O3tly9ffvLkSSP+UACdiI2NzcnJYTsKFsjl8oiIiKysLKVS2c5VJSUlZWRkbN68WSaTXb58uXv37kOHDq2pqWnVStpZERiFAAxPT+OnDkcngiDKy8uHDBmSn5+flZVVXV1dUFAQFha2cOHC+Pj49q/cAFQHN0qFj4+PgSMxzd2ltbW1WCxOSUkpLCw8ffq0WCzOzc318PAICAiIj4+XSqU6aaXwStbW1nFxcVevXpXL5V5eXqtXr0bmAcBocH3WrL6+PjY21snJyc7OLigo6NixY81fU1RUNGHCBJFI5Orq+re//a2hoYEuz83N9fPzs7KyGjBgwC+//MK8XlM5WyQSCUmSlpaWhw4d8vT0tLOzmzFjBv3fQuYspK1bt7q6ulpbW0+ZMoX+rTt16lSSJOn/stbU1ND/2MzOzqbftWjRonPnztGFr/w/cPMEMiskSTI3N5cgCE9PT+Z8KLpSHB0draysRo0adfXq1eYb4uPjY2ZmNmHCBD0mDvijeadr3krVth+mkNDaUwiCqKysnDhxorW1tZub265du5ydnUmSXLBgQQsjZIaaJq1aUznj4cOHTGcJCAjQ0is19WVNrl+/Hh4enpqa2opEayCVSkNCQt566y1LS0snJ6fk5GQvLy96EUcqQkueWawCYIWm/b7afb3a/Z2mnZSWxqm2mTXvC2KxWMvOUcvmNAlGeyfSlAFNfYHZLnd3d9VJE/11Wx2OTgRBzJs3r6KiIjs7u3///kKh0MHBYerUqcuXL2dewNOqv379Ov2gDdWtZdwzfHXziLu7e1RUVFZWVmlp6apVqwiCiI+Ppw9Ay8jIePjwIdsBGj8XF5f09PQjR47861//8vPz2717N9sRAQDoAmUQbf6g2bNn9+rV69KlS3K5/OjRo926daPLN2zY0LNnT/rx6NGjc3Nz5XL57du3/f39U1JSKIqqqqqysrI6ePCgQqEoKiry9PQsKyvTUm7IjaKa/U8yJydHIBDMnz9fJpMdPXqUJMmDBw8yW2ptbf3ll1+Wl5dfvnzZ1dU1KiqKXrRkyZI333yTWYmNjc3evXvVLlL7oQy1CayoqLCwsNi9ezf9Grlc7u/v39jYSFHU3LlzBw4ceOfOncrKytjY2B49erx48YLZkA4dOkyfPr2srGzv3r3jx49vQ3IM1ixBh7TUmqZO17yVqm0/OTk5FhYWzAs09ZTQ0NDXX3/9+vXrz549i4yMtLS03LFjh5aAVccQiqJmz57t5uZ26dKl8vLyWbNmOTg4VFZWailn3t7Y2Dhr1qz169fT69HSK7X0ZS1OnDhBEMSdO3de+UotVTBp0qQ+ffo8fvxY7VJDVoSmUUhTnrUsMkAVYCzSk8TExMTERE1LNe331e6qKHUNWNNOSkvj1NTMmvcFLTtHtTQFo6UTacqApiCZ7SorK4uMjLSxsWG2S0/jJ63lo5OWGq+trRUKhbGxsVrezouqVx3cLly4EBoaqhpYa6tby5Bo+OrW3mG5r6SkJCsrKzw8XCQSubu7z5kzJy8vTy6Xsx2X8cvLy+vbt++777575coVtmMBAGgXTs+alZeXCwSCDRs2NF/U5BcvIy0tbeTIkRRFFRUVEQRx4MCBJi/QVN4Gup01IwjiwYMH9FNfX98VK1bQjzds2CAQCJ4/f04/Xblypbm5eVVVFaW7WTNVTAIpivrkk08++OAD+vHOnTvp70wVFRXm5ua5ubl0eX19vaWl5bZt21Q35P79+y1NhDr4pcpHWmpNU6dTO1nTvP00+RmgtqeUlpaamZlt2rSJLq+oqCAIouWzZhUVFQKBICMjg35aV1fXuXPnlJQUTeXM25VK5RdffLF161ZNG9VkykZTX9ZCJ7Nmd+7c8fX1FQqFY8aMWbVqVXFxsepSQ1aE2lFIS57ZrQKMRXqi5Ue4lv2+KtVdVZMa17ST0tI4tTQztX1B7c5RLS17TE2dSFMGNAXZZLuePn2q2un0NH7SdDJrVlBQQBDE2rVrX7kSGmer3t7eXvV/0s1nzVpe3VqiYqW6+T5rxlAqlfn5+SkpKWKx2NbWljmvk+24jFlDQ0N6erqzs3N4eLimf90BAHAfp8/QvHXrllKp7Nu3r/aX5eXlDR482MbGhiTJ2NjYZ8+eEQTh5eU1ZsyY999/38fHZ/ny5cxlQTWVs04gEPTo0YN+LBKJVG+k7eTk1LFjR/px3759GxoadHLxXYbaBBIEERERcfDgwUePHhEEsXnz5oiICIIgioqKGhoagoOD6fMUhEKhXC6/efMmszZzc3NXV1cdhgd816pO98r2o7an3L59u7GxsXfv3kx5kx8w2hUVFSmVSj8/P/qplZWVp6fn1atXNZXTT5VKZWho6K5du4YPH97CD9J3X9bE09Pz2rVr+/btc3d3T09P9/DwCA0Nra+v1/IWQ1aEljwbTRVAC2nZ72vaVTWhaSelpXFqb2bN+4LanWOrgqGXqu1EmjKgKcgm2+Xo6GhnZ6cpHn2MnzpBkqSWpXypetVjzZqH1/Lq1hKVcVQ3Wzp06ODv7x8XF5eXl3fv3r2oqKji4uLRo0d7eHhMnz599+7dqt+9QScEAkFUVNSdO3fc3d39/Pzi4+NxYQQA4CNOz5pRLbgTUGlp6YQJE955550nT55QFLVmzRr6XSRJ5uTk/Pbbb+7u7gkJCb6+vvfv39dSzroOHTowj5t8fWxsbGQeN8mJ6tO2XXRTUwIJgvjggw9EItHWrVsfPHigUCjc3d2ZTzx79qzq5OvSpUuZFZqZcbpRgeG1qtO9sv2o7SnNx4qXL1+2PEK1Qw1JkprK6QelpaVhYWFDhgwJDw/X1Emb9EotfVnfOnTo8N577/39738vLCw8cuTIzz//vGnTJi2vN2RFaMmzMVUBtISmStGyq1K7huY7KS2NU3sza94X1O4cWxUMvbSFnUh7kM3LVVerZZGuxs928vT0tLCwuHfvnqYX8LHqAwICtm/f3qSw5dXdqiGRX9XNHfb29iEhIenp6Q8ePMjLy+vdu3dGRoaLi0tgYGBqaurFixexg9Chjh07SiSSy5cvP3782NfXNyMjwzRbHQDwF6cnOHx9fQUCAXM5VbUKCwvr6uoiIyM7d+5MEITq0RMkSX744Ye///77vXv3GhoamGumairnrNLSUub+64WFhebm5p6engRBdOrUibm185MnTxQKBfMW7f+2Zfj4+GhJoLm5+aeffrply5YtW7aEhYXRhb6+vubm5s0vyA2ghdpO18JW2hLe3t5mZmaFhYX007KyMqbLtESToUYul9+7d8/Pz09TOf3UxcUlODh4y5YtN2/eTElJoQu19EpCc1/Wt+DgYNU+O2LEiNdee62kpIR+ym5F+Pj4aMmz0VQBtJCm/b72fX2TNajdSWlpnNqbWXNqd46aNqe1e0xNGdAUZJPtkslk5eXlLf84ot3jZzvR9+X46aefXrx4oVoeFhZG55anVd9CaqtbS1R8r25ucnd3j4mJycvLKy0tlUgkMpksPDycvodAZmYmd85K4TtXV9fMzMyff/5527ZtgwcPPnr0KNsRAQC0FKdnzUQi0YwZM5YtW3blyhWFQrF///7u3bvX1taqvsbb21soFK5du/b58+d3797dunUrXX727NnAwMAHDx40NDQ8ffq0vr6evgW4pnIus7GxSUhIqKioKCgoSEtLmzZtGv3dsV+/frdv3z5x4kRlZWVaWppQKGTe4uDgUFJSUlNTExkZuXbtWi0r15RAWnh4+J07d9auXRsSEkKXiESimTNnLl269Ny5cwqFIj8/38vL68yZM3rYbjASmjpdy1vpKzk4OPzlL3+hL1BSXl6+aNEiGxublr+dGWoKCgpkMllcXJxQKIyOjtZUrvpeFxeXjIwMiURy8eJFQmuvJDT3ZQOYM2fO1atXFQpFWVlZWloafVoKvYj1itCSZ2OqAmgJTft9LbuqJg1Y005KS+NsSTNrovnOUdPmtHaPqSkDmoJU3a6Kioq4uDj6Loot187xs/3S0tIcHBw++uijgoKC+vr6hw8fxsfHHzx4UCKREFq/pXC56gmCEIvFzD8nNFFb3UKhUFNURlDdXGZtbc1c7Oz06dNisTg3N9fDwyMgICA+Pl4qlbbtrA5QNXjw4BMnTkgkks8//zwoKOjGjRtsRwQA0AKtvA5aG7X5gxQKxbx58xwcHKysrIYMGUIfeD99+nQmfplMtmvXLk9Pz06dOr377rtz584lCMLGxkapVK5fv75///5WVlbu7u6rVq2iV6ip3GAbRV89l/bWW29RFLVmzRrVzfH29qYff/bZZ9R/rni9e/funj17WllZffrpp8ylrCmKmjVrlp2dXa9evfLy8ujvPfQVW8vKyt58801LS8thw4aVl5erfqgq+qqxahPIfISPj8+UKVNUN0GhUMyfP9/R0dHS0rJfv347d+6ky1U3hD6Hom0M1ixBh7TUmqZO16SVqm0/iYmJTOHMmTO19BSZTPbJJ59YWlr26tVr3759Xbt2Ze501lyTMYSiKLlcTg81FhYWI0aMYO73pLY8ISFBdQhVjZDS3Cu19+XmGhoaVHurvb19m6vg4cOHX3/9df/+/W1sbLp06fLWW29lZ2czSw1TEdpHIU35Z7cKMBbpifaLi6vd71Oad1VNGjCleSelZZRQ28y079Sa7xw1bU7zYLTv9zVlQFM3Ybbrtdde27lzp5OTE0EQ8+fP19P4SbV+dHrl5eSrq6vj4+M9PDyEQmG3bt3+8pe/3Lp1i1nK8arXNLgRBMGcVdra6tYyJBq+uo3mbgBt09DQcOLEibi4OH9//65duzLndbIdF+8pFIpVq1Z17do1Kirq6dOnbIcDAKCN+gv36JymKwTxmmE2auPGjcnJyf/+97/1/UGazJgx46OPPmIOSzEAo2wtRo9TtVZTU9O5c+fz588HBASwHct/6bsvc6oKaFyriNZWAQdTahzoY4jov2xpf+M0/M7RMPTRbblQ4wxUvaqWZINT1ceup0+fHj9+nL5Uq52dXXBw8NixY99++20LCwu2Q+Or8vLy5cuXb9myZd68eTExMa09dhIAwDA4fYYmsK6qquratWtisZjtQABeITo6+u9//3tdXV1ZWdncuXP79OnzxhtvsB2UKUJFAGfpsHEa2c7R6Lstql6V0Ve3/jg5OYWEhGRmZpaWlmZlZbm4uKSmpjo5OQUFBaWmpqreUB5ayN7ePiUl5dixYxcvXvT29s7MzMQ/qwCAgzBrxmnR0dGRkZF//vknSZIGvlzrggULSJL08vJauHAhbosJ3Ldo0aL8/Hx3d3cfH5+ysrJ9+/YJBAKCIEh1DB+elr7MkQh1RVNFsI7F4RQ4QieNU9POkdcdmePjZ/vptep5h7OjNI906NDB398/Li4uLy/v3r17UVFR9NVCPTw8pk+fvnv37urqarZj5BNvb++srKzNmzevXLly6NChp06dYjsiAID/gTM0284oN4oLkFg+Qq2xDlWgc0ipnuCEL1ODGuc1VF/LFRcX5+Tk5Obmnjlz5o033hg7dqxYLB44cCBPp5sNr7Gx8eeff/7b3/42aNCg1NTUXr16sR0RAABB4FgzAAAAAACAdnJ3d4+JicnLyystLZVIJDKZLCIiolu3bpMmTcrMzJTJZGwHyHVmZmYhISE3btzw9/cfNGhQTExMVVUV20EBAGDWDAAAAAAAQEesra3FYnFKSsqNGzdOnz4tFotzc3M9PDwCAgLi4+OlUqlSqWQ7Ru6ytraOi4u7evWqXC738vJavXo10gUA7MKsGQAAAAAAgO65u7tHRUVlZWWVlpauWrWKIIj4+Hj6ALSMjIyHDx+yHSBHubi4pKenHzly5F//+lffvn13797NdkQAYLoMd10zA3wKGA1cS4h30MfBKGEs0geJRJKUlMR2FADQUomJibiumW6VlpYeO3YsJyfnt99+s7OzCw4OHjt27Ntvv21hYcF2aFwklUrnzZvn5OS0YsWK/v37sx0OAJgc3A3AoJCHlkCW+Ai1pj/ILVuQeT3BxcWNBqrSFKCW9erly5dXrlyRSqVSqfTChQuDBg0Si8Xjxo3z9fVlOzRuUSqVmzZtSkxMDAoKSk1N7datG9sRAYAJwRmaAAAAAAAAhtahQwd/f/+4uLi8vLx79+5FRUUVFxePHj3aw8Nj+vTpu3fvrq6uZjtGThAIBFFRUXfu3HF3d/fz84uPj3/+/DnbQQGAqcCsGQAAAAAAAJvs7e1DQkLS09MfPHiQl5fXu3fvjIwMFxeXwMDA1NTUixcv4vDnjh07SiSSy5cvP378mM7Py5cv2Q4KAIwfZs0AAAAAAAC4wt3dPSYmJi8vr7S0VCKRyGSyiIgI+h4CmZmZMpmM7QDZ5OrqmpmZ+csvv2zbtm3w4MFHjx5lOyIAMHI8mzVbuXLluHHj2I4CANiH0QAA9A3jDACwy9raWiwWp6Sk3Lhx4/Tp02KxODc318PDIyAgID4+XiqVKpVKtmNkx6BBg06cOCGRSD7//POgoKAbN26wHREAGC2ezZpRFKXXg5OTk5OHDBmiv/WzS1dbZ9xZAr7Q62iARt4GGGHA+OBbhynDmAZc4+7uHhUVlZWVVVpaumrVKoIg4uPj6QPQMjIyHj58yHaALBg7duzNmzeDg4NHjhw5ffr00tJStiMCACPEs1mz2NjYnJwctqMAMDm1tbVc+2cmRgMAzqqqqmI7BN3AOAMAHCQQCAIDA1NSUvLz82/cuBESEnLy5Mn+/ft7eHjExMRIpVKFQsF2jIYjFApjYmJu3bolEon69euXmpoql8vZDgoAjAqfZs0kEglJkpaWlk2eHjp0yNPT087ObsaMGfT/hKOjo0mSdHNz27p1q6urq7W19ZQpU2pqagiCmDp1KkmS9D/9ampqSJIkSTI7O5t+16JFi86dO0cX3r17l71tfbX6+vrY2FgnJycrK6tRo0ZdvXqVaOXWmUKWQFfOnTtnb2//17/+9cSJE1y4GK3qaGDiQ4GeYISB9hg9evQbb7zx448/Pnv2jO1Y2g7fOowJxjQwVo6OjiEhIZmZmaWlpVlZWS4uLqmpqU5OTkFBQampqTdv3mQ7QAPp0qVLSkrK8ePHL1686O3tnZmZyYXvqwBgJCiD0NUH5eTkWFhYqD4VCATz58+XyWRHjx4lSfLgwYP0og0bNlhbW3/55Zfl5eWXL192dXWNioqiFy1ZsuTNN99kVmJjY7N37161i3ROhwmfPXu2m5vbpUuXysvLZ82a5eDgUFlZSbVy64w+S6Arhw4d6tixo5mZmY2NTZcuXWJiYi5fvqz6AsPXmupowLuhoFVY6RFGPMK0HMaiNuvbty9BENbW1hYWFkOHDt22bVt1dTWzNDExMTExkb3oWoHv3zr0jUdViTGtzXhUy8B49uxZVlZWVFSUq6src15nVVUV23EZyKFDhwYMGDB48OCTJ0+yHQsAGAM+HWumllKpnDt3rp2d3YgRI3x8fK5du8Ysqq+vT01N7dKlyxtvvBEbG7t58+bq6urWrn/Hjh1du3b9448/dBp1e8lksnXr1n311VcDBgzo0qXLd999p1Ao1q9f34ZVGXGWQLcEAkFjY2NtbW1FRcUPP/wQGBjYvXv3hISE27dvsx0aQZjqUKAnGGFAJ+rq6hQKxZkzZ2bOnOng4PDOO+9kZmbW1dWxHVe7YKjhI4xpYGrs7e1DQkLS09Pv37+fl5fXu3fvjIwMFxeXwMDA1NTUixcvUkZ9HNY777yTn5+/YMGCsLCwSZMmoa8BQDsJ2A6gvQQCQY8ePejHIpFI9buLk5NTx44d6cd9+/ZtaGi4e/fuwIEDW7V+Zn5RVwHrRFFRkVKp9PPzo59aWVl5enrSpxu0FjezlJqaqqtVgU7cu3dPtX6VSqVSqaytrV2xYsXKlStdXV0Jgnj8+LGLiwtbEZrmUKAnRj/CtBzGorZpckkduj8eOXLk/PnzM2bM8PDwGDBgwMuXLzt06MBSgG2HoYaPMKaBKXN3d4+JiYmJiamrqzt9+rRUKo2IiCgvLx8+fHhwcHBwcHCXLl3YjlH3zMzMQkJCxowZs2bNmkGDBoWGhi5evNjW1pbtuACAl3g/a6b6nZskSdVFjY2NzOMmX02a/P7Xsv4pU6ZMmTKlvVHqmtpvWszmt3zrCK5mSSaT6XBt0H7Pnz9nO4RXMM2hQE+MfoRpOYxFbWPE0wEYavgIYxoAQRDW1tZisVgsFqekpBQXF0ul0tzc3Llz57q7u9PlI0eOFAh4/9tQlbW1dVxcXHh4eFJSkpeX11dffTVz5szm21heXm5vb89KhADAC0Y1MjZRWlpaWVlpZ2dHEERhYaG5ubmnpydBEJ06dWJu7/XkyRPVf4k3+QbMWb6+vgKB4Pr16/SlZ+Vy+b179yZNmkS0fuu4maWUlBR9fwS0yuHDhw8cOMA8FQgEFhYWtra2U6dO/eyzz7y8vEiSZPFAM+242ci5zOhHmJbDWNQ2v/32m+rTzp07KxSKYcOGTZ06deLEid999x3xv9NPxoHvrd2IYUwDaIK+2FlUVJRSqTx79mxubm58fPyff/45atQosVj84YcfMgfVGgEXF5f09PSYmJiFCxeuW7duyZIlISEhzNIzZ85Mnjz5/Pnzzs7OLAYJAFzG++uaaWFjY5OQkFBRUVFQUJCWljZt2rTOnTsTBNGvX7/bt2+fOHGisrIyLS1NKBQyb3FwcCgpKampqYmMjFy7di3B1WtPiESiGTNmLFu2rKCgQCaTxcXFCYXC6OhoopVbRxh1lkC3lEolczeAmTNnnjx58tGjR0uXLvXy8mI7tFdAI28tjDCgE8zdAH744YeysrLDhw9HRERYW1uzHZe+oLVzFsY0AE0EAkFgYGBKSkp+fv6NGzdCQkJOnjzZv39/Dw+PmJgYqVTa5Ix7tf797383NDQYINr26N2792+//bZ27drFixeLxeIrV64QBEFR1PTp0x8/fjxy5Ej6lrgAAGq0/4YCLaGTD0pMTGTCvnnz5po1a5inMpnM29ubfvzZZ59RFLVhw4aePXvu3r27Z8+eVlZWn3766fPnz5lVzZo1y87OrlevXnl5eTY2NgRB0LcHKisre/PNNy0tLYcNG1ZeXk5R1K5du7p06UJf1Kn9dJhwuVw+b948BwcHCwuLESNGXLlyhVnU8q0z+iyBrhw6dKhz587Tpk07fvx4Y2Nj8xcYuNZUR4OZM2fybihoFVZ6hBGPMC2HsajNBg8e3L9/f3qyrPlSvtySzwi+degbX6qSwpjWDjyqZdAVpVKZn5+fkpIiFottbW3pkzpv3Lih6fURERHe3t6FhYWGDLLNGhoa0tPTnZ2dw8PD161bR1+p0NLScvjw4Q0NDWxHBwBcRFIGufgISRrogxgbN25MTk7+97//bcgPfSXD50E7ZAlaqLa21sLCQsvVLjhba9zErtT0AAAgAElEQVRs5K3C2dy+Et+Tz9/Ms66qqkrLRZclEgnz12jwvbW3jVFWpRaoZTBB5eXlhw8flkql+/fvNzc3p6+A9t5779FHWdIcHBzKy8stLS2//fbbmJgYXpyVXFVVtXjx4k2bNlVWVtIlNjY248eP/+mnn9gNDAA4yJjP0AQAXbGxsTGyC8QCgP7gPmUAAMbB3t4+JCQkPT39/v37eXl5vXv3zsjIcHFxCQwMTE1NvXjxYmFhYV1dHUVRL168+Prrr4cNG/bw4UO2o341W1tbe3t71RNLa2trf/3114SEBBajAgBuMs6fwdHR0enp6QRBkCQpk8noi7ZCE8gSGD00chYh+WA60NpNAWoZwN3dPSYmJiYmpqam5siRIwcOHJg8ebLqcdm1tbX5+fk+Pj7r168PCwtjN1rtysrKvv3229raWtXC2tra1atXu7i4qF79AwDAaM/Q5CbkoSWQJT5CrekPcssWZF5PcMKX0UBVmgLUMmg3ePDgCxcuNCm0sbEZNWpUZmamSCRiJapXmjlz5saNG83MzORyeZNF1tbWP//88/vvv89KYADAQThDEwAAAAAAAFrnxYsXV69ebV5eW1ubl5fn7e197Ngxw0fVEhKJ5Pfff09JSQkPD/f19bWwsOjUqZNIJDI3N6+rqxs/fvylS5fYjhEAuMI4z9AEAAAAAAAekUgkSUlJbEcBuqFQKMrKykaOHMl2IC2lUCiYx/X19f7+/iwGAwCsS0xMZI6zxqwZAAAAAACwT/VXCnDfrl279u3b5+Dg4ODgYPcfIpGIeWxtbc12jG1UX19fWVnp6OjIdiA6gPOsAVqrSX8x3KwZL25CbADIAxgrtG39QW7ByCQlJeGIEqOBqjR6iYmJbIcAHDV58uTJkyezHYVeCIVC45gyA4D2M9ysGa6p3BwuNa0WJgh4Co3ZMDBuGAzGIv3B4STGB8cyGCvd1qlcLu/QoYO5ubkO1wkAAKBXuBsAAAAAAADo3YULF1xdXdPS0mpqatiOBQAAoEVwXTMAAAAAAFBv165dhw8fdnFxcXJycnJycnFxcXBw6Natm7Ozs6Ojo0DQil8TJSUl1dXV33zzzTfffDN9+vSFCxc6OzvrL3IAAID2w7FmAAAAAACg3ujRo5OTkz/66CMPD4/a2tpjx479+OOPX3zxxaBBg6ytrZ2dnf38/EaPHh0REbFgwYKVK1du37790KFDN27cKCsra7KqJ0+eUBRVW1tbW1u7du1aNze3iRMnFhYWsrJd8ErJyclDhgzh+PpXr15tbm5+9+5dnYQEpqa6ujohIcHb29vS0tLFxUUsFqenp1dWVhosAL32Mn13YdPBiVmzgIAAkiRJktyyZQtTuGPHjl27drEXVCs0NjZGRkY+e/ZMtbBr1670Rkml0ratlu9pIdRlpv1pAVPD9zbPLzzKNt9TDZzCo5ZPoPG3Bo9qlsvVKhKJhg8fPnny5Dlz5ixdunTz5s2//fbbpUuXHj16pFAoCgoK/vnPfy5YsCAoKMjZ2fnBgwcHDhz49ttvJ0+e3Lt3bwsLix49egwaNGjs2LGff/75gQMHFAoFvdr6+nqFQpGdnT1o0KBRo0bhmyG0llwuj4iIyMrKUiqVbMcCvFReXj5kyJD8/PysrKzq6uqCgoKwsLCFCxfGx8ezHRpwDGUQ2j/I398/ISFBteQf//hHSEjIy5cv9+7dS8cZHBzc2NjIvMDGxoYuDw0N1VfQmq1atUogENy5c4cpOXXqVEBAgFwuV33Z8+fPCYLIy8vTtB6jTwulLjPtTAtwk55qjWnzFEVxsNm3sM3rlv46CJdHGCNLtYlLTExMTExkO4r/4nLLp1hq/G3AtWqlOF+z33//PUEQR44cYUo4WK1Uu2tWoVA8ePDg/PnzOTk5GzdufOutt9T+HiFJUiAQODk5TZ48md7pgyqFQjFv3jxHR0dbW1uxWHz06FHVQktLy5EjRxYUFFAURd/w1MLCQiqVenh42NraRkdHM81e7Xooirp58+b48ePt7Ox69OixcOHC+vp6iqKmT5+uWkf0KESvwcHBoeUfqnblrVq/JhcuXDh48OCJEyeYt4NaHByfOSI8PNzJyamurk61cP369dOnT6cf66qXtb8XtKGXtb+LmbImvYaLs2ZPnjyxtbV98OABU2JnZ0cQRJPePnPmTC0zL3ry4sWL8PDwYcOGNR+dw8PDv/nmG9US3c6a8TQtVLPMYNbMKOmj1pq3eYozzb5VbV639NRBODvCGF+qgVNf3znb8ilWG38bcKpaKW7XLEVRV65cGTx4cJNZM4p71Urpumabz5qZmZl17NhRKBS6ubn5+/tPnjz5+fPnuvo4ozF79uxevXpdunRJLpcfPXq0W7dudKGbm9ulS5fKy8tnzZrl4OBQWVlJUVROTo5AIJg/f75MJjt69ChJkgcPHtSyHoqiRo8enZubK5fLb9++7e/vn5KSQpcvWbLkzTffVI1k7ty5AwcOvHPnTmVlZWxsbI8ePV68eKH9QzWtvFXr1wKzZq/EtfGZI2pra4VCYWxsrJbX6KqX6aQXtKGX6aSLmaYmvYYTZ2g2kZWV5efn16NHD6bE0dFx4sSJixcvzsnJUfuW+vr62NhYJycnKyurUaNGXb16lSAIiURCkqSlpeWhQ4c8PT3t7OxmzJhBUZTqWxwdHVXf8krXr18PDw9PTU1tvmjixIlbtmxh1q9zPE0Lof/MgLFq3uYJzjR742vznB1hjC/VwCm6avkEGj/HcHZMIwhCLpfPnz//xx9/bL7I6Ku1pKSEIAgzM7POnTsLhcJevXpNnz79p59+Kikp+eOPP4KDg318fDp27Mh2mNxSUVGxbt26r776asCAARYWFiNGjHj8+LFMJmMKu3Tp8t133ykUivXr19NvUSqVc+fOtbOzGzFihI+Pz7Vr1zSth379v/71rzFjxlhYWLz++uuhoaEHDhxQG4lMJvvhhx8WL17s6elpa2ubkpLy7NmzPXv2aPnQlq/8lesH0K27d+/W19e7u7treoEOe5muekE7exm6WJtxcdZMKpX6+vqqltDX9urXr19YWNjt27ebv2XBggV79+49cODAo0eP+vbtKxaLq6qqJBJJTk7Oy5cv9+/fn5+f/+uvv6anpzMXTYiLizt27Njp06dLSkoGDhw4ZswYuVz+ytgCAgKCgoLULurdu/f9+/eLiopav8UtwtO0EPrPDBir5m2e4EyzN742z9kRxvhSDZyiq5ZPEAQaP6dwdkwjCCI+Pj4+Pt7Jyan5IqOv1rq6Ok9Pzy+//HL79u1Pnz4tLi7+8ccfx40bJxKJ2A6Nu27duqVUKvv27ataWFRUpFQq/fz86KdWVlaenp7MvK1AIGCmjEUiUXV1tab10PLy8gYPHmxjY0OSZGxsrKbr6xUVFTU0NAQHB9MXKRYKhXK5/ObNm1o+tOUrf+X6AfSBJElNi3TYy3TVC9rZy9DF2oyLs2aPHj3q2rVrk0IbG5vs7GyhUDhhwgT6FD9GG6aB9THPSsfM/NNG53iaFkL/mQFjpbbNE3xo9nxs8zwdYfiYauAU3bZ8Ao2fMzg7ph04cKBz585isVjtUqOv1lu3bt25c2fNmjVjx46lz5mFV1J77KHaQub3f4cOHZoXajqGsbS0dMKECe+88w59h9M1a9ZoeiVdfvbsWdXzmJYuXarlQ1u+8leuH0C3PD09LSws7t27p+kFuuplOuwF7exl6GJtxsVZM5lMZm5u3rzczc1tz549d+7cmTp1qmpTaMM0sD7mWYVCIUEQFRUV7VmJFjxNC6H/zICx0tTmCc43ez62eZ6OMHxMNXCKbls+gcbPGdwc08rKyjZt2kRf1Fkto6/WTp06sR0C//j6+goEguvXr2splMvl9+7dYxpwy9dDEERhYWFdXV1kZGTnzp0Jgqivr2cWNTkMx9fX19zcvIVnIr9y5TpZP0CbWVtbT5ky5aeffnrx4oVqeVhYWFhYGKG7XqbvXqDXLgw0Ls6aiUSihoYGtYtGjBixevXqX375ZdmyZUxhm6eBdTvPSjfQLl26tGclWvA0LYT+MwPGSkubJ7jd7PnY5nk6wvAx1cApum35BBo/Z3BzTEtLS9u9e7dAICBJ0tXVlSCIUaNGkSSZn59PvwDVCs2JRKIZM2YsW7bsypUrCoVi//793bt3FwqFdGFBQYFMJouLixMKhdHR0a1dT21trbe3t1AoXLt27fPnz+/evbt161bmLQ4ODiUlJTU1NZGRkWvXrhWJRDNnzly6dOm5c+cUCkV+fr6Xl9eZM2e0fKiWletk/QDtkZaW5uDg8NFHHxUUFNTX1z98+DA+Pv7gwYMSiYRQ6TLt7GU9evTQay/QaxcGGhdnzbp3767lXN8vv/wyMjJy0aJFx48fp0vaNg2s83lWOmYXFxcdrlMVT9NC6D8zYKy0t3mCw82ej22epyMMH1MNnGKAlk+g8bOBm2PasmXLmPm1Bw8eEP+5h2ZAQAD9AlQrqPX999+PHz9+9OjRIpFo8eLFv/zyi42NzfLly8ePHx8UFNStW7eCgoK8vDxbW9u1a9eOHTtWoVCQJFlZWenj43Pq1KmkpKSpU6dqWk+3bt22bduWm5vbvXv36Ojod95558aNG/Q9GT7++GNnZ2cHB4fCwsIpU6YQBJGamjpx4sRx48bZ2dl9/vnnS5YsGTp0qJYP1bLylq9fU1qUSiVJkm+//TZBEK+//rray3oAaGFnZ3f69OkBAwZ88sknnTp1Gjx48P3790+ePOnp6Um/QCe9zNPTs/29oG29rJ1dDP6LMgjtH+Tv75+QkMA8Xb169dtvv636Am9vb9Wn9fX1gYGBBEEwNwufPXu2u7v7lStXKioq5syZo3pTWAsLC+aNb731FnMD0blz5/bs2fPs2bNyufzChQuvv/766dOn6UX79+83Nzevr6/XFLDaOxz/+uuvr732WmNjI1NCXzJDyx3NTSEtVLPMtDMtwE36qLXmbZ4ybLPXVZvXLT11EHZHGJNKNTS5mTe7dNjyKSNq/G3AqWqlOD+mUf87a8bgWrVShq1ZrrUiAOOAngXQWk16DRdnzZ48eWJnZ/fw4UOKovbu3ctM8KnOszx9+tTV1ZUpkcvl8+bNc3BwoO/weuXKFYqi1qxZw7xXJpN5e3vTjz/77DOKohQKxfz58x0dHS0tLfv167dz505m5XPmzAkLC1MbapOj/e3t7ZlFERER33zzjeqLdTtrxtO0NM8MZs2Mkj5qTbXNU2w0e121ed3SUwdhd4QxqVQDp76+66rlU8bV+NuAU9VKcXhMo40YMYJZbffu3ZlyrlUrhVkzAP5DzwJoLY7OmtHfGzZv3kyX/OMf/5g0adLLly8NEdz/unDhAn1npVa969SpUwEBAXK5nCmxt7dv/v2sCaNPC9UsM+1PC3CTnmrNCNq8zumvg7CVbRNMtYnj2td3jDM6wbVqpTCm6QhmzYB1hDpsB8Un6FkArdWk1wjUDkMGxlwDlfHXv/7V0tJy9+7dkydPNnAwAQEBqv+TbInGxsZNmzbt37/fwsKCKdR+PaaW4HtaCHWZaX9awKQYQZvnEbaybYKpBk7BOGOsMKYBGAdKw8QZAIBhcGLWTC36enW8YGZmtnHjRsN8Fo/SQhg2M2Cs0OYNiUfZ5nuqgVN41PIJNP7W4FHNoloBAAC4iYv30AQAAAAAAAAAAGAXZs0AAAAAAAAAAACa4u4ZmgAAAAAAYDqSkpKSkpLYjgLACKFnAbRKYmIi8xizZgAAAAAAwL7ExESJRMJ2FAB8QncZdBwAHWrSoQw3a0aSpME+i0eQFjAaaMwGg1QD3+FwEmOFajVKqv9vBwAAMDUGmjXDDYMBjBv6OAC0kEQiwb/EAQAAAIAXcDcAAAAAAAAAAACApjBrBgAAAAAAYORWrlw5btw4tqMAAOAZzJoBAAAAAAAYOYqi9HpJjeTk5CFDhuhv/QA8oqvugG7FBZg1AwAAAAAAMHKxsbE5OTlsRwEAwDOYNQMAAAAAADBmEomEJElLS8smTw8dOuTp6WlnZzdjxgz6SLTo6GiSJN3c3LZu3erq6mptbT1lypSamhqCIKZOnUqSJH3kS01NDUmSJElmZ2fT71q0aNG5c+fowrt377K3rQA6Vl9fHxsb6+TkZGVlNWrUqKtXrxKt7A7oVryGWTMAAAAAAABjJpFIVA80o5++fPly//79+fn5v/76a3p6ulQqJQhi/fr1GzZsKCsrO3/+fEFBwenTp0+ePDl//nyCILZs2bJkyRJ6DR07dqQoysbGhn66fv36JUuWvPnmm/R5oJ6engbfRAB9WbBgwd69ew8cOPDo0aO+ffuKxeKqqqpWdQd0K17DrBkAAAAAAIDJUSqVc+fOtbOzGzFihI+Pz7Vr15hF9fX1qampXbp0eeONN2JjYzdv3lxdXd3a9e/YsaNr165//PGHTqMGMCiZTLZu3bqvvvpqwIABXbp0+e677xQKxfr169uwKnQrnsKsGQAAAAAAgMkRCAQ9evSgH4tEItUf8E5OTh07dqQf9+3bt6GhoQ1nh1H/oZNoAVhRVFSkVCr9/Pzop1ZWVp6envRJmq2FbsVTmDUDAAAAAAAwOR06dGAekySpuqixsZF53OT3uepTpVKpZf1TpkwpLy93d3dvb6AA7FE7P8X0l5Z3BwLdircwawYAAAAAAAD/VVpaWllZST8uLCw0Nzenr6nUqVOnqqoquvzJkycKhYJ5S5N5NwDj4OvrKxAIrl+/Tj+Vy+X37t2jDz1rbXdAt+IpzJoBAAAAAADAf9nY2CQkJFRUVBQUFKSlpU2bNq1z584EQfTr1+/27dsnTpyorKxMS0sTCoXMWxwcHEpKSmpqaiIjI9euXUvgAkxgFEQi0YwZM5YtW1ZQUCCTyeLi4oRCYXR0NNHK7kCgW/EWZs0AAAAAAACMmUQiGTt2rEKhIEmyqKho7dq1zNPKykofH59Tp04lJSVNnTqVfr1IJBo1atTAgQOHDh06bNiwFStW0OWjRo2aOXPmuHHjBg4c+N5775mbm3/00UcSiYQgiI8//tjZ2dnBwaGwsHDKlCkEQXTo0AEXYAIjsHz58vHjxwcFBXXr1q2goCAvL8/W1pZoZXcg0K14i0S6AQAAAACAXfRPRPovsGvjxo3Jycn//ve/2Q4EXg0dhy/QrXikSbfCsWYAAAAAAAAAAABNCdgOAAAAAAAAADghOjo6PT2dIAiSJGUymZ2dHdsRAfAeuhWv4VgzAAAAAAAAIAiCWL9+PfUf+G0PoBPoVryGWTMAAAAAAAAAAICmDHSGJkmShvkgMA64SQXvoI+DUcJYpA8SiSQpKYntKACgpRITE3GhcQAAMFmGu66Zkf32IEncflRfMP/CU+gR7MKgpHMYi/QHP8JNCu7vxmuoOAAAMHG4GwAAAAAAALAvKSkJx6ICtAE6DoBuJSYmMo8xawYAAAAAAOzDgagAAAaGQ8Kba5IN3A0AAAAAAAAAAACgKT7NmpWUlJAkSZLkzp07W/ve6OhokiTd3Nz0EBcA6NHKlSvHjRun23W2c0AwzfFEHxXRZqZZBQDaNf+axKluC7qF6gYAADAMPs2aOTs7UxTl5OTUhveuX79+w4YNOg+pDU6ePEn+R2BgoD4+Ijk5eciQIYb8RIA2aNJQNaEoSucXuW/ngGCY8eTUqVPBwcGdOnXq2rXrmDFjrl271uZVKZXKpKQkLy8vKysrFxeXadOmnT17lllqmIrQ7UDEnSEdWNfCBmwKmn9N0sf4Seh0dKJVV1cnJCR4e3tbWlq6uLiIxeL09PTKykrt7+JI1asObqoEAv1eBcVg1Q0AAGDi+DRrZhwCAwMpirK3t1++fPnJkyeN8hMBdCg2NjYnJ4ftKFjw7rvv+vn5PXjwoKCggCCIoKCgioqKtq0qKSkpIyNj8+bNMpns8uXL3bt3Hzp0aE1NTatW0s6KwEAEYHh6Gj91ODoRBFFeXj5kyJD8/PysrKzq6uqCgoKwsLCFCxfGx8frLmQ9Uh3cKBU+Pj4GjsTod5cBAQH0jOSWLVuYwh07duzatYu9oFqnsbExMjLy2bNnLX8LNpBTsIHNYQM5pfkGdu3alR45pVJpe9bMrzxo0YY2QPBi1qyysnLixInW1tbu7u5Nvg3U19fHxsY6OjpaWVmNGjXq6tWrquVOTk52dnZBQUHHjh1TfdfDhw+Z/wRev37dcFuijkQiIUnS0tLy0KFDnp6ednZ2M2bMoP9VyJyCtHXrVldXV2tr6ylTptA/dKdOnUqSJP0v1pqaGnpbsrOz6XctWrTo3LlzdOHdu3e1B1BUVDRhwgSRSOTq6vq3v/2toaFBdZ0kSebm5hIE4enpyZwPpTbtqhvi4+NjZmY2YcIEvaYOeCQ3N9fPz8/KymrAgAG//PILoa6hqm1CTCGhtbMQKgOFm5vbrl27nJ2dSZJcsGBBCyNkBg1Ng0mTcobqeEJ/odfUMTV1Z02cnJy+/fZbOzu77t27p6WlPX369MSJE61IugqpVBoSEvLWW29ZWlo6OTklJyd7eXnRizhSEVryzGIVACs07cHV7q3U7vI0fTfQ0jjVNrPmfUEsFmvZOWrZHC17zOadSFMGNPUFTV+T9NdtdTg6EQQxb968ioqK7Ozs/v37C4VCBweHqVOnLl++nHkBT6ue+YbZhurWMu4Zvro5JSEhgaKoqVOn0k83bdq0d+/ekJAQgiCys7PpCho7dqzqMXcdO3aky8PCwgwf8IoVK0iSPHr0KP3UzMxs2rRpH3zwgUKhaMnbObuBJSUlCxcudHV1tbKy6tOnT0ZGBl1uNBvIMNYaVCqV3377rZeXl6WlZf/+/X/77Te63Gg2cPv27eT/or/yGc0GtrwPPnv27Pnz5+38OCYPnEoCofXg94aGhri4uJ49e1pZWXl6eqamptLlrW0D/x9lEO35oNDQ0Ndff/369etlZWWRkZE2NjY7duygF82dO3fgwIF37typrKyMjY3t0aPHixcvKIqaPXt2r169Ll26JJfLjx492q1bN4qiNmzY0LNnT4qiGhsbZ82atX79era2iPrf/0nm5OQIBIL58+fLZLKjR4+SJHnw4EF60YYNG6ytrb/88svy8vLLly+7urpGRUXRi5YsWfLmm28yK7Sxsdm7d6/aRc0/UdXo0aNzc3Plcvnt27f9/f1TUlLo8oqKCgsLi927d9NP5XK5v79/Y2MjpTntOTk5HTp0mD59ellZ2d69e8ePH9+25BisWYIOaam1qqoqKyurgwcPKhSKoqIiT0/PsrIySl1DVduEcnJyLCwsmBdo6izMQPHs2bPIyEhLS0tmoFCLGRBos2fPdnNzu3TpUnl5+axZsxwcHCorK7WUaxpPtHRMLd35lZ48eUIQxIEDB7S8RksVTJo0qU+fPo8fP1a71JAVoWkg0pRnLYsMUAUYi/QkMTExMTFR01K1e3BK896qeQPWtJPS0jg1NbPmfUHLzlEtLXtMTZ1IUwY0Banla5Kexk9VLRmdtNR4bW2tUCiMjY3V8nZeVL3q4HbhwoXQ0FDVwFpb3VqGRMNXt/YOq1vaP8vf35+eNaM9efLE1tb2wYMHqq+xs7MjCKLJSmbOnJmXl6fjWFvgypUrgwcPJgjiyJEjquXh4eHffPPNK9/O5Q0MDQ0NDAwsLi6uqalZu3YtQRCHDx9mlhrBBtKMuAb/7//+z9nZ+cyZM1VVVcuXLxcIBOfPn2eWGsEGbtu2bdu2bZqWGsEGtqoP0rNmWiLUPvY2zwNHkkBRlIWFRXx8vEwme/jw4Ycffujk5FReXk4vSkpKsrOzO3ny5IsXL3Jzc4VC4ebNm5k3vrINNMkJ12fNSktLzczMNm3aRD99+vQpQRD03r2iosLc3Dw3N5deVF9fb2lpuW3btvLycoFAsGHDhiaron9iKZXKL774YuvWrW3dlP9Pt7NmBEEwDdHX13fFihX04w0bNggEgufPn9NPV65caW5uXlVVRelu1kxVWlrayJEjmaeffPLJBx98QD/euXMn3W40pZ3ZkPv377ciEerglyofaam1oqIitb+p1E7WNG9CTX4GqO0sTQYK+lyhls+aVVRUCASCjIwM+mldXV3nzp1TUlI0lVOaxxPtUzaauvMrbd++3dPTs6GhQctrtFTBnTt3fH19hULhmDFjVq1aVVxcrLrUkBWhdiDSkmd2qwBjkZ5o+XKmaQ/ehOreqkmNa9pJaWmcWpqZ2r6gdueo1iv3mM07kaYMaApSy9ckSm/jp6qWjE5aapw+x3Pt2rUt/DjOVr29vb3q/6Sbz5q1vLq1RMVKdXN21mz16tX06bGqvLy8Jk6cSJLkvn37mELV33IKhWLevHmOjo6WlpYjR44sKCigP5cgCAsLC6lU6uHhYWtrGx0dzUyJ0m9xcHBQfcsrvXjx4t13383Pz28+5/Lrr7++9tprWmbbub+BoaGhx48fpx+/fPmySTM2gg2kjLoGGxsbO3bsmJyczJT4+vp++umnRrOB1KtmzYxgA1vVB9s5a9Y8D21Lgj7yoLqZ9E/O7Oxs+umECROCg4OZV/bv33/WrFnM01e2gSY54foZmrdv325sbOzduzf91NHRkZ7aJAiiqKiooaEhODiYPhpQKBTK5fKbN2/eunVLqVT27du3+dqUSmVoaOiuXbuGDx9uuG1oAYFA0KNHD/qxSCSqrq5mFjk5OXXs2JF+3Ldv34aGhleedNkqeXl5gwcPtrGxIUkyNjZW9RTfiIiIgwcPPnr0iCCIzZs3R0REEJrTTr/F3Nzc1dVVh+GBEfDy8hozZsz777/v4+OzfPlymUym5cWvbEJqO0uTgUIkEjX5AaNdUVGRUqn08/Ojn9LH8V69elVTOf20DeNJ27pzZWXl4sWLMzMz23xtaU9Pz2vXru3bt8/d3T09Pd3DwyM0NLS+vl7LWwxZEVryzJEqAIPRsvjaLq0AACAASURBVAfXsrdSpWknpaVxam9mzfuC2p1jq4Khl6rtRJoyoClILV+TmtP5+Nn+0YlGkqSWpXypetVjzZqH1/Lq1hIVu9XNNVKp1NfXt0khSZJbtmzp169fWFjY7du3m79rwYIF/4+9O41r4lz/Bj7BEDZFgiAqomwKuAtYOWhFa7RaweopaKuA2lMQRKmiFoq1gEsFrbRUraL9u59TFa1LcKlE60IBd1GKK7QqCsgSVMQEAnlezHPmpJCMLElmEn7fF37MTDK55rruuSfcmdxz+PDhU6dOPX36dMCAAQKB4MWLF/Hx8UKhsL6+/uTJk1evXj169Ghqaio1B1B0dPT58+ezsrJKSkrc3d0nTZokkUjeGl5MTExMTIzSm5j169fv8ePH5B94OrqDe/fufffdd+Vy+fPnzxMSEnr37j116lR92kFCrytYVlZWXV2t+ANzR0fH7OxsvdlB0rFjx/r06WNubu7l5XXq1CnFVXqwg2o5BpupaR5alwSCINSeh0ePHlEfITp37kwQBDlTAUEQ//znP7OysrKzsyUSyalTpx4+fPjhhx9SL2xpitg+aiZvcjOgDh06KK7KyclRHBRcvXp105dQnj9/HhgY6OXlFRQU1NDQoLmwW4raKaLJZ0fFOBvtmuJDmUzWivd9/vz5lClT3nvvveLiYrlcvmHDBsVtTpw4kc/n79q168mTJ1Kp1NHRkVCddvIlBgZsb1GgfRwORygUHj9+3NHRcdmyZW5ubo8fP1b15Lc2IaUHS9Ojvr6+vvkRKu00OByOquXkf1T1JzQHJs3hrMqrV6+mTp26evXqf/zjH815viodOnR4//33f/jhh/z8/N9+++3QoUPbt2+neb42C0GTZzaUALRJVVHoz1ZNt9CczwZU46RvZk2PBaUnxxYFQ65t5kFEHyTNx6Sm1Nt/qqV3cnZ2NjIyKigoUPUEXSy9p6fn3r17Gy1sfrlb1CVqrdws9PTpUysrq6bLzczMjhw5wuPxpkyZ0mg2H7FYvHnz5tjY2KFDh1paWq5du1YqlW7ZsoVcK5PJFi5caGFh4ePj4+rqSs6PIxaLN23atGLFCmdn586dOycmJpaXlx88eJA+tlOnTpmbmwsEAqVrybCfPXumuztICggIsLGxOXLkyMGDBxWHX/VgB/W7glZWVsbGxn/99Re15MmTJxUVFXqzgySJRJKenv748eOAgIAPPvhA8VZU+rGDRJuPwWZSmodWJ4HQQB5I5FSeY8eOJR8GBQUlJCSMGzfOxMRkxowZ27ZtUzyiW5oito9xuLi4GBgY5Ofnkw/FYjF1SLu5uRkaGjadGdrNzY3L5Sqd5r9Hjx6+vr47d+68c+dOYmKiRiNXl+fPn1M3X8/Pzzc0NHR2diYIolOnTuSQLUEQxcXFirPZ0X9nS3F1dc3Pz6+pqQkJCTE3NycIotG1J4aGhh9//PHOnTt37txJTeynKu0ANDgczgcffHDixImCgoK6ujrylyPNbKjN0aijKCsro46a5mjUaUgkkoKCgoEDB6paTj5U2p/QHJiE6sNZladPn/r6+sbGxvr7+zd/d5ry9fVVPGZ9fHx69epVUlJCPmS2EK6urjR5ZrwEoGWqzuA0Z6tGDVjVSYqmcdI3s6aUnhxV7U5Lz5iqMqAqSJqPSc3Uuv5TXb0TeV+Of//732/evFFcHhgYSOZWR0vfTErLTRMVU+VWo7ZPSk0Ri8WGhoZKV9nb2x88ePDBgwezZ89WHCikv7pQ6dV59FeMKlVWVrZ9+3byh0hK8Xg8giDeeudZ1u4g5eDBg5WVlQsWLBg5cmRGRobe7KDeV9DAwODTTz/duHHjpUuXyFmxHjx4QF2howc7SBBEYGDgsWPHXFxcLCwsFi9e/M4775CTf+nNDpLaeAw2k6o8tC4JhAbyQCi7+H3NmjVJSUkikej169cHDhyIiIhQvP9yS1PE9lEza2vrTz75JDExMT8/v7KyMjo6mjqk+Xx+RETE6tWrL126JJVKr1692rdv3+zsbD6fHx4evmbNmps3b0ql0pMnT9ra2r5+/ZraZo8ePbZu3RofH3/t2jWGdqsFzMzMli1bVllZmZubm5ycPGfOHPKD46BBg+7fv3/x4sWqqqrk5GSy8CRra+uSkpLq6uqQkBDFDqIpFxcXHo+3cePGV69ePXz4cNeuXY2eEBQU9ODBg40bN5K3DiFUp13d+w36IycnZ+TIkU+ePKmrqystLa2trXV1dSVa0lDfSrGjqKioWL58uZmZWfNfTnUaubm5YrE4Ojqax+OFhYWpWq742kb9Cc2BSag+nJW6devWtGnTfvzxx3HjxhEEIRKJYmJiWpYXBZGRkbdu3ZJKpWVlZcnJyYWFhePHjydXMV4ImjwzWwLQPlVncJqzVaMGrOokRdM4m9PMGml6clS1Oy09Y6rKgKogaT4mNVMrDlv19k7JycnW1tZTp07Nzc2tra0tKiqKiYk5ffp0fHw8QftBhc2lJwhCIBBQX06oorTcPB5PVVSMlFu9XFxc+vTps2DBAqFQ2MYBOz6fT95QVSkfH5+UlJRffvllzZo11EL6qwtprs5TdcWoUsnJyWlpaVwul8PhkD/yHTNmDIfDIWfIIv47+GtpaamjO9goyM8++0wgEKxatYpaqOs72B4q+O23337yySf+/v7dunW7du1acHBwnz59qLV6sIONODk5/fnnn9RDfdrBthyDzX8LVXloRRIIDeSh6cXv5GsXLFjg5eVlamoqEAgCAwNXrlxJvaTFKZJrRVveSCwWf/TRR8bGxr169dq3bx/58/LFixfL5XKpVLp48WJynrlBgwbt27ePfAk1k5yJiYmXl1dOTs6yZcuUFjIiIkLLe6R4d/YRI0Zs2LCBeigWi11cXMj/z5o1S/7f6a7T0tLIe6Z+/PHH1DzWcrl8/vz5FhYWDg4OGRkZ5Icecsq6srKy4cOHGxsbe3t7V1RUqLofPDll7P79+52dnTt16jR27NiFCxcSBGFmZqYYsKur64wZMxSXKE274o6QP6BoNa01S1AjmqrJZLItW7YMHjzYxMTE0dHx+++/J5c3aqhKm5DiF30RERE0BwvVUTg4OBw7dszKyoq601lTc+fOVdyUXC6XSCRkp2FkZOTj43Pz5k3ymUqX0/cnqg5M+sO5kTdv3nTq1KnRMRsdHd26EhQVFX311VeDBw82MzOztLQcMWIENVOm1gpB3xGpyj+DJaBPKbQF/aSzTc/g5HJVZ6tGDViu+rMBTS+htJnRn9eanhxV7Q79GbPpQaQqA6oOE1UfkzTUf7aid3rrdPIvX76MiYlxcnLi8Xjdu3f/5JNP7t27R61leelVdW4EQVC/Km1puWm6RC2XuznlaxHy8l4DAwNzc3Mej+fg4BAeHn706NHKysq3vlejuwH4+fmFhIQ0eo6Li4viw5CQEAMDg4EDB5JzVJN3WqDmzH7z5g35OyD53++lIJfLR4wYoXgXLOrmDC315MkToslc8g8ePCAIIj8/n/61bN5BBweH+vp66mFAQICHh4c+7SBFXysYERFB3TtFLpd7eHisWbNGn3ZwyJAhz58/px4OHz582rRp+rSDLToG23g3gKZ5aHUS5Bo4VIuKikaNGkXdJ5okk8mMjIzWrl1LLVmwYIGtrS318K1tQMfuocla2tkjxdv8MSUsLOzXX3/V5jvqX2tpD1hVtVevXnE4nCtXrjAdyN9o+nBmVQlIbCtES0vAwpTqB23ekk+VtjdO7Z8ctUMThy0bKk5B6RU1JxvqLd+IESMajS0aGBh07NiRx+PZ29t7eHhMnz5d1fcZTe+hSU6GrajR33K1tbUjR45U/HNxwYIFjo6ON2/erKysjIyMtLa2rqqqkqv+Q04uly9cuLB37945OTkSieTKlSt9+vTJysqSy+UnT540NDSsra2l2V+lYy6K926j2Qibd7Bz584RERHFxcWvXr3as2ePoaHhypUr9WkHKfpawYiIiBEjRhQXFz99+nTp0qV9+vRRPO70YAcHDx4cEBBQVFRUVVX17bffcjic8+fP69MONv8YlKvjHpqN8tDqJKg9D7m5ud7e3nl5eeTDjIwM6mu8f/7zn3Z2dpcuXaqpqTlz5kznzp3nzZunKkVvzQlGzVqpnYyaVVVVjRgxQnEkWwv0r7W0B4xXbe7cuSkpKa9fv37+/Pm//vUv8vaIzIbUSDsZNWNzITBqxhJMjaGosXEycnLUHE0ftoyPmqH0ilqajTaWTyqVPnny5PLly0Kh8Keffmo6akbicDhcLtfGxmb69Omq0tto1Ky4uNjCwqKoqIh8ePjwYWprin8clpaW2tnZUUveenWh0usBlV7DGBkZGRgYSLPvPj4+1GYVr3EIDg7++uuv37oRNu9gdnb21KlTu3fvbmZm1q9fv3Xr1ilWTQ92kKTHFXz69GlgYCB5F92goKBnz54prtWDHfzjjz9mzpxpa2tL3kPzxIkTeraDzT8G5W0eNVPMQ1uSoPY80F/8XllZOW/ePDs7OyMjIwcHh6VLl75+/VpVit6aE4yatZIW9qjpj8i0afHixQRBdO3aVfGXXNqhf62lPWC8akVFRUFBQTY2NpaWlpMnTy4sLKQCa0r74dEczuqKkPESkFQVgnGt6FFZklL9w9QYiloap6qTI0u6mtbRdP/J+KiZRkuvc1qaDfryNTQ0lJSU3Lp169dff929e/e6desWLVo0c+bM9957r3///lZWVjwez9bW1tPT09fX99NPP504cWKj2zh06NDB1NR09OjRGRkZb/2FJvmSHTt2kEv+7//+b9q0aYwMYl65coW8c1xLX/j77797enpKJJLmbAQ7qDnYQVWwg4p0fQflcjl1b81Wj5rJdTMPNBqlSKlGOVFyz3JNUHpzdJ2mf3vEHsitLkLVGIcSqB1SqiHkLO/kv9AeoOI6LT4+npwKrbi4uLS0tLS09NmzZ8+fPycflpWVWVpaWltbd+/evVu3bl27drW1tVV8aG1trbi1DRs2fPHFFxKJhCAIHo/H4XD8/PwSEhL69etHtKqp/Oc//+nQocP06dPVuMua09DQEBoampiYaGVl1cyXYAdZBTvYFHaQVVqxg0Tz+l7dygONZqaoUU64mg8MAAAAAAB00unTp2/cuNGjRw8bGxsbGxsfHx/FcTEutwV/TXTr1s3AwIC8T8vcuXOXLl3arVu3tsQ2Y8aMtrxcywwMDH766acWvQQ7yCrYwaawg6zSih1sJt3KA43WpQijZgAAAAAAoNz06dPVdalgt27dOnXq9MUXX4SGhnbs2FEt2wQAANAojJoBAAAAAIDGDRs27MmTJ4aGhkwHAgAA0FzaGzVrNPenHtC/PQJoCxwRjEMJQFckJCQkJCQwHQVoFSquu+Li4tS1KWNjY3VtCgAAQDu0N2qGOZUJzC3dPPjLX0ehbWsI+g2moC/SnLi4OMwNrwcwzX97gPoCjf379x87dsza2tra2triv/h8PvV/U1NTpmNUv5qamlevXtnY2DAdCABoCX6hCQAAAAAAzMOFqAAAjEDf24jiddYYNQMAAAAAAIbFx8fj0jbd8ubNGz6fL5VKm64yMjIyNzdPS0vz8fHRfmBtJ5fL79y58/vvv2dkZGRmZorFYhMTkxcvXnA4nN9//3348OFMBwgA2oNRMwAAAAAAAGgZExOTQYMGXblypdFyMzOzMWPG7N69m8/nMxJYW+zbt2/z5s1Xr141MDCQy+WvX78ml0skEjMzs/Xr12PIDKC9MWA6gJb57rvvJk+ezHQUAMA89AYAoGnoZwAAmqqurhYKhREREc7OzuRFWNQqLpdrZma2ZcsWoVCoi0NmBEH06NEjKyurpqamurqaGjIjCMLU1PSf//zn3LlzGYwNABihY6Nmcrlco7Nir1q1ysvLS3PbZ5a69k6/swS6QqO9ARp5K6CHAf2DTx3tGfo0gEYKCwtTUlLGjRvXrVu3pKSkXr167d+//+jRo9TNc8zMzDw9Pe/evRsYGMhsqG0xatSoTz75RHEokCAILpfr6Oi4bds2pqICAAbp2C80o6KioqKimI4CoN15/fo1j8czNDRkOpD/QW8AwFpVVVUWFhZMR6EG6GcAoJ2rqKg4e/asSCQ6efKkoaGhQCAIDQ09dOiQubk59RxTU9M3b94YGxuvWrXq888/14M7UCcnJx85ckRxSceOHU+ePGlkZMRUSADAIF261iw+Pp7D4RgbGzd6eObMGWdnZwsLi/DwcPI74bCwMA6HY29vv2vXLjs7O1NT0xkzZlRXVxMEMXv2bA6HQ37pV11dzeFwOBwO2S2GhYUtX7780qVL5MKHDx8yt69vV1tbGxUVZWNjY2JiMmbMmFu3bhEt3Lv2kCVQl0uXLllZWc2ZM+fixYsNDQ1Mh/O33qCddwUagh4G2uL9998fPHjwpk2bysvLmY6l9fCpQ5+gTwNovvr6+mvXriUlJY0bN87JyWnr1q2Ojo6nTp0qKChITU0NCAhQHDIjCOKDDz7o27fvtWvXFi5cqAdDZpmZmaNHj3ZxcenYsSO5xNTU9MiRIz179mQ2MABgjFwr1PVGQqHQyMhI8SGXy128eLFYLD537hyHwzl9+jS5atu2baampvPmzauoqLhx44adnV1oaCi5auXKlcOHD6c2YmZmdvjwYaWr1E6NCV+wYIG9vf3169crKirmz59vbW1dVVUlb+He6X2WQF3OnDnTsWNHAwMDMzMzPp//+eef37hxQ/EJ2q+aYm+gc11BizByROhxD9N86ItabcCAAQRBmJqaGhkZeXl57d69++XLl9TauLi4uLg45qJrAV3/1KFpOlRK9GmtpkNVhjYqLS09cOBAUFCQpaWlo6NjZGRkRkaGRCJ56wv//PPP2tpaLUSoaWKxODIy0tbWdteuXXK5fPTo0eQ0bevXr2c6NABgki5da6aUTCZbuHChhYWFj4+Pq6vr7du3qVW1tbVJSUmWlpZDhgyJiorasWPHy5cvW7r9n3/+2crK6s8//1Rr1G0lFos3b94cGxs7dOhQS0vLtWvXSqXSLVu2tGJTepwlUC8ul9vQ0PD69WuxWLxp06aRI0fa2touW7bs/v37TIdGEO21K9AQ9DCgFjU1NVKpNCcnhxykeO+993bv3l1TU8N0XG2CrkYXoU8DUEUmk2VmZsbExHh6evbv3z8tLW3kyJG5ubkFBQUpKSkCgaA5v0m0t7dn1SQerZOWlubm5iaRSPLz84ODgwmC2LlzZ4cOHSZMmICf6gO0czo2r1lTXC6XulyWz+crfnaxsbGhLqwdMGBAXV3dw4cP3d3dW7R9anxRXQGrxd27d2Uy2cCBA8mHJiYmzs7O5M8NWoqdWUpKSlLXpkAtCgoKFOsrk8lkMtnr16/Xr1//3Xff2dnZEQTx7NmzHj16MBVh++wKNETve5jmQ1/UOlKpVPEheTz+9ttvly9fDg8Pd3JyGjp0aH19fYcOHRgKsPXQ1egi9GkAjRQWFor+y9HRUSAQJCYmkpdWMR0aAx4+fDhv3ryysrKjR4++88471PLevXvv27dv/PjxDMYGAGyg8z2j4mfuRj+kV5x9qdFHk0Z//9Nsf8aMGTNmzGhrlOqm9JMWtfvN3zuCrVkSi8Vq3Bq03atXr5gO4S3aZ1egIXrfwzQf+qLW0ePhAHQ1ugh9GgBBEDU1NVlZWSKRSCgUVlRUjBo1ytfXd8uWLZaWlkyHxpi6urrk5OS1a9d+8cUXS5YsafpdzpQpUxgJDABYRedHzWg8f/6cuo1Xfn6+oaGhs7MzQRCdOnV68eIF+Zzi4mLFr8R1ZQJLNzc3Lpebl5dHTj0rkUgKCgqmTZtGtHzv2JmlxMRETb8FtMjZs2dPnTpFPeRyuUZGRp07d549e/asWbP69u3L4XAYvNCMHjsbOZvpfQ/TfOiLWuf48eOKD83NzaVSqbe39+zZs/39/deuXUv8ffhJP+h6a9dj6NOgPSssLBQKhenp6dnZ2UOGDPHz89u9e7e7uzta5vnz58nLn2/evEn+bAIAQCmdn9eMhpmZ2bJlyyorK3Nzc5OTk+fMmUPe8GXQoEH379+/ePFiVVVVcnIyj8ejXmJtbV1SUlJdXR0SErJx40aCrXNP8Pn88PDwNWvW5ObmisXi6OhoHo8XFhZGtHDvCL3OEqiXTCaj7gYQERGRmZn59OnT1atX9+3bl+nQ3gKNvKXQw4BaUHcD2LhxY1lZ2dmzZ4ODg01NTZmOS1PQ2lkLfRq0NxUVFWlpaXPnzu3Vq9e4cePy8/NDQ0OfPXuWmZkZHR3t4eHRzofMKisr586dGxgYuGrVKqFQiCEzAHgLddxS4O3U8kZxcXFU2Hfu3NmwYQP1UCwWu7i4kP+fNWuWXC7ftm1b796909LSevfubWJi8vHHH7969Yra1Pz58y0sLBwcHDIyMszMzAiCIG8PVFZWNnz4cGNjY29v74qKCrlcvn//fktLS3JSp7ZTY8IlEsmiRYusra2NjIx8fHxu3rxJrWr+3ul9lkBdzpw5Y25uPnv27AsXLtTX1zd9gparptgbRERE6FxX0CKMHBF63MM0H/qiVnvnnXcGDRpEDpY1Xasrt+TTg08dmqYrpZSjT2sDHapyOyeTya5evZqYmCgQCDp37kxOVZafn890XOzS0NCwa9eubt26RUZGKh6/AAA0OHKtTD7C4WjpjSg//fTTqlWr/vrrL22+6VtpPw/0kCVoptevX/N4PJobJLG2auxs5C3C2ty+la4nX3czzzjqJ2xKxcfHU//qDV1v7a2jl6WkgSoDCz1//vz8+fNCofD48eMWFha+vr5+fn7vvvtuc+592d7cv38/PDz8xYsXqampHh4eTIcDADpDn+c1AwB1Ib82BwBoDpohMwAAaCOZTJaTk5Oeni4SiR49ejRmzBiBQPDNN99Qd/iFRt68eZOUlLR58+bY2NgFCxYYGOjzJEUAoHb6OWoWFhaWmppKEASHwxGLxfj4rhSyBHoPjZxBSD60H2jt7QGqDIwrLCwU/ZejoyP5G8zRo0dzufr5B526nDhxYv78+Z6enrdu3bKxsWE6HADQPXr7C012Qh6aA1nSRaia5iC3TEHmNQQ/+NIbKGV7gCozq6amJisrSyQSCYXCioqKUaNGkb/B5PP5TIemA4qLi6Ojo7OysjZt2vT+++8zHQ4A6Cp8NQEAAAAAAMAWhYWFQqEwPT09Ozt7yJAhfn5+u3fvdnd3b+f3vmy+hoaGn376KTY29rPPPsvLyzM2NmY6IgDQYRg1AwAAAAAAYFJFRcXZs2dFItGJEyd4PJ5AIAgNDT106JC5uTnToemY3NzcuXPn8ni8Cxcu9OvXj+lwAEDnYdQMAAAAAABA2+rr62/evElOVXblypVhw4YJBILTp0+7ubkxHZpOevXq1ddff71v377ExMTg4GBcmgcAaqG9UTN0WyTkAfQV2rbmILegZxISEhISEpiOAtQDpdR7cXFxTIegb54/f37+/HmhUHj8+HELCwtfX9/o6Oh3333XyMiI6dB02IEDBxYvXjx+/Pi8vLwuXbowHQ4A6A/tjZphTuWmMNW0Uhgg0FFozNqBfkNr0BdpTlxcHCYX1zOYM15foabqIpPJcnJy0tPTRSLRo0ePxowZIxAIvvnmm549ezIdms57+PDhggULnj17tm/fvhEjRjAdDgDoG/xCEwAAAAAAQP0KCwtF/+Xo6CgQCBITE0ePHs3l4q8wNXjz5k1SUtKGDRsWLFgQGxvL4/GYjggA9BD6awAAAAAAAPWoqanJysoSiURCobCiomLUqFG+vr6pqal8Pp/p0PSKUCiMjIwcMGDAzZs37ezsmA4HAPQWRs0AAAAAAADapLCwUCgUpqenZ2dnDxkyxM/Pb/fu3e7u7vi9v9oVFhZGRkY+ePAgNTV1/PjxTIcDAHrOgOkACIIgPD09ORwOh8PZuXMntfDnn3/ev38/c0G1QENDQ0hISHl5ueJCKysrcqdEIlHrNqvraSGUZabtaYH2RtfbvG7RoWzreqqBVXSo5RNo/C2hQ5VFWXVURUVFWlra3Llz7ezsxo0bl5+fHxoa+uzZs8zMzOjoaA8PDwyZqVdtbW1SUtKwYcM8PT1v3bqFITMA0AJWjJoRBLFs2TK5XD579mzy4fbt2w8fPhwQEHDkyBFykMXPz09xAuyOHTuSywMDA7UfbUpKiqGh4cOHD8mHBgYGc+bMmThxolQqpZ5TXl7+6tWrNr6RTqeFUJYZtaQF2g+qzRMEwcJm35w2r0PY3MPoWaqBVdjc8gk0/jZgZ2VlMtk333zTt29fY2PjwYMHHz9+nFyOsuqQ+vr6a9euJSUljRs3zsnJaevWrY6OjqdPny4oKEhNTQ0ICDA3N2c6Rv105syZwYMHZ2ZmXr9+PT4+HrccBQAtkWsF/Rt5eHiQw0Ok4uLizp07P3nyhFpiYWFBEERcXJziqyIiIjIyMtQd6Vu8efMmKCjI29ubIIgHDx4orgoKCvr6668Vl5DDQzRBtoe0yJtkpo1pAXbSRNWatnk5a5p9i9q8emnoAGFtD6N/qYa4uLhG7YpBrG35ckYbfyuwqqxyFlf2yy+/7NatW3Z29osXL9atW8flci9fvkytZVtZ5eyrLINKSkoOHDgQFBRkaWnp6OgYGRmZkZEhkUiYjqtdKCoqCgoKcnZ2PnHiBNOxAEC7w5ZrzRQdOHBg4MCBirdh7tq1q7+//4oVK4RCodKX1NbWRkVF2djYmJiYjBkz5tatWwRBxMfHczgcY2PjM2fOODs7W1hYhIeHy//7HSP5kq5duyq+5K3y8vKCgoKSkpKarvL399+5c6dc4TtM9dLRtBCazwzoq6ZtnmBNs9e/Ns/aHkb/Ug2soq6WT6Dxsww7+zS5XL5hw4b58+d7eXmZm5svWbKkT58+ycnJ1BNQVraRyWSZmZkxMTGenp4DBgxIS0sbOXJkat86gwAAIABJREFUbm5uQUFBSkqKQCDA5U6aVldXl5KSMnToUEdHx9u3b0+cOJHpiACg3WHjqJlIJHJzc1NcQs7tNWjQoMDAwPv37zd9yZIlSw4fPnzq1KmnT58OGDBAIBC8ePEiPj5eKBTW19efPHny6tWrR48eTU1NpabTio6OPn/+fFZWVklJibu7+6RJkyQSyVtj8/T0HDdunNJV/fr1e/z48d27d1u+x82io2khNJ8Z0FdN2zzBmmavf22etT2M/qUaWEVdLZ8gCDR+VmFnn1ZWVlZdXW1vb08tcXR0zM7Oph6irCxRWFi4devWadOmde3adeHChQRBJCYmFhcXHzhwIDQ0tNH3eaA5586dGzp0qEgkunTpUnx8vLGxMdMRAUB7xMZRs6dPn1pZWTVaaGZmduTIER6PN2XKlEYTY4nF4s2bN8fGxg4dOtTS0nLt2rVSqXTLli3kWplMtnDhQgsLCx8fH1dX19u3b5Mv2bRp04oVK5ydnTt37pyYmFheXn7w4MG2hE3G/OzZs7ZshIaOpoXQfGZAXylt84QuNHtdbPM62sPoYqqBVdTb8gk0ftZgZ59mZWVlbGz8119/UUuePHlSUVGh+AQCZWVITU2NSCSKiYnp16+ft7e3SCTy9fUtKCi4evVqYmKiQCDgcrlMx9iOFBcXBwcHBwcHkyPXDg4OTEcEAO0XG0fNxGKxoaFh0+X29vYHDx588ODB7NmzFa9dv3v3rkwmGzhwIPnQxMTE2dmZukiey+VS3wjx+fyXL1+SL6mrq/P19SVngeXxeBKJ5M6dO20Jm8fjEQRRWVnZlo3Q0NG0EJrPDOgrVW2eYH2z18U2r6M9jC6mGlhFvS2fQONnDXb2aQYGBp9++unGjRsvXbpUXV29cePGBw8eKF4+g7JqX2FhYUpKyrhx47p27RofH8/n8/fs2UNeVhYcHMzn85kOsN2RyWQpKSkDBw7k8/n5+fn+/v5MRwQA7R0bvzPh8/l1dXVKV/n4+KSkpERERKxZs4ZaqHT2B+o2zx06dGi6kHxJTk7O8OHD1RV2bW0tQRCWlpbq2mAjOpoWQvOZAX1F0+YJdjd7XWzzOtrD6GKqgVXU2/IJNH7WYG2f9u233xoZGfn7+4vF4oCAgODgYMVRV5RVOyoqKs6ePSsSiU6cOMHj8QQCQWho6KFDh3DvS8ZdvHgxIiLC2tr64sWLTafpAABgBBuvNbO1tS0vL1e1dt68eSEhIcuXL79w4QK5xM3Njcvl5uXlkQ8lEklBQQH1baFSbm5uhoaGzZzqvpnImHv06KHGbSrS0bQQms8M6Cv6Nk+wuNnrYpvX0R5GF1MNrKKFlk+g8TOBtX3a0qVLx44d++TJk+rq6h07dly9enXy5MnUWpRVc+rr669du5aUlDRu3DgnJ6etW7c6OjqePn26oKAgNTU1ICAAQ2bMKikpCQ4O/uSTT5YsWXLmzBkMmQEAe7Bx1EwgENBPg7pp0yZvb29yUgmCIPh8fnh4+Jo1a3Jzc8VicXR0NI/HCwsLo9kCn8+PiIhYvXr1pUuXpFLp1atX+/btS83GeurUKR6PR3ORi1L5+fm9evVydXVt0auaT0fTQmg+M6Cv3trmCQ03+3bV5pntYdpVqoFVtNDyCTR+JrC5T1uzZk1JScmzZ8+++OKLly9fzp8/n1qFsqpdaWlpWlpacHCwtbX1tGnTnj17Fh0dXVpampGRER0djaEZNmhoaNi9e/fQoUP5fP6dO3eCg4OZjggA4O/kWkH/Rh4eHsuWLaMeFhcXW1hYFBUVyeXyw4cPU6FmZGRQzyktLbWzs6OWSCSSRYsWWVtbGxkZ+fj43Lx5Uy6Xb9iwgXqtWCx2cXEh/z9r1iy5XC6VShcvXty1a1djY+NBgwbt27eP2nhkZGRgYKDSUBt9AOrSpQu1Kjg4+Ouvv1Z8MjnRrGLY7TAtTTPTxrQAO2miaoptXs5Es1dXm1cvDR0gzPYw7SrVEBcXFxcXx3QU/5+6Wr5cvxp/K7CqrHIW92lPnz4NDAzk8/ldunQJCgp69uyZ4lq2lVXOvso2R11d3cWLF6Ojoz08PKysrAICAlJTU588ecJ0XKDE1atX33nnHR8fn7y8PKZjAQBQji2jZuRHkB07dpBL/u///m/atGn19fXaCO7vrly5Qt5ZqUWv+v333z09PSUSCbWkS5cuTT+fNaL3aZE3yUzb0wLspKGq6UGbVzvNHSBMZbsdprqdY9sf4ehn1IJtZZWjT1MTFlZWFeq3lnw+38PDIzo6OiMjo66ujum4QLmysrJ//etftra2//nPf5iOBQCADkeubPZTteNwWvxG//nPfzp06DB9+nQNhaRGDQ0NoaGhiYmJTe9xTk+/00K0NjOtSAswTnNVaw9tvkU0eoDoULZ1PdXtWXx8PPUvS+hQyye00vhbgYVlJXSqsuwsK8HWylJqamqysrJEItGxY8cqKytHjRrl6+vr5+eHe1+ymUwm27x586pVq2bOnBkfH48Z5QCA5dg7atYeIC1KIS26CFXTGqRaa5BqDWH5H+HQOiirvmJnZQsLC4VCYXp6enZ29pAhQ/z8/AQCgbu7u+INbYGdzp079/nnn3fp0iUlJeWtt1IBAGADLtMBAAAAAAAA0KmoqDh79qxIJDpx4gSPxxMIBKGhoYcOHcKVSrqiqKgoNjb23Llzq1atwpT/AKBDMGoGAAAAAACsU19ff/PmTZFIJBKJrly5MmzYMIFAcPr0adz7Ure8efPmhx9+WL9+/bx587Zu3WpsbMx0RAAALYBRMwAAAAAAYIvS0tILFy6Qv8Hk8/m+vr7R0dHvvvuukZER06FBiwmFws8//7x///6XL1+2t7dnOhwAgBbDqBkAAAAAADBJJpPl5OSkp6eLRKJHjx6NGTNGIBB88803PXv2ZDo0aKW7d+8uXLjw0aNHW7ZsGT9+PNPhAAC0kvbuBqCFdwG9gRm4dQ6OcdBL6Is0IT4+PiEhgekoAKC54uLiNHc3gMLCQvIHmBkZGU5OTgKBQCAQjB49msvFV/s6rKqqKi4u7ueff162bFlERASqCQA6DTcIAwAAAAAALampqcnKyhKJRMeOHausrBw1apSvr6+fnx+fz2c6NGirhoaGvXv3RkdHjxs3bv369dbW1kxHBADQVhj4BwAAAAAAzSosLCSnKsvOzh4yZIifn9+ePXvc3d1xubreuHz5cmRkpJGR0alTpwYPHsx0OAAA6oFrzQAAAAAAQP0qKirOnj0rEolOnDjB4/HIH2BOmDChU6dOTIcG6vTs2bOYmJizZ89+8803QUFBGAkFAH2Ca80AAAAAAEA96uvrb968Sc5WduXKlWHDhgkEgtOnT7u5uTEdGqhfXV3djz/+uHLlypkzZ965cwfjoQCgfzBqBgAAAAAAbVJaWnrhwgXyN5h8Pt/X1zc6Ovrdd981MjJiOjTQFJFIFBkZ6eTkdPnyZUdHR6bDAQDQCPxCEwAAAAAAWkwmk+Xk5KSnp4tEokePHo0ZM0YgEEyaNMnW1pbp0ECzHjx4sHDhwocPH37//fcTJ05kOhwAAA3CqBkAAAAAADRXYWEh+QPMjIwMJycncray0aNHc7n4FYv+e/369bp16zZv3hwVFbVo0SIej8d0RAAAmoVzGwAAAAAA0KmpqcnKyhKJRMeOHausrBw1apSvr29qaiqfz2c6NNASuVy+Z8+emJgYgUBw69YtGxsbpiMCANAGjJoBAAAAAIAShYWF5FRl2dnZQ4YM8fPz27Nnj7u7O26S2N5cu3YtMjKytrb20KFD//jHP5gOBwBAe/ALTQAAAAAA+P8qKirOnj0rEolOnDjB4/HIH2BOmDABt0dsnyoqKlasWHHo0KGvv/76s88+MzAwYDoiAACtwrVmAAAAAADtWn19/c2bN8nZyq5cuTJs2DBfX98vv/zS3t6e6dCAMbW1tT/88ENSUtKnn356584dDJsCQPuEUTMAAAAAgPaotLT0woUL5G8wu3fv7ufnFx0dPWrUKEzxDkeOHFm6dKmrq2tWVlafPn2YDgcAgDH4hSYAAAAAQHshk8lycnLS09NFItGjR4/GjBkjEAgmTZpka2vLdGjACnfu3Fm8ePGff/65fv36Dz74gOlwAAAYhlEzAAAAAAA9V1hYSP4AMyMjw8nJSSAQ+Pr6ent7Y5oqoJBTmO3bty82NjYiIoLLxc+SAADwC00AAAAAAH1UU1OTlZUlEomOHTtWWVk5fvz4gICA1NRUPp/PdGjALnV1dT/++OOqVatmzJhx7949CwsLpiMCAGALjJoBAAAAAOiPwsJCcqoycl5/gUCwZ88ed3d3DofDdGjARkKhcNGiRQ4ODufPn+/Xrx/T4QAAsAt+oQkAAAAAoNsqKirOnj0rEolOnDjB4/EEAoFAIJgwYQLuewg0rl+/HhUV9fz58/Xr10+cOJHpcAAA2AijZgAAAAAAuqe+vv7mzZvkbGXkZWW+vr4ffvihvb0906EB2xUXF8fHxx85ciQ2Nnb+/PkdOnRgOiIAAJZSz6gZrvcGLcNoL9ugEwC9hK5GE+Lj4xMSEpiOAgCaKy4uLj4+nukoQG1qa2s3b968cuXKmTNnrlixonPnzkxHBADAamqb1wx/WqgXh4PLAFXCAA07ocUyC52G2qGr0Rz8Ed6ukLVGxXUUCqdP5HL5gQMHoqOjPT09L1++7OjoyHREAAA6AHcDAAAAAAAA0GdZWVmLFy+uq6vbtWuXj48P0+EAAOgMA6YDAAAAAAAAAI14/PhxcHDw9OnT58yZc+nSJQyZAQC0CEbNAAAAAAAA9E1VVVVMTIy7u3uPHj3u3LkTGhqKWf8BAFqK7aNmYWFhHA6n7XcCUtd2AEDLvvvuu8mTJ6t3m23sENpnf6KJQrRa+ywBAL2SkhIOh8PhcPbt20cuYdVhC+qFcgO9urq6rVu3urm5PXv2LC8vLzExsWPHjkwHBQCgk9g+arZly5Zt27ZpfzurVq3y8vJq+/tqQmZmJue/Ro4cqYm3aLT7WnhHaIeaeZTJ5XK1T3Lfxo5FXf0SvZKSkqVLl9rZ2ZmYmPTv33/r1q2t3pRMJktISOjbt6+JiUmPHj3mzJmTk5NDrdVOIdTbjWinBKAT2Hy+1rJu3brJ5XIbGxtqiSb6T0KtvRPp5cuXy5Ytc3FxMTY27tGjh0AgSE1Nraqqon8VS0qv2Lkp4nI1O3ew1soNukgkEg0dOjQtLe3XX3/dvXt3t27dmI4IAECHsX3UDJoaOXKkXC7v0qXLunXrMjMz9fIdAShRUVFCoZDpKBiwZMmSnJycCxculJeXz5s3b+7cub/99lvrNpWQkLB169YdO3aIxeIbN27Y2tr+4x//qK6ubtFG2lgIdCMA2qeh/lONvRNBEBUVFV5eXlevXj1w4MDLly9zc3MDAwOXLl0aExOjxpg1R7FzkytwdXXVciTt9nQJiq5duzZ69OjIyMjExMSMjIxBgwYxHREAgM7TxqhZbW1tVFRU165dTUxMxowZc+vWLYIg4uPjORyOsbGxSCRycHCwtLRcu3ZtZWXlhAkTOnbsOG7cuPLycsWNHDx40N7e3tTUdMaMGdQfe3fv3p0yZQqfz7ezs/viiy/q6urI5dTGz5w54+rqamBgMGXKFGpTRUVF1DeBeXl5TQMOCwtbvnz5pUuXyOc8fPiQ2gsbGxvFvSAIwsvLi3zaV199RRDE0aNHnZycyFUDBgzgcDienp6K8Tg7O1tYWISHh6vr+0CajVM/Ytq1a5ednZ1i9mbPns3hcMgvaaurq8ldOHLkiKrdp9G0CtQGORxOeno6QRDOzs7Uz6mUtgfibVUDnZaenj5w4EATE5OhQ4f+8ssvhLJmprQBUAsJ2qZOEERVVZW/v7+pqam9vf3+/fu7devG4XCWLFnSzAhVHeCqllMU+xNPT0+aw0rVwUjjm2++cXBwMDMzCw8P53K5BQUFzc3434lEooCAgBEjRhgbG9vY2Kxatapv377kKpYUgibPzJYAtI+quIWFxbhx486fP08uV3rGpzlfNz3L0DROpc2s6bEgEAhozm40u6PqI5DSg0hVBlQdC9R+OTo6Kg6aaPSwVVfvRBDEokWLKisrjxw5MnjwYB6PZ21tPXv27HXr1lFP0NHSU58wW1Fumn6PkXKDTigqKpo7d+6kSZOmTp16+/ZtX19fpiMCANAXcnWg387ChQvd3d0fPHhQVVUVFRXVs2fPN2/eyOVyoVDI5XKjo6OrqqrS0tIIgvj444//+OOPp0+f9u3b98svvyRfvm3bNnNz87CwsPLy8hs3btjZ2YWGhpKrxo8fn56eLpFI7t+/7+HhkZiYSL2pUCjs0KHD3Llzy8rKDh8+/OGHH27btq13795yubyhoWH+/PlbtmyhiXnlypXDhw9XXLJgwQJ7e/vr169XVFTMnz/f2tq6qqqKXOXu7p6QkED+/7PPPiMIIj8/Xy6Xy2SyESNGUPFwudzFixeLxeJz585xOJzTp0+3OqXyv3+rSbPxbdu2mZqazps3r6KiolH2Gu2jmZnZ4cOHVe2+XNn3qCSlVaisrDQyMkpLSyOfI5FIPDw8Ghoa5Krbg1xZ1VqXHNA+mqK8ePHCxMTk9OnTUqn07t27zs7OZWVlcmXNTGkDEAqFRkZG1BNUNfWZM2f26dMnLy+vvLw8JCTE2Nj4559/pgmY6hBIqg5wVctV9Sc0hxXNwUijoaGhtLT066+/dnJyKi8vp3kmTQmmTZvWv3//Z8+eKV2rzUKo6kZoOlgGS4CuRkPi4uLi4uJUrV2wYIGDg8P169clEsm5c+e6d+9OLld1xm/agFWdZWgap6pm1vRYoDm7KUX/EUjpQaQqA6qCpParrKwsJCTEzMyM2i8N9Z+k5vdONBV//fo1j8eLioqieblOlF6xc7ty5crMmTMVA2tpuWm6RO2Xm/6ABTaorq6Oi4vr0qVLdHT0ixcvmA4HAEDfaHzUrLKy0tDQMD09nXxYW1trbGy8Z88euVxOfkVWVFRErjI3N4+Pjyf/v2jRookTJ5L/37Ztm4GBgVgsJh9+9913hoaGTU8JycnJo0ePph6SG3/8+DG1hPwTSyaTffbZZ7t27aLfo0YfxSorK7lc7tatW8mHNTU15ubm1Oe2+Ph4d3d3uVze0NAwbNiwHj16kJ+czp07Fx0drRjPkydPyIdubm7r16+nCaClo2aqNr5t2zYul/vq1SvyoWL21DVqpkixCh999BFVxH379pEfuWjag1xZ1ZTCn7IsRFOUu3fvEgRx6tSpRsuVDtY0bQCN/gxQ2tSfP39uYGCwfft2cnllZSVBEM0fNVN1gNMc+Kr6E/ohG1UHI42PPvqIIIhBgwbduHGD/pk0JXjw4IGbmxuPx5s0adL3339fWFiouFabhVDajdDkmdkSoKvREJo/wisqKrhc7rZt2+i3oHiuaXq+VnqWoWmcNM1M6bGg9Oym1Fs/AjU9iFRlQFWQjfartLRU8aDTUP9J5aGZvRNNxXNzcwmC2Lhx41vfjsTa0nfp0kXxO+mmo2bNLzdNVIyUG6NmbFZXV7dly5bu3bvPnj2b+pMKAADUS+O/0Lx7925dXZ2vry95WTuPx5NIJHfu3CHXcrlcW1tb8v+dOnWiLnQ3Nzd/+fIltRHywnXy/wMGDKirqyMvxc/IyHjnnXfMzMw4HE5UVFSjH3UaGhra2dkpLpHJZDNnzty/f/+oUaNauhcymWzgwIHkQxMTE2dnZ+qC+cmTJ1+/fr2oqOj69euenp5+fn7k1ftHjx798MMPqY1wudyePXuS/+fz+Yo72HY0G7exsaFumqOYPXVRVYXg4ODTp08/ffqUIIgdO3YEBwcTb2sPhLKqga7r27fvpEmTJkyY4Orqum7dOrFYTPPktzYApU39/v37DQ0N/fr1o5Y3+gOGnqoDnP7Ab0V/0oqD8eDBg5WVlQsWLBg5cmRGRkbzd0qRs7Pz7du3jx075ujomJqa6uTkNHPmzNraWpqXaLMQNHlmQwlAm+7duyeTyQYMGNB0Ff0Zn6LqLEPTOOmbWdNjQenZrUXBkGuVHkSqMqAqyEb71bVrV+rzUlPq7T/V0juROBwOzVpdKb3itWZNw2t+uWmiYrDcwEJHjx4dNGhQWlraiRMnduzYQf1JBQAA6qXxUTO5XE4QRE5OjuJY3erVq8m1HTp0UHxyo4f/i9Lgf3HK/zsvw/Pnz6dMmfLee+8VFxfL5fINGzbI/z5TmOKrqJcEBgZ6eXkFBQU1NDS0dC8aoT7kDR06tFevXseOHUtPT//www8nT578+++/V1VVXbp0SfHuTop7R/8BsRVoNq64p412RPGhTCZrxfvSVGHixIl8Pn/Xrl1PnjyRSqWOjo7E29oDoaxqoOs4HI5QKDx+/Lijo+OyZcvc3NweP36s6slvbQBKm3rTI7S+vr75Eao6wOkPfFX9Cc1hRXMw0uDz+Z999plAIFi1alUzX9JUhw4d3n///R9++CE/P/+33347dOjQ9u3baZ6vzULQ5JklJQCtUVWUt57xG22h6VmGpnHSN7Omx4LSs1uLgiHXNvMgog+y6XJVH6Wa/47N7z/b3js5OzsbGRnRTIumi6X39PTcu3dvo4XNL3eLukRtlhvY4/Lly6NHj46NjU1ISBCJREOGDGE6IgAAfabxEQo3NzdDQ8Om8ze3SGlpKTVnc35+vqGhobOzc35+fk1NTUhIiLm5OUEQ9NdNkHr06OHr67tz5847d+4kJibSPLPRwJObmxuXy6UmdpVIJAUFBdTXgARB+Pn5HT169Pz582PGjBk7dqyRkdG3337bv39/tY+OtcLz58+p27dT2SMIolOnTi9evCCXFxcXS6VS6iXNDNvV1ZWmCoaGhh9//PHOnTt37twZGBhILlRLewCdw+FwPvjggxMnThQUFNTV1ZG/HFHj0eHi4mJgYJCfn08+LCsro9p8c6g6wOkPfKX9Cc1hRag+GJVydHRUHOLh8XivX79u/k4p8vX1VTzofHx8evXqVVJSQj5kthCurq40eWa2BKB9jSpOoTnXND1fKz3L0DTOt57iG1F6dlO1Oy095anKgKogG+2XWCyuqKho/tsRrTps1dg7kffl+Pe///3mzRvF5YGBgWRudbT0zaS03DRRMVJuYJX79+9PmzbN399/xowZt27dCggIYDoiAAD9p/FRMz6fHxERsXr16kuXLkml0qtXr/bt2zc7O7tFGzE0NIyOjhaLxbm5ucnJyXPmzDE3N3dxceHxeBs3bnz16tXDhw937drVzK316NFj69at8fHx165dU/Uca2vrkpKS6urqkJCQjRs38vn88PDwNWvW5ObmisXi6OhoHo8XFhZGPX/y5Mm//fZb165deTyekZHR+PHj161bx5JbQJqZmS1btqyyslIxewRBDBo06P79+xcvXqyqqkpOTubxeNRLGu0+zcbpqxAUFPTgwYONGzdSJ3W1tAfQLTk5OSNHjnzy5EldXV1paWltba2rqyvRkmb2VtbW1p988kliYmJ+fn5FRcXy5cvNzMya/3JVB/hbD3yiSX9Cc1gRqg9GpSorKyMjI8kU7d2798iRI23pUiIjI2/duiWVSsvKypKTkwsLC8ePH0+uYrwQNHlmtgSgfVTFb968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\n", "text/plain": [ "" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "preprocessed_inputs_cat = layers.Concatenate()(preprocessed_inputs)\n", "\n", "titanic_preprocessing = tf.keras.Model(inputs, preprocessed_inputs_cat)\n", "\n", "tf.keras.utils.plot_model(model = titanic_preprocessing , rankdir=\"LR\", dpi=72, show_shapes=True)" ] }, { "cell_type": "markdown", "metadata": { "id": "PNHxrNW8vdda" }, "source": [ "이 모델은 입력 전처리만 포함합니다. 이를 실행하여 데이터에 어떤 영향을 미치는지 확인할 수 있습니다. Keras 모델은 Pandas DataFrames를 자동으로 변환하지 않습니다. 왜냐하면 하나의 텐서로 변환해야 하는지 아니면 텐서 사전으로 변환해야 하는지가 명확하지 않기 때문입니다. 따라서 이를 텐서 사전으로 변환합니다." ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.585438Z", "iopub.status.busy": "2022-12-14T21:07:16.585028Z", "iopub.status.idle": "2022-12-14T21:07:16.589734Z", "shell.execute_reply": "2022-12-14T21:07:16.589035Z" }, "id": "5YjdYyMEacwQ" }, "outputs": [], "source": [ "titanic_features_dict = {name: np.array(value) \n", " for name, value in titanic_features.items()}" ] }, { "cell_type": "markdown", "metadata": { "id": "0nKJYoPByada" }, "source": [ "첫 번째 훈련 예제를 잘라서 이 전처리 모델로 전달하면 숫자 특성과 문자열 원-핫이 모두 함께 연결된 것을 볼 수 있습니다." ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.593343Z", "iopub.status.busy": "2022-12-14T21:07:16.592806Z", "iopub.status.idle": "2022-12-14T21:07:16.657037Z", "shell.execute_reply": "2022-12-14T21:07:16.656346Z" }, "id": "SjnmU8PSv8T3" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n", "titanic_preprocessing(features_dict)" ] }, { "cell_type": "markdown", "metadata": { "id": "qkBf4LvmzMDp" }, "source": [ "이제 이 위에 모델을 빌드합니다." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.661020Z", "iopub.status.busy": "2022-12-14T21:07:16.660467Z", "iopub.status.idle": "2022-12-14T21:07:16.807941Z", "shell.execute_reply": "2022-12-14T21:07:16.807113Z" }, "id": "coIPtGaCzUV7" }, "outputs": [], "source": [ "def titanic_model(preprocessing_head, inputs):\n", " body = tf.keras.Sequential([\n", " layers.Dense(64),\n", " layers.Dense(1)\n", " ])\n", "\n", " preprocessed_inputs = preprocessing_head(inputs)\n", " result = body(preprocessed_inputs)\n", " model = tf.keras.Model(inputs, result)\n", "\n", " model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", " optimizer=tf.keras.optimizers.Adam())\n", " return model\n", "\n", "titanic_model = titanic_model(titanic_preprocessing, inputs)" ] }, { "cell_type": "markdown", "metadata": { "id": "LK5uBQQF2KbZ" }, "source": [ "모델을 훈련할 때 특성 사전을 `x`로, 레이블을 `y`로 전달합니다." ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:16.812779Z", "iopub.status.busy": "2022-12-14T21:07:16.812177Z", "iopub.status.idle": "2022-12-14T21:07:18.973192Z", "shell.execute_reply": "2022-12-14T21:07:18.972491Z" }, "id": "D1gVfwJ61ejz" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 22s - loss: 0.6991" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.5924 " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 1s 5ms/step - loss: 0.5686\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.6472" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.5246" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.5040\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.4836" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "14/20 [====================>.........] - ETA: 0s - loss: 0.4718" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4742\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.3842" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4375" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4549\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.6322" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4425" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4436\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 6/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.3895" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "14/20 [====================>.........] - ETA: 0s - loss: 0.4203" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4349\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 7/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.3454" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "14/20 [====================>.........] - ETA: 0s - loss: 0.4434" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4297\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 8/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.4162" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4326" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4266\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 9/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.4274" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4350" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4252\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 10/10\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.3639" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "14/20 [====================>.........] - ETA: 0s - loss: 0.4104" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4230\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "titanic_model.fit(x=titanic_features_dict, y=titanic_labels, epochs=10)" ] }, { "cell_type": "markdown", "metadata": { "id": "LxgJarZk3bfH" }, "source": [ "전처리는 모델의 일부이므로 모델을 저장하고 다른 곳에 다시 로드하여도 동일한 결과를 얻을 수 있습니다." ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:18.977169Z", "iopub.status.busy": "2022-12-14T21:07:18.976474Z", "iopub.status.idle": "2022-12-14T21:07:22.747279Z", "shell.execute_reply": "2022-12-14T21:07:22.746438Z" }, "id": "Ay-8ymNA2ZCh" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: test/assets\n" ] } ], "source": [ "titanic_model.save('test')\n", "reloaded = tf.keras.models.load_model('test')" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.755636Z", "iopub.status.busy": "2022-12-14T21:07:22.754958Z", "iopub.status.idle": "2022-12-14T21:07:22.816598Z", "shell.execute_reply": "2022-12-14T21:07:22.815852Z" }, "id": "Qm6jMTpD20lK" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([[-1.923]], shape=(1, 1), dtype=float32)\n", "tf.Tensor([[-1.923]], shape=(1, 1), dtype=float32)\n" ] } ], "source": [ "features_dict = {name:values[:1] for name, values in titanic_features_dict.items()}\n", "\n", "before = titanic_model(features_dict)\n", "after = reloaded(features_dict)\n", "assert (before-after)<1e-3\n", "print(before)\n", "print(after)" ] }, { "cell_type": "markdown", "metadata": { "id": "7VsPlxIRZpXf" }, "source": [ "## tf.data 사용하기\n" ] }, { "cell_type": "markdown", "metadata": { "id": "NyVDCwGzR5HW" }, "source": [ "이전 섹션에서는 모델을 훈련하는 동안 모델의 내장 데이터 셔플링 및 배치에 의존했습니다.\n", "\n", "입력 데이터 파이프라인을 더 많이 제어해야 하거나 메모리에 쉽게 맞출 수 없는 데이터를 사용해야 하는 경우 `tf.data`를 사용합니다.\n", "\n", "더 많은 예를 보려면 [`tf.data`: TensorFlow 입력 파이프라인 빌드](../../guide/data.ipynb) 가이드를 참조하세요." ] }, { "cell_type": "markdown", "metadata": { "id": "gP5Y1jM2Sor0" }, "source": [ "### 인메모리 데이터에서\n", "\n", "CSV 데이터에 `tf.data`를 적용하는 첫 번째 예제로 다음 코드를 고려할 경우 이전 섹션의 특성 사전을 수동으로 분할합니다. 각 인덱스에는 각 특성에 대해 이러한 인덱스를 사용합니다.\n" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.820772Z", "iopub.status.busy": "2022-12-14T21:07:22.820032Z", "iopub.status.idle": "2022-12-14T21:07:22.824527Z", "shell.execute_reply": "2022-12-14T21:07:22.823784Z" }, "id": "i8wE-MVuVu7_" }, "outputs": [], "source": [ "import itertools\n", "\n", "def slices(features):\n", " for i in itertools.count():\n", " # For each feature take index `i`\n", " example = {name:values[i] for name, values in features.items()}\n", " yield example" ] }, { "cell_type": "markdown", "metadata": { "id": "cQ3RTbS9YEal" }, "source": [ "이것을 실행하고 첫 번째 예제를 출력합니다." ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.828213Z", "iopub.status.busy": "2022-12-14T21:07:22.827526Z", "iopub.status.idle": "2022-12-14T21:07:22.831826Z", "shell.execute_reply": "2022-12-14T21:07:22.831175Z" }, "id": "Wwq8XK88WwFk" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sex : male\n", "age : 22.0\n", "n_siblings_spouses : 1\n", "parch : 0\n", "fare : 7.25\n", "class : Third\n", "deck : unknown\n", "embark_town : Southampton\n", "alone : n\n" ] } ], "source": [ "for example in slices(titanic_features_dict):\n", " for name, value in example.items():\n", " print(f\"{name:19s}: {value}\")\n", " break" ] }, { "cell_type": "markdown", "metadata": { "id": "vvp8Dct6YOIE" }, "source": [ "메모리 데이터 로더에서 가장 기본적인 `tf.data.Dataset`은 `Dataset.from_tensor_slices` 생성자입니다. 이것은 TensorFlow에서 위의 `slices` 함수의 일반화된 버전을 구현하는 `tf.data.Dataset`를 반환합니다." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.835258Z", "iopub.status.busy": "2022-12-14T21:07:22.834784Z", "iopub.status.idle": "2022-12-14T21:07:22.842976Z", "shell.execute_reply": "2022-12-14T21:07:22.842328Z" }, "id": "2gEJthslYxeV" }, "outputs": [], "source": [ "features_ds = tf.data.Dataset.from_tensor_slices(titanic_features_dict)" ] }, { "cell_type": "markdown", "metadata": { "id": "-ZC0rTpMZMZK" }, "source": [ "다른 Python iterable과 마찬가지로 `tf.data.Dataset`에 대해 반복할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.846608Z", "iopub.status.busy": "2022-12-14T21:07:22.846038Z", "iopub.status.idle": "2022-12-14T21:07:22.860781Z", "shell.execute_reply": "2022-12-14T21:07:22.860117Z" }, "id": "gOHbiefaY4ag" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sex : b'male'\n", "age : 22.0\n", "n_siblings_spouses : 1\n", "parch : 0\n", "fare : 7.25\n", "class : b'Third'\n", "deck : b'unknown'\n", "embark_town : b'Southampton'\n", "alone : b'n'\n" ] } ], "source": [ "for example in features_ds:\n", " for name, value in example.items():\n", " print(f\"{name:19s}: {value}\")\n", " break" ] }, { "cell_type": "markdown", "metadata": { "id": "uwcFoVJWZY5F" }, "source": [ "`from_tensor_slices` 함수는 모든 구조의 중첩된 사전 또는 튜플을 처리할 수 있습니다. 다음 코드는 `(features_dict, labels)` 쌍의 데이터세트를 만듭니다." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.864594Z", "iopub.status.busy": "2022-12-14T21:07:22.863880Z", "iopub.status.idle": "2022-12-14T21:07:22.873521Z", "shell.execute_reply": "2022-12-14T21:07:22.872887Z" }, "id": "xIHGBy76Zcrx" }, "outputs": [], "source": [ "titanic_ds = tf.data.Dataset.from_tensor_slices((titanic_features_dict, titanic_labels))" ] }, { "cell_type": "markdown", "metadata": { "id": "gQwxitt8c2GK" }, "source": [ "이 `Dataset`를 사용하여 모델을 훈련하려면 최소한 데이터를 `shuffle`하고 `batch` 처리해야 합니다." ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.877374Z", "iopub.status.busy": "2022-12-14T21:07:22.876807Z", "iopub.status.idle": "2022-12-14T21:07:22.886826Z", "shell.execute_reply": "2022-12-14T21:07:22.886169Z" }, "id": "SbJcbldhddeC" }, "outputs": [], "source": [ "titanic_batches = titanic_ds.shuffle(len(titanic_labels)).batch(32)" ] }, { "cell_type": "markdown", "metadata": { "id": "-4FRqhRFuoJx" }, "source": [ "`features` 및 `labels`를 `Model.fit`에 전달하는 대신 데이터세트를 전달합니다." ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:22.890287Z", "iopub.status.busy": "2022-12-14T21:07:22.889802Z", "iopub.status.idle": "2022-12-14T21:07:23.811947Z", "shell.execute_reply": "2022-12-14T21:07:23.811084Z" }, "id": "8yXkNPumdBtB" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 8s - loss: 0.4248" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4374" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 1s 4ms/step - loss: 0.4216\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 2/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.4226" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4476" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4205\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 3/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.3747" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.3898" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4214\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 4/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.4503" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4247" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4193\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 5/5\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 1/20 [>.............................] - ETA: 0s - loss: 0.3207" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "13/20 [==================>...........] - ETA: 0s - loss: 0.4287" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "20/20 [==============================] - 0s 4ms/step - loss: 0.4196\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "titanic_model.fit(titanic_batches, epochs=5)" ] }, { "cell_type": "markdown", "metadata": { "id": "qXuibiv9exT7" }, "source": [ "### 단일 파일로부터\n", "\n", "지금까지 이 튜토리얼은 인메모리 데이터로 작업했습니다. `tf.data`는 데이터 파이프라인을 빌드하기 위한 확장성이 뛰어난 툴킷이며 CSV 파일 로드를 처리하는 몇 가지 기능을 제공합니다. " ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:23.815905Z", "iopub.status.busy": "2022-12-14T21:07:23.815313Z", "iopub.status.idle": "2022-12-14T21:07:23.828049Z", "shell.execute_reply": "2022-12-14T21:07:23.827397Z" }, "id": "Ncf5t6tgL5ZI" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://storage.googleapis.com/tf-datasets/titanic/train.csv\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 8192/30874 [======>.......................] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "30874/30874 [==============================] - 0s 0us/step\n" ] } ], "source": [ "titanic_file_path = tf.keras.utils.get_file(\"train.csv\", \"https://storage.googleapis.com/tf-datasets/titanic/train.csv\")" ] }, { "cell_type": "markdown", "metadata": { "id": "t4N-plO4tDXd" }, "source": [ "이제 파일에서 CSV 데이터를 읽고 `tf.data.Dataset`를 작성합니다.\n", "\n", "(전체 설명서는 `tf.data.experimental.make_csv_dataset`를 참조하세요.)\n" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:23.831987Z", "iopub.status.busy": "2022-12-14T21:07:23.831336Z", "iopub.status.idle": "2022-12-14T21:07:23.891075Z", "shell.execute_reply": "2022-12-14T21:07:23.890364Z" }, "id": "yIbUscB9sqha" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/data/experimental/ops/readers.py:572: ignore_errors (from tensorflow.python.data.experimental.ops.error_ops) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use `tf.data.Dataset.ignore_errors` instead.\n" ] } ], "source": [ "titanic_csv_ds = tf.data.experimental.make_csv_dataset(\n", " titanic_file_path,\n", " batch_size=5, # Artificially small to make examples easier to show.\n", " label_name='survived',\n", " num_epochs=1,\n", " ignore_errors=True,)" ] }, { "cell_type": "markdown", "metadata": { "id": "Sf3v3BKgy4AG" }, "source": [ "이 함수에는 많은 편리한 특성이 포함되어 있어 데이터 작업이 용이합니다. 여기에는 다음이 포함되어 있습니다.\n", "\n", "- 열 헤더를 사전 키로 사용.\n", "- 각 열의 유형을 자동으로 결정.\n", "\n", "주의: `tf.data.experimental.make_csv_dataset`에서 `num_epochs` 인수를 설정해야 합니다. 그렇지 않으면 `tf.data.Dataset`의 기본 동작은 루프를 무한히 반복하는 것입니다." ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:23.895445Z", "iopub.status.busy": "2022-12-14T21:07:23.894824Z", "iopub.status.idle": "2022-12-14T21:07:23.948114Z", "shell.execute_reply": "2022-12-14T21:07:23.947357Z" }, "id": "v4oMO9MIxgTG" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "sex : [b'male' b'female' b'male' b'female' b'male']\n", "age : [26. 42. 32. 21. 46.]\n", "n_siblings_spouses : [0 0 0 0 0]\n", "parch : [0 0 0 0 0]\n", "fare : [ 8.05 13. 8.05 7.75 79.2 ]\n", "class : [b'Third' b'Second' b'Third' b'Third' b'First']\n", "deck : [b'unknown' b'unknown' b'E' b'unknown' b'B']\n", "embark_town : [b'Southampton' b'Southampton' b'Southampton' b'Queenstown' b'Cherbourg']\n", "alone : [b'y' b'y' b'y' b'y' b'y']\n", "\n", "label : [0 1 1 0 0]\n" ] } ], "source": [ "for batch, label in titanic_csv_ds.take(1):\n", " for key, value in batch.items():\n", " print(f\"{key:20s}: {value}\")\n", " print()\n", " print(f\"{'label':20s}: {label}\")" ] }, { "cell_type": "markdown", "metadata": { "id": "k-TgA6o2Ja6U" }, "source": [ "참고: 위의 셀을 두 번 실행하면 다른 결과가 생성됩니다. `tf.data.experimental.make_csv_dataset`의 기본 설정에는 `shuffle_buffer_size=1000`이 포함되며, 이는 이 작은 데이터세트에는 충분하지만 실제 데이터세트에는 그렇지 않을 수 있습니다." ] }, { "cell_type": "markdown", "metadata": { "id": "d6uviU_KCCWD" }, "source": [ "즉시 데이터 압축을 풀 수도 있습니다. 다음은 [대도시 주간 교통량 데이터세트](https://archive.ics.uci.edu/ml/datasets/Metro+Interstate+Traffic+Volume)가 포함된 gzip으로 압축된 CSV 파일입니다.\n", "\n", "![교통 정체.](images/csv/traffic.jpg)\n", "\n", "이미지 출처: [Wikimedia](https://commons.wikimedia.org/wiki/File:Trafficjam.jpg)\n" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:23.952296Z", "iopub.status.busy": "2022-12-14T21:07:23.951719Z", "iopub.status.idle": "2022-12-14T21:07:24.471113Z", "shell.execute_reply": "2022-12-14T21:07:24.470418Z" }, "id": "kT7oZI2E46Q8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 8192/405373 [..............................] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 81920/405373 [=====>........................] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "385024/405373 [===========================>..] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "405373/405373 [==============================] - 0s 0us/step\n" ] } ], "source": [ "traffic_volume_csv_gz = tf.keras.utils.get_file(\n", " 'Metro_Interstate_Traffic_Volume.csv.gz', \n", " \"https://archive.ics.uci.edu/ml/machine-learning-databases/00492/Metro_Interstate_Traffic_Volume.csv.gz\",\n", " cache_dir='.', cache_subdir='traffic')" ] }, { "cell_type": "markdown", "metadata": { "id": "F-IOsFHbCw0i" }, "source": [ "압축된 파일로부터 직접 읽도록 `compression_type` 인수를 설정합니다." ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:24.475234Z", "iopub.status.busy": "2022-12-14T21:07:24.474523Z", "iopub.status.idle": "2022-12-14T21:07:24.740479Z", "shell.execute_reply": "2022-12-14T21:07:24.739739Z" }, "id": "ar0MPEVJ5NeA" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "holiday : [b'None' b'None' b'None' b'None' b'None']\n", "temp : [267.84 285.35 266.41 280.66 279.53]\n", "rain_1h : [0. 0. 0. 0. 0.]\n", "snow_1h : [0. 0. 0. 0. 0.]\n", "clouds_all : [90 32 90 90 1]\n", "weather_main : [b'Snow' b'Clouds' b'Snow' b'Mist' b'Clear']\n", "weather_description : [b'heavy snow' b'scattered clouds' b'heavy snow' b'mist' b'sky is clear']\n", "date_time : [b'2013-03-19 12:00:00' b'2013-07-29 02:00:00' b'2013-01-03 22:00:00'\n", " b'2013-05-23 07:00:00' b'2013-04-04 15:00:00']\n", "\n", "label : [4755 324 1550 6717 5992]\n" ] } ], "source": [ "traffic_volume_csv_gz_ds = tf.data.experimental.make_csv_dataset(\n", " traffic_volume_csv_gz,\n", " batch_size=256,\n", " label_name='traffic_volume',\n", " num_epochs=1,\n", " compression_type=\"GZIP\")\n", "\n", "for batch, label in traffic_volume_csv_gz_ds.take(1):\n", " for key, value in batch.items():\n", " print(f\"{key:20s}: {value[:5]}\")\n", " print()\n", " print(f\"{'label':20s}: {label[:5]}\")" ] }, { "cell_type": "markdown", "metadata": { "id": "p12Y6tGq8D6M" }, "source": [ "참고: `tf.data` 파이프라인에서 해당 날짜-시간 문자열을 파싱해야 하는 경우 `tfa.text.parse_time`을 사용할 수 있습니다." ] }, { "cell_type": "markdown", "metadata": { "id": "EtrAXzYGP3l0" }, "source": [ "### 캐싱" ] }, { "cell_type": "markdown", "metadata": { "id": "fN2dL_LRP83r" }, "source": [ "CSV 데이터를 파싱하는 데 약간의 오버헤드가 있습니다. 작은 크기의 모델의 경우 이때 훈련 병목 현상이 발생할 수 있습니다.\n", "\n", "사용 사례에 따라 CSV 데이터가 첫 번째 epoch에서만 파싱되도록 `Dataset.cache` 또는 `tf.data.experimental.snapshot`을 사용하는 것이 좋습니다.\n", "\n", "`cache`와 `snapshot` 메서드의 주요 차이점은 `cache` 파일은 이를 생성한 TensorFlow 프로세스에서만 사용할 수 있다는 것입니다. 다만, `snapshot` 파일은 다른 프로세스에서 읽을 수 있습니다.\n", "\n", "예를 들어, `traffic_volume_csv_gz_ds`를 20번 반복하는 데 캐싱 없이는 약 15초, 캐싱이 있으면 약 2초가 걸릴 수 있습니다." ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:24.744691Z", "iopub.status.busy": "2022-12-14T21:07:24.744032Z", "iopub.status.idle": "2022-12-14T21:07:37.732024Z", "shell.execute_reply": "2022-12-14T21:07:37.731245Z" }, "id": "Qk38Sw4MO4eh" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".\n", "CPU times: user 17.7 s, sys: 3.98 s, total: 21.6 s\n", "Wall time: 13 s\n" ] } ], "source": [ "%%time\n", "for i, (batch, label) in enumerate(traffic_volume_csv_gz_ds.repeat(20)):\n", " if i % 40 == 0:\n", " print('.', end='')\n", "print()" ] }, { "cell_type": "markdown", "metadata": { "id": "pN3HtDONh5TX" }, "source": [ "참고: `Dataset.cache`는 첫 번째 epoch의 데이터를 저장하고 순서대로 재생합니다. 따라서 `cache` 메서드를 사용하면 파이프라인의 초기에 모든 셔플이 비활성화됩니다. 아래에서 `Dataset.shuffle`은 `Dataset.cache` 뒤에 다시 추가됩니다." ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:37.735992Z", "iopub.status.busy": "2022-12-14T21:07:37.735422Z", "iopub.status.idle": "2022-12-14T21:07:39.516322Z", "shell.execute_reply": "2022-12-14T21:07:39.515507Z" }, "id": "r5Jj72MrPbnh" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ".................." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".................." ] }, { "name": "stdout", "output_type": "stream", "text": [ "................." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".................." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".................." ] }, { "name": "stdout", "output_type": "stream", "text": [ "......\n", "CPU times: user 1.98 s, sys: 293 ms, total: 2.27 s\n", "Wall time: 1.78 s\n" ] } ], "source": [ "%%time\n", "caching = traffic_volume_csv_gz_ds.cache().shuffle(1000)\n", "\n", "for i, (batch, label) in enumerate(caching.shuffle(1000).repeat(20)):\n", " if i % 40 == 0:\n", " print('.', end='')\n", "print()" ] }, { "cell_type": "markdown", "metadata": { "id": "wN7uUBjmgNZ9" }, "source": [ "참고: `tf.data.experimental.snapshot` 파일은 사용 중 데이터세트를 *임시로* 저장하기 위한 것입니다. 이것은 장기 보관을 위한 형식이 *아닙니다*. 파일 형식은 내부 정보로 간주되며 TensorFlow 버전 간에 보장되지 않습니다." ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:39.520378Z", "iopub.status.busy": "2022-12-14T21:07:39.519726Z", "iopub.status.idle": "2022-12-14T21:07:41.586105Z", "shell.execute_reply": "2022-12-14T21:07:41.585268Z" }, "id": "PHGD1E8ktUvW" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From :1: snapshot (from tensorflow.python.data.experimental.ops.snapshot) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use `tf.data.Dataset.snapshot(...)`.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ ".............." ] }, { "name": "stdout", "output_type": "stream", "text": [ ".............." ] }, { "name": "stdout", "output_type": "stream", "text": [ "................" ] }, { "name": "stdout", "output_type": "stream", "text": [ "................" ] }, { "name": "stdout", "output_type": "stream", "text": [ "................" ] }, { "name": "stdout", "output_type": "stream", "text": [ "................." ] }, { "name": "stdout", "output_type": "stream", "text": [ "..\n", "CPU times: user 3.03 s, sys: 814 ms, total: 3.84 s\n", "Wall time: 2.06 s\n" ] } ], "source": [ "%%time\n", "snapshot = tf.data.experimental.snapshot('titanic.tfsnap')\n", "snapshotting = traffic_volume_csv_gz_ds.apply(snapshot).shuffle(1000)\n", "\n", "for i, (batch, label) in enumerate(snapshotting.shuffle(1000).repeat(20)):\n", " if i % 40 == 0:\n", " print('.', end='')\n", "print()" ] }, { "cell_type": "markdown", "metadata": { "id": "fUSSegnMCGRz" }, "source": [ "CSV 파일 로드로 인해 데이터 로드가 느려지고 `Dataset.cache` 및 `tf.data.experimental.snapshot`이 사용 사례에 충분하지 않은 경우, 데이터를 보다 간소화된 형식으로 다시 인코딩하는 것이 좋습니다." ] }, { "cell_type": "markdown", "metadata": { "id": "M0iGXv9pC5kr" }, "source": [ "### 여러 파일" ] }, { "cell_type": "markdown", "metadata": { "id": "9FFzHQrCDH4w" }, "source": [ "지금까지 이 섹션의 모든 예제는 `tf.data` 없이 쉽게 수행할 수 있었습니다. `tf.data`를 사용하여 실제로 작업을 단순화할 수 있는 한 예는 파일 모음을 처리할 경우입니다.\n", "\n", "예를 들어 [문자 글꼴 이미지](https://archive.ics.uci.edu/ml/datasets/Character+Font+Images) 데이터세트는 글꼴당 하나씩, csv 파일 모음으로 배포됩니다.\n", "\n", "![글꼴](images/csv/fonts.jpg)\n", "\n", "Pixabay에서 Willi Heidelbach가 제공한 이미지\n", "\n", "데이터세트를 다운로드하고 내부 파일을 검토합니다." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:41.590261Z", "iopub.status.busy": "2022-12-14T21:07:41.589700Z", "iopub.status.idle": "2022-12-14T21:07:49.413141Z", "shell.execute_reply": "2022-12-14T21:07:49.412404Z" }, "id": "RmVknMdJh5ks" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\r", " 8192/160313983 [..............................] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 81920/160313983 [..............................] - ETA: 3:12" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 229376/160313983 [..............................] - ETA: 1:43" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 540672/160313983 [..............................] - ETA: 58s " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 991232/160313983 [..............................] - ETA: 39s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 1769472/160313983 [..............................] - ETA: 26s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 3211264/160313983 [..............................] - ETA: 17s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 5963776/160313983 [>.............................] - ETA: 10s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 9043968/160313983 [>.............................] - ETA: 7s " ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 12173312/160313983 [=>............................] - ETA: 6s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 15286272/160313983 [=>............................] - ETA: 5s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 18415616/160313983 [==>...........................] - ETA: 4s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 21495808/160313983 [===>..........................] - ETA: 4s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 24641536/160313983 [===>..........................] - ETA: 3s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 27770880/160313983 [====>.........................] - ETA: 3s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 30793728/160313983 [====>.........................] - ETA: 3s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 33923072/160313983 [=====>........................] - ETA: 3s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 37036032/160313983 [=====>........................] - ETA: 3s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 39862272/160313983 [======>.......................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 42975232/160313983 [=======>......................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 46104576/160313983 [=======>......................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 49201152/160313983 [========>.....................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 52322304/160313983 [========>.....................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 55435264/160313983 [=========>....................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 58548224/160313983 [=========>....................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 61677568/160313983 [==========>...................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 64806912/160313983 [===========>..................] - ETA: 2s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 67952640/160313983 [===========>..................] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 71081984/160313983 [============>.................] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 74227712/160313983 [============>.................] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 77201408/160313983 [=============>................] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 80027648/160313983 [=============>................] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 82886656/160313983 [==============>...............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 85671936/160313983 [===============>..............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 88465408/160313983 [===============>..............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 91414528/160313983 [================>.............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 94535680/160313983 [================>.............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", " 97665024/160313983 [=================>............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "100810752/160313983 [=================>............] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "103940096/160313983 [==================>...........] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "107069440/160313983 [===================>..........] - ETA: 1s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "110198784/160313983 [===================>..........] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "113328128/160313983 [====================>.........] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "116457472/160313983 [====================>.........] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "119586816/160313983 [=====================>........] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "122732544/160313983 [=====================>........] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "125837312/160313983 [======================>.......] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "128942080/160313983 [=======================>......] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "132005888/160313983 [=======================>......] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "134856704/160313983 [========================>.....] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "137674752/160313983 [========================>.....] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "140500992/160313983 [=========================>....] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "143343616/160313983 [=========================>....] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "146448384/160313983 [==========================>...] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "149553152/160313983 [==========================>...] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "152682496/160313983 [===========================>..] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "155811840/160313983 [============================>.] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "158941184/160313983 [============================>.] - ETA: 0s" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r", "160313983/160313983 [==============================] - 3s 0us/step\n" ] } ], "source": [ "fonts_zip = tf.keras.utils.get_file(\n", " 'fonts.zip', \"https://archive.ics.uci.edu/ml/machine-learning-databases/00417/fonts.zip\",\n", " cache_dir='.', cache_subdir='fonts',\n", " extract=True)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:49.417695Z", "iopub.status.busy": "2022-12-14T21:07:49.417027Z", "iopub.status.idle": "2022-12-14T21:07:49.423221Z", "shell.execute_reply": "2022-12-14T21:07:49.422594Z" }, "id": "xsDlMCnyi55e" }, "outputs": [ { "data": { "text/plain": [ "['fonts/AGENCY.csv',\n", " 'fonts/ARIAL.csv',\n", " 'fonts/BAITI.csv',\n", " 'fonts/BANKGOTHIC.csv',\n", " 'fonts/BASKERVILLE.csv',\n", " 'fonts/BAUHAUS.csv',\n", " 'fonts/BELL.csv',\n", " 'fonts/BERLIN.csv',\n", " 'fonts/BERNARD.csv',\n", " 'fonts/BITSTREAMVERA.csv']" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pathlib\n", "font_csvs = sorted(str(p) for p in pathlib.Path('fonts').glob(\"*.csv\"))\n", "\n", "font_csvs[:10]" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:49.427082Z", "iopub.status.busy": "2022-12-14T21:07:49.426359Z", "iopub.status.idle": "2022-12-14T21:07:49.430672Z", "shell.execute_reply": "2022-12-14T21:07:49.430085Z" }, "id": "lRAEJx9ROAGl" }, "outputs": [ { "data": { "text/plain": [ "153" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(font_csvs)" ] }, { "cell_type": "markdown", "metadata": { "id": "19Udrw9iG-FS" }, "source": [ "많은 파일을 처리할 경우 glob 스타일의 `file_pattern`을 `tf.data.experimental.make_csv_dataset` 함수에 전달할 수 있습니다. 파일의 순서는 각 반복마다 뒤섞입니다.\n", "\n", "`num_parallel_reads` 인수를 사용하여 병렬로 읽고 함께 인터리브 처리되는 파일의 수를 설정합니다." ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:49.434063Z", "iopub.status.busy": "2022-12-14T21:07:49.433528Z", "iopub.status.idle": "2022-12-14T21:07:50.528615Z", "shell.execute_reply": "2022-12-14T21:07:50.527844Z" }, "id": "6TSUNdT6iG58" }, "outputs": [], "source": [ "fonts_ds = tf.data.experimental.make_csv_dataset(\n", " file_pattern = \"fonts/*.csv\",\n", " batch_size=10, num_epochs=1,\n", " num_parallel_reads=20,\n", " shuffle_buffer_size=10000)" ] }, { "cell_type": "markdown", "metadata": { "id": "XMoexinLHYFa" }, "source": [ "이러한 CSV 파일의 이미지는 단일 행으로 평면화되어 있습니다. 열 이름의 형식은 `r{row}c{column}`입니다. 다음은 첫 번째 배치입니다." ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:50.533249Z", "iopub.status.busy": "2022-12-14T21:07:50.532604Z", "iopub.status.idle": "2022-12-14T21:07:53.057636Z", "shell.execute_reply": "2022-12-14T21:07:53.056807Z" }, "id": "RmFvBWxxi3pq" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "font : [b'BOOK' b'BOOK' b'BASKERVILLE' b'BASKERVILLE' b'PANROMAN'\n", " b'CITYBLUEPRINT' b'MAGNETO' b'HIMALAYA' b'VLADIMIR' b'BOOK']\n", "fontVariant : [b'BOOK ANTIQUA' b'BOOK ANTIQUA' b'BASKERVILLE OLD FACE'\n", " b'BASKERVILLE OLD FACE' b'PANROMAN' b'CITYBLUEPRINT' b'MAGNETO'\n", " b'MICROSOFT HIMALAYA' b'VLADIMIR SCRIPT' b'BOOK ANTIQUA']\n", "m_label : [ 1045 8211 181 214 8230 61498 180 126 66 8595]\n", "strength : [0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4 0.4]\n", "italic : [0 0 0 1 0 0 0 0 0 0]\n", "orientation : [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]\n", "m_top : [38 66 48 22 20 60 45 45 33 36]\n", "m_left : [21 22 19 30 24 26 38 20 25 25]\n", "originalH : [46 5 44 58 55 31 10 6 49 62]\n", "originalW : [38 29 32 50 25 2 14 24 58 23]\n", "h : [20 20 20 20 20 20 20 20 20 20]\n", "w : [20 20 20 20 20 20 20 20 20 20]\n", "r0c0 : [222 1 1 1 255 255 1 1 1 1]\n", "r0c1 : [222 255 32 1 255 255 1 1 1 1]\n", "r0c2 : [234 255 255 1 255 255 1 128 1 1]\n", "r0c3 : [255 255 255 1 255 255 1 255 1 1]\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "...\n", "[total: 412 features]\n" ] } ], "source": [ "for features in fonts_ds.take(1):\n", " for i, (name, value) in enumerate(features.items()):\n", " if i>15:\n", " break\n", " print(f\"{name:20s}: {value}\")\n", "print('...')\n", "print(f\"[total: {len(features)} features]\")" ] }, { "cell_type": "markdown", "metadata": { "id": "xrC3sKdeOhb5" }, "source": [ "#### 선택 사항: 패킹 필드\n", "\n", "여러분은 아마도 이와 같이 별도의 열에 있는 각 픽셀로 작업하고 싶지는 않을 것입니다. 이 데이터세트를 사용하기 전에 픽셀을 이미지 텐서로 패킹해야 합니다.\n", "\n", "다음은 각 예제의 이미지를 빌드하기 위해 열 이름을 파싱하는 코드입니다." ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:53.061579Z", "iopub.status.busy": "2022-12-14T21:07:53.060995Z", "iopub.status.idle": "2022-12-14T21:07:53.066654Z", "shell.execute_reply": "2022-12-14T21:07:53.065944Z" }, "id": "hct5EMEWNyfH" }, "outputs": [], "source": [ "import re\n", "\n", "def make_images(features):\n", " image = [None]*400\n", " new_feats = {}\n", "\n", " for name, value in features.items():\n", " match = re.match('r(\\d+)c(\\d+)', name)\n", " if match:\n", " image[int(match.group(1))*20+int(match.group(2))] = value\n", " else:\n", " new_feats[name] = value\n", "\n", " image = tf.stack(image, axis=0)\n", " image = tf.reshape(image, [20, 20, -1])\n", " new_feats['image'] = image\n", "\n", " return new_feats" ] }, { "cell_type": "markdown", "metadata": { "id": "61qy8utAwARP" }, "source": [ "데이터세트의 각 배치에 해당 함수를 적용합니다." ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:53.070038Z", "iopub.status.busy": "2022-12-14T21:07:53.069514Z", "iopub.status.idle": "2022-12-14T21:07:55.230839Z", "shell.execute_reply": "2022-12-14T21:07:55.229956Z" }, "id": "DJnnfIW9baE4" }, "outputs": [], "source": [ "fonts_image_ds = fonts_ds.map(make_images)\n", "\n", "for features in fonts_image_ds.take(1):\n", " break" ] }, { "cell_type": "markdown", "metadata": { "id": "_ThqrthGwHSm" }, "source": [ "결과 이미지를 플롯합니다." ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:55.235086Z", "iopub.status.busy": "2022-12-14T21:07:55.234798Z", "iopub.status.idle": "2022-12-14T21:07:56.026344Z", "shell.execute_reply": "2022-12-14T21:07:56.025635Z" }, "id": "I5dcey31T_tk" }, "outputs": [ { "data": { "image/png": "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Mn78eL9HM4EnRAAAhIH8/HzZvXu3pKWliYjI0aNHJT8/X5KTk32ezAYKEQAAMI8fqgYAIAysWrVKbr31VmnatKnEx8dL9erVpXXr1vLwww9LTk6O3+NVeTwhAgDAR2VlZfLoo4/Kc889J9HR0dKtWzdp3bq1HDt2TJYuXSorVqyQhIQEef311+V3v/ud3+NWWRQiAAB89MQTT8ioUaMkNTVVPvroIznrrLN+ls+YMUP69+8vxcXFMm/ePOnSpYtPk1Zt/CezEFu4cKFERESU638LFy70e1zAF8c/Ty699FK/RwE8lZ2dLWPGjJGYmBj58MMPf1WGRESuv/56mTBhgpSWlsqgQYMkEAj4MGnVRyEKsdTUVBk1apTUqFFDREQef/xxGTVqlIwaNUoef/xxERGpUaPGT386AADY8dprr0lJSYn07t1bWrdufdLr7rjjDqlfv76sX79eFi1a5OGEdvCfzDySmpoqW7duleLiYomO/nH9U0lJicTExEjjxo0lOzvb3wEBHxUUFMi2bdskISFBGjVq5Pc4gGe6du0qn332mUydOlXuvPNO9dqbb75Z3n77bRkzZoz86U9/8mhCO3hCBMB3gUBAVq9eLZs2bfJ7FMBTu3btEhGRhg0bOl57/JqdO3eGdCarKEQAfLd7927p16+fPPHEE36PAsAoChEA3xUVFYmISLVq1XyeBPBWvXr1RERk+/btjtcevyYlJSWkM1lFIQLgu8WLF4uISNOmTX2eBPBW586dRUTkP//5j3pdaWnpT7+J3KlTp1CPZRKFCICvVqxYIQ899JDExcXJ0KFD/R4H8NTAgQMlKipK3n//fVm7du1Jr3v11Vdl586d0rx5c7nkkks8nNAOCpGPoqOjJSIiQgoKCvweBfDF6tWrpUePHnL06FF58803T7iDBajKmjZtKn/84x+luLhYrrnmGlm3bt2vrvnggw9k2LBhEhUVJZMnT5bISL51h0K03wNY16hRI9m6dasMHDhQ+vXrJz169PB7JMATubm5ctVVV0leXp688cYbcv311/s9EuCL0aNHy5EjR2T8+PHStm1b6dGjh5x11llSXFwsS5culeXLl0t8fLy88847bKkOIWqmz8aMGSN169aV119/XRYsWOD3OIBnpk2bJjk5OXLrrbdK//79/R4H8E1kZKS88MILsnz5crnppptk7dq1MnHiRJk6dark5+fLgw8+KBs2bJA+ffr4PWqVxhMij5xs8eKAAQNkwIAB3g4DhIGNGzeKiMi5557r8yRAeGjfvr20b9/e7zHM4gkRAF+kp6eLyI9/cWVJSclP/zw3N1ceffRR9QdMASDY+Ks7APjihx9+kLZt28qOHTskPT1dOnfuLD/88IPMnz9f8vPzZc2aNerf7QQAwUQhAuCbPXv2yMiRI2XevHmyY8cOSU5Ols6dO8vdd98tl112md/jATCEQgQAAMzjZ4gAAIB5FCIAAGAehQgAAJhHIQIAAOZRiAAAgHkV3lTdLdLd6vCo5mmO1zz4yftq3jW+1NUMqDz+vK+Vnree5dEkJ+f2cwJhpL2+9yjn0YCav9zuH2reKc75z6BLCvUz7pkyRM3XPjPc8YxQC4fPieiGZ6r5d2PrqPnmy191PcN3x/S/uPvG1berecK7NdS85tz1ah7IP6LmIiJbRp6n5h0u1xek3pC8Qs0nprVwnCHU5gXeK9d1PCECAADmUYgAAIB5FCIAAGAehQgAAJhHIQIAAOZRiAAAgHkV/rV7t/La1na8hl+rx3HTl3dS8z/rvyUN/MyGqReo+dIrJqh5/egkhxPc/xnT6Vfzv7l/ksMd/P+1ey/k9+mg5s89O1nN/3P4bDW/5O671Dxp1TY1FxHZ9dsmal6cHKHmnR9epuZXj/1KzWtFHlVzEZF9pavU/K737lbzPR+kOpywxnGGcMETIgAAYB6FCAAAmEchAgAA5lGIAACAeRQiAABgHoUIAACYRyECAADmeb6HaE9752veOKTvKmoTm6Pm7WJjKzLSr8w/GuV4TU5xTVdnhIMbTtul5rERMWqeF9B3XMzKb1jhmX6p6bsB/YI7XB+BKmLnQx0dr/nyynFqXjPKac9Q6BWX6XvYWvzzXjXfMiyY04Sv0z/PVvMnr+uv5hGbd6h53KEVal6ipj9KnrK7HFed3Joxer62ZR81L4vVv4aLiETuy1XzJjn6LqSqhCdEAADAPAoRAAAwj0IEAADMoxABAADzKEQAAMA8ChEAADCPQgQAAMyjEAEAAPM8X8zY7KFMx2veeuhMNR87Rl9Gtf72yRWa6ZdGPnan4zVJ/3T+9wh3zTbvVfNOcfrrpxxso+aftU6s6Ei/Ei1fuL4HbCho4LDEU0RqRiV4MIk7GZ/epefDHb72GFnMWLJ7j36BQx6d2kjNtw87W82PNj6mny8ivzs3tF+/1hzUl+NuX5jseI8z1p2m5tU/088oPXjQ8YzKgidEAADAPAoRAAAwj0IEAADMoxABAADzKEQAAMA8ChEAADCPQgQAAMzzfA9RMLx680sOV+g979kD6WpeFXYMiYjsGdpRzTvFrXZ1/3emdlPzurLU1f2BisgYudbxmrTSe9T8tu4LXM0wbeklat5gXoTjPTLeX+VqBjMu1Peg5Y/OV/MJzd9V808Pt1bzVxfp72sRkcXPd3C8xo2COvr3uuo99F1zIiKLB/1LzVcUFav5wFf0xVcNx1ae7wM8IQIAAOZRiAAAgHkUIgAAYB6FCAAAmEchAgAA5lGIAACAeRQiAABgXljuIYpKa6LmZ0Q67TVIUNO5u1upeTXZ6nD/yiG/ccDV6/MCR9U8aWepq/sDwRQ4fNjxmmYP6TvGFkm8qxkyZIWr1+NHJV3Pc7ymy4Qlrs6494n71PyM15apebosd3V+MFR3uuAvzvfoIe3UfPsIfZ/d9Dv0Qz69Qd/ntKRTspqLlO9zOxh4QgQAAMyjEAEAAPMoRAAAwDwKEQAAMI9CBAAAzKMQAQAA8yhEAADAvLDcQ7Tzyvpq3rKavmfIycEPG6h53Sqyh+jOHvNdvf7bY7FqnjjD/z0csCOqur515funWjreI6PVDlczbP1vYzVvNNppRxpERCLbtFDzm/72seM9/n3gLDU/0j9Rzc/I1vcM4UcNx+of06NmD1DzR97/p5qXLnZ+LpM5oI2aB9Z873iP8uAJEQAAMI9CBAAAzKMQAQAA8yhEAADAPAoRAAAwj0IEAADMoxABAADzwnIP0bFLDrl6/ZbifDWvt0y/f5mr070Rcf7Zjtf0SPq7wxX6nqGh3/ZT82RZ7zgDECwbRrVS883XTQn5DFdc2UHNK8PXDi9EJSereerfs9W8W+ImxzNmXn6umpfkbHO8B9xz2gH0p0fuVPPZEyY4nrF+cl01P9DJ8RblwhMiAABgHoUIAACYRyECAADmUYgAAIB5FCIAAGAehQgAAJhHIQIAAOZRiAAAgHlhuZjx982Xu3r9ztIENS9b9a2r+4eDw02THK9pF6svXnRy5Osz1FxfvQZUTKBzOzV/6up3XJ9xsLRAzTu9/JCaNyxa6noGC7beka7mnzSYpObp/3jY8YymOcsqNBP8kfgv/ft5+wsedLzHkpvGqXnP2/XP2/LiCREAADCPQgQAAMyjEAEAAPMoRAAAwDwKEQAAMI9CBAAAzKMQAQAA8zzfQ1TU6wLHa+6pOdHhing1HfDJIDVPF3d7jsJB8e8PhPyMZn/LUvPSkE+AqsTpc7/P83PVvG9SnusZzps1XM3Tn2TPUDCUnXdIzVcUFat5g4UlwRwHYaw87+vsvtXUvODKw0GZhSdEAADAPAoRAAAwj0IEAADMoxABAADzKEQAAMA8ChEAADCPQgQAAMzzfA/R4TOdj6wRqe8ZcpKYHeXq9eEgMi5Ozc+vs931Gd8dK1Dz0j17XZ+ByiEyMVHNt/yhreM9WnXZqOb/TptWoZl+aX/pETW/4N/DHO/R8k/fqzm7tYJjXcc31Xxwzm/UPHbOymCOgzBWnvf19P36x4vTx5vIqHLNwhMiAABgHoUIAACYRyECAADmUYgAAIB5FCIAAGAehQgAAJhHIQIAAOZ5voeoSX99V0kwpIxbGvIzQq3k/BZqPqnBdNdn9PxU39uSIewCqSyiUxup+XcP1Vfz2y5epOZzak+q8EwVlVWcr+b9H31IzTPeyXQ8gz1DAE6GJ0QAAMA8ChEAADCPQgQAAMyjEAEAAPMoRAAAwDwKEQAAMI9CBAAAzAv6HqLoBilq3r32atdn/HlfK9f3CHd7L0gI+Rmnr44J+RlwFhFTzfGaLSPPU/N/9J+o5u1j/X9f37L1YjXfd08DNa/+tfOeIQA4VTwhAgAA5lGIAACAeRQiAABgHoUIAACYRyECAADmUYgAAIB5FCIAAGAehQgAAJgX9MWMx5rUUfO7aux0fcb05Z3UPENWuj7Db2WXHAz5GSmf7FDzkpBPYEN+nw5qfuPouY73GFpzssMV/i9e/OvBxmq+//Z6ah5Y910wx4GPdpXkq3l85DE1j4yLczwjUFhYoZkQnsrzvnb6eHH6eNNXvv5/s5TzOgAAgCqLQgQAAMyjEAEAAPMoRAAAwDwKEQAAMI9CBAAAzKMQAQAA84K+hyirj/NOAbdSZ4b8iJCLqqvva5rQ+p+uz7hpSxc1D+ze6/oMiBRffp6aP/70dDW/IqEoiNP45+U3eql5g3VLXd0/8Jtz1Dz5mWzHezzaYI6rGf7xw0Vq/u2tLdQ88LWNXUuXT/6Dmq8dOknNz7l9sOMZdV5y9/GE8LD79nMdr5lTX/94Oeuv+sfbd2PLNwtPiAAAgHkUIgAAYB6FCAAAmEchAgAA5lGIAACAeRQiAABgHoUIAACYF/Q9REmN84J9y19J+H6PmpeEfAL3IuL1fU1d40tdn/HtvnpqXr/Qxk6UUMsbdljNq8Keoft3ne94TePXs9Tc6fMy9xZ9x8+MJ59X8zOjkxxOEBFxtyft+XpfqfnFTS5Q8/ivXR1faTScq38fmHt7rJr/6w/POZ4x+KXOFZoJ4Sm933rHa+YW6B8vTh9vwh4iAACA8qEQAQAA8yhEAADAPAoRAAAwj0IEAADMoxABAADzKEQAAMC8Cu8hik5tpOZr2r9zysMc12ZFPzWvn1359+es+2PdkJ9Rd5y+uwHB8cV5//R7BNd2leSr+ecv6/t1RERq717maob93QrVvHx7hkLrxi2Xqflpy7epeWXYkRYMZV+tVfNnht6i5i9MesnxjKy326l5+m3fq3mgUP94Q/lExum7vTa+2kLN320w1fGMBwffq+axX610vEd58IQIAACYRyECAADmUYgAAIB5FCIAAGAehQgAAJhHIQIAAOZRiAAAgHkV3kNU0CL0+3Pyt9YI+Rl+a9DogKvXry4qcrwmOlffsxFwNQGqkuVF9dS89lR3O4ZERCLbtlTzrK6vuT7DrbcO11Lz3MuOqHlZ0Q/BHKfKip2j742589lhjvf41yMvqvkrn1+s5t+O0ndrxX4SnN02lV1RT/3tdPaf16j507VfVvPbnr3fcYbkOe6//pQHT4gAAIB5FCIAAGAehQgAAJhHIQIAAOZRiAAAgHkUIgAAYB6FCAAAmEchAgAA5lV4MWP2daEY4+eavacvFKwKFreZ6er1T+7o5XhN4NvvXZ2B8mk1abCaL7l7nJrXjEoI5jinpHnMXjXf/OwAx3uU1tOXhc67dKLDHZLUtKisWM0XHNVfLyJy379uU/O0cRvUvKzI3UJVlE/yFOdFfCM+vUHNt72gf17NmTJBzbssHqLmMd85f942mnNIzaNy9jvew4393Zo4XvPDFUfVfEFn/e105Rd3qfmWG+qrefJmb5YulgdPiAAAgHkUIgAAYB6FCAAAmEchAgAA5lGIAACAeRQiAABgHoUIAACYV+E9RAM7LHF14NS8FMdrqm3Rd6KUuJrAG0eu7+BwxWpX91+zON3xmiYS2h0X+FHDJ5eqeR+HfSY7usQ5ntGqy0Y1n5k2z/EempbV9J0qGwdMdrzHksKAmv/2i7vVvHDzaWp+5vxSNY+ds1LNRUSaiL7zRD8B4aRkc7aap/TWX//7y4bpF3SvpsaXXfOF/noR+dug5Y7XhNKQHKfvQyKf5zRV85uGPqDmKbNWqHll+H59HE+IAACAeRQiAABgHoUIAACYRyECAADmUYgAAIB5FCIAAGAehQgAAJgXUVZWVub3EAAAAH7iCREAADCPQgQAAMyjEAEAAPMoRAAAwDwKEQAAMI9CBAAAzKMQAQAA8yhEAADAPAoRAAAwj0IEAADMoxABAADz/h9PSsSld328XQAAAABJRU5ErkJggg==\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from matplotlib import pyplot as plt\n", "\n", "plt.figure(figsize=(6,6), dpi=120)\n", "\n", "for n in range(9):\n", " plt.subplot(3,3,n+1)\n", " plt.imshow(features['image'][..., n])\n", " plt.title(chr(features['m_label'][n]))\n", " plt.axis('off')" ] }, { "cell_type": "markdown", "metadata": { "id": "7-nNR0Nncdd1" }, "source": [ "## 하위 수준 함수" ] }, { "cell_type": "markdown", "metadata": { "id": "3jiGZeUijJNd" }, "source": [ "지금까지 이 튜토리얼은 csv 데이터를 읽기 위한 가장 높은 수준의 유틸리티에 중점을 두었습니다. 사용 사례가 이 기본 패턴에 맞지 않는 경우 고급 사용자에게 도움이 될 수 있는 다른 두 가지 API가 있습니다.\n", "\n", "- `tf.io.decode_csv`: 텍스트 줄을 CSV 열 텐서 목록으로 파싱하는 함수입니다.\n", "- `tf.data.experimental.CsvDataset`: 하위 수준 CSV 데이터세트 생성자입니다.\n", "\n", "이 섹션에서는 `tf.data.experimental.make_csv_dataset`에서 제공하는 기능을 다시 만들어 이 하위 수준 기능을 사용하는 방법을 보여줍니다.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "LL_ixywomOHW" }, "source": [ "### `tf.io.decode_csv`\n", "\n", "이 함수는 문자열 또는 문자열 목록을 열 목록으로 디코딩합니다.\n", "\n", "`tf.data.experimental.make_csv_dataset`과 달리 이 함수는 열 데이터 유형을 추측하지 않습니다. 각 열에 대해 올바른 유형의 값이 포함된 `record_defaults` 목록을 제공하여 열 유형을 지정합니다.\n", "\n", "`tf.io.decode_csv`를 사용하여 타이타닉 데이터를 **문자열로** 읽기 위해 다음과 같이 할 수 있습니다." ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.030929Z", "iopub.status.busy": "2022-12-14T21:07:56.030186Z", "iopub.status.idle": "2022-12-14T21:07:56.036076Z", "shell.execute_reply": "2022-12-14T21:07:56.035371Z" }, "id": "m1D2C-qdlqeW" }, "outputs": [ { "data": { "text/plain": [ "['', '', '', '', '', '', '', '', '', '']" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "text = pathlib.Path(titanic_file_path).read_text()\n", "lines = text.split('\\n')[1:-1]\n", "\n", "all_strings = [str()]*10\n", "all_strings" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.039933Z", "iopub.status.busy": "2022-12-14T21:07:56.039256Z", "iopub.status.idle": "2022-12-14T21:07:56.047465Z", "shell.execute_reply": "2022-12-14T21:07:56.046790Z" }, "id": "9W4UeJYyHPx5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n" ] } ], "source": [ "features = tf.io.decode_csv(lines, record_defaults=all_strings) \n", "\n", "for f in features:\n", " print(f\"type: {f.dtype.name}, shape: {f.shape}\")" ] }, { "cell_type": "markdown", "metadata": { "id": "j8TaHSQFoQL4" }, "source": [ "실제 유형으로 파싱하려면 해당 유형의 `record_defaults` 목록을 만듭니다. " ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.050970Z", "iopub.status.busy": "2022-12-14T21:07:56.050407Z", "iopub.status.idle": "2022-12-14T21:07:56.053991Z", "shell.execute_reply": "2022-12-14T21:07:56.053377Z" }, "id": "rzUjR59yoUe1" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0,male,22.0,1,0,7.25,Third,unknown,Southampton,n\n" ] } ], "source": [ "print(lines[0])" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.057039Z", "iopub.status.busy": "2022-12-14T21:07:56.056795Z", "iopub.status.idle": "2022-12-14T21:07:56.061791Z", "shell.execute_reply": "2022-12-14T21:07:56.061136Z" }, "id": "7sPTunxwoeWU" }, "outputs": [ { "data": { "text/plain": [ "[0, '', 0.0, 0, 0, 0.0, '', '', '', '']" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "titanic_types = [int(), str(), float(), int(), int(), float(), str(), str(), str(), str()]\n", "titanic_types" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.065007Z", "iopub.status.busy": "2022-12-14T21:07:56.064470Z", "iopub.status.idle": "2022-12-14T21:07:56.072621Z", "shell.execute_reply": "2022-12-14T21:07:56.071964Z" }, "id": "n3NlViCzoB7F" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "type: int32, shape: (627,)\n", "type: string, shape: (627,)\n", "type: float32, shape: (627,)\n", "type: int32, shape: (627,)\n", "type: int32, shape: (627,)\n", "type: float32, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n", "type: string, shape: (627,)\n" ] } ], "source": [ "features = tf.io.decode_csv(lines, record_defaults=titanic_types) \n", "\n", "for f in features:\n", " print(f\"type: {f.dtype.name}, shape: {f.shape}\")" ] }, { "cell_type": "markdown", "metadata": { "id": "m-LkTUTnpn2P" }, "source": [ "참고: CSV 텍스트의 개별 라인보다 대형 라인 배치에서 `tf.io.decode_csv`를 호출하는 것이 더 효율적입니다." ] }, { "cell_type": "markdown", "metadata": { "id": "Yp1UItJmqGqw" }, "source": [ "### `tf.data.experimental.CsvDataset`\n", "\n", "`tf.data.experimental.CsvDataset` 클래스는 `tf.data.experimental.make_csv_dataset` 함수의 편리한 특성인 열 헤더 파싱, 열 유형 추론, 자동 셔플링, 파일 인터리빙 없이 최소한의 CSV `Dataset` 인터페이스를 제공합니다.\n", "\n", "이 생성자는 `tf.io.decode_csv`와 같은 방식으로 `record_defaults`를 사용합니다.\n" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.076385Z", "iopub.status.busy": "2022-12-14T21:07:56.075857Z", "iopub.status.idle": "2022-12-14T21:07:56.094270Z", "shell.execute_reply": "2022-12-14T21:07:56.093571Z" }, "id": "9OzZLp3krP-t" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']\n" ] } ], "source": [ "simple_titanic = tf.data.experimental.CsvDataset(titanic_file_path, record_defaults=titanic_types, header=True)\n", "\n", "for example in simple_titanic.take(1):\n", " print([e.numpy() for e in example])" ] }, { "cell_type": "markdown", "metadata": { "id": "_HBmfI-Ks7dw" }, "source": [ "위의 코드는 기본적으로 다음과 같습니다." ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.098155Z", "iopub.status.busy": "2022-12-14T21:07:56.097524Z", "iopub.status.idle": "2022-12-14T21:07:56.175959Z", "shell.execute_reply": "2022-12-14T21:07:56.175219Z" }, "id": "E5O5d69Yq7gG" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, b'male', 22.0, 1, 0, 7.25, b'Third', b'unknown', b'Southampton', b'n']\n" ] } ], "source": [ "def decode_titanic_line(line):\n", " return tf.io.decode_csv(line, titanic_types)\n", "\n", "manual_titanic = (\n", " # Load the lines of text\n", " tf.data.TextLineDataset(titanic_file_path)\n", " # Skip the header row.\n", " .skip(1)\n", " # Decode the line.\n", " .map(decode_titanic_line)\n", ")\n", "\n", "for example in manual_titanic.take(1):\n", " print([e.numpy() for e in example])" ] }, { "cell_type": "markdown", "metadata": { "id": "5R3ralsnt2AC" }, "source": [ "#### 여러 파일\n", "\n", "`tf.data.experimental.CsvDataset`을 사용하여 글꼴 데이터세트를 파싱하려면 먼저 `record_defaults`에 대한 열 유형을 결정해야 합니다. 우선 한 파일의 첫 번째 행을 검사합니다." ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.179630Z", "iopub.status.busy": "2022-12-14T21:07:56.179323Z", "iopub.status.idle": "2022-12-14T21:07:56.187778Z", "shell.execute_reply": "2022-12-14T21:07:56.187024Z" }, "id": "3tlFOTjCvAI5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AGENCY,AGENCY FB,64258,0.400000,0,0.000000,35,21,51,22,20,20,1,1,1,21,101,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,1,1,1,93,255,255,255,176,146,146,146,146,146,146,146,146,216,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,141,141,141,182,255,255,255,172,141,141,141,115,1,1,1,1,163,255,255,255,255,255,255,255,255,255,255,255,255,255,255,209,1,1,1,1,163,255,255,255,6,6,6,96,255,255,255,74,6,6,6,5,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255,1,1,1,93,255,255,255,70,1,1,1,1,1,1,1,1,163,255,255,255\n" ] } ], "source": [ "font_line = pathlib.Path(font_csvs[0]).read_text().splitlines()[1]\n", "print(font_line)" ] }, { "cell_type": "markdown", "metadata": { "id": "etyGu8K_ySRz" }, "source": [ "처음 두 개의 필드만 문자열이고 나머지는 정수 또는 부동 소수점이며 쉼표를 계산하여 총 특성 수를 얻을 수 있습니다." ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.191573Z", "iopub.status.busy": "2022-12-14T21:07:56.190910Z", "iopub.status.idle": "2022-12-14T21:07:56.194981Z", "shell.execute_reply": "2022-12-14T21:07:56.194144Z" }, "id": "crgZZn0BzkSB" }, "outputs": [], "source": [ "num_font_features = font_line.count(',')+1\n", "font_column_types = [str(), str()] + [float()]*(num_font_features-2)" ] }, { "cell_type": "markdown", "metadata": { "id": "YeK2Pw540RNj" }, "source": [ "`tf.data.experimental.CsvDataset` 생성자는 입력 파일 목록을 가져올 수 있지만 순차적으로 읽습니다. CSV 목록의 첫 번째 파일은 `AGENCY.csv`입니다." ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.198569Z", "iopub.status.busy": "2022-12-14T21:07:56.197917Z", "iopub.status.idle": "2022-12-14T21:07:56.202480Z", "shell.execute_reply": "2022-12-14T21:07:56.201826Z" }, "id": "_SvL5Uvl0r0N" }, "outputs": [ { "data": { "text/plain": [ "'fonts/AGENCY.csv'" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "font_csvs[0]" ] }, { "cell_type": "markdown", "metadata": { "id": "EfAX3G8Xywy6" }, "source": [ "따라서 파일 목록을 `CsvDataset`에 전달할 때 `AGENCY.csv`의 레코드를 먼저 읽습니다." ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.205899Z", "iopub.status.busy": "2022-12-14T21:07:56.205298Z", "iopub.status.idle": "2022-12-14T21:07:56.238253Z", "shell.execute_reply": "2022-12-14T21:07:56.237430Z" }, "id": "Gtr1E66VmBqj" }, "outputs": [], "source": [ "simple_font_ds = tf.data.experimental.CsvDataset(\n", " font_csvs, \n", " record_defaults=font_column_types, \n", " header=True)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.241842Z", "iopub.status.busy": "2022-12-14T21:07:56.241535Z", "iopub.status.idle": "2022-12-14T21:07:56.329248Z", "shell.execute_reply": "2022-12-14T21:07:56.328377Z" }, "id": "k750Mgq4yt_o" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n", "b'AGENCY'\n" ] } ], "source": [ "for row in simple_font_ds.take(10):\n", " print(row[0].numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "NiqWKQV21FrE" }, "source": [ "여러 파일을 인터리브하려면 `Dataset.interleave`를 사용합니다.\n", "\n", "CSV 파일 이름이 포함된 초기 데이터세트는 다음과 같습니다. " ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.333358Z", "iopub.status.busy": "2022-12-14T21:07:56.332787Z", "iopub.status.idle": "2022-12-14T21:07:56.351961Z", "shell.execute_reply": "2022-12-14T21:07:56.351206Z" }, "id": "t9dS3SNb23W8" }, "outputs": [], "source": [ "font_files = tf.data.Dataset.list_files(\"fonts/*.csv\")" ] }, { "cell_type": "markdown", "metadata": { "id": "TNiLHMXpzHy5" }, "source": [ "이렇게 하면 각 epoch마다 파일 이름을 셔플합니다." ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.355767Z", "iopub.status.busy": "2022-12-14T21:07:56.355483Z", "iopub.status.idle": "2022-12-14T21:07:56.407711Z", "shell.execute_reply": "2022-12-14T21:07:56.406842Z" }, "id": "zNd-TYyNzIgg" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " b'fonts/VIN.csv'\n", " b'fonts/KRISTEN.csv'\n", " b'fonts/SKETCHFLOW.csv'\n", " b'fonts/CONSTANTIA.csv'\n", " b'fonts/PALACE.csv'\n", " ...\n", "\n", "Epoch 2:\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " b'fonts/VERDANA.csv'\n", " b'fonts/SERIF.csv'\n", " b'fonts/FRENCH.csv'\n", " b'fonts/MATURA.csv'\n", " b'fonts/TECHNIC.csv'\n", " ...\n" ] } ], "source": [ "print('Epoch 1:')\n", "for f in list(font_files)[:5]:\n", " print(\" \", f.numpy())\n", "print(' ...')\n", "print()\n", "\n", "print('Epoch 2:')\n", "for f in list(font_files)[:5]:\n", " print(\" \", f.numpy())\n", "print(' ...')" ] }, { "cell_type": "markdown", "metadata": { "id": "B0QB1PtU3WAN" }, "source": [ "`interleave` 메서드는 상위 `Dataset`의 각 요소마다 하위 `Dataset`를 생성하는 `map_func`를 사용합니다.\n", "\n", "여기에서 파일 데이터세트의 각 요소에서 `tf.data.experimental.CsvDataset`을 생성하려고 합니다." ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.411373Z", "iopub.status.busy": "2022-12-14T21:07:56.410875Z", "iopub.status.idle": "2022-12-14T21:07:56.415161Z", "shell.execute_reply": "2022-12-14T21:07:56.414323Z" }, "id": "QWp4rH0Q4uPh" }, "outputs": [], "source": [ "def make_font_csv_ds(path):\n", " return tf.data.experimental.CsvDataset(\n", " path, \n", " record_defaults=font_column_types, \n", " header=True)" ] }, { "cell_type": "markdown", "metadata": { "id": "VxRGdLMB5nRF" }, "source": [ "인터리브로 반환한 `Dataset`는 여러 하위 `Dataset`를 순환하며 요소를 반환합니다. 아래에서 데이터세트가 `cycle_length=3` 세 가지 글꼴 파일을 순환하는 방식을 확인하세요." ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.418690Z", "iopub.status.busy": "2022-12-14T21:07:56.418096Z", "iopub.status.idle": "2022-12-14T21:07:56.642295Z", "shell.execute_reply": "2022-12-14T21:07:56.641491Z" }, "id": "OePMNF_x1_Cc" }, "outputs": [], "source": [ "font_rows = font_files.interleave(make_font_csv_ds,\n", " cycle_length=3)" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.646559Z", "iopub.status.busy": "2022-12-14T21:07:56.645933Z", "iopub.status.idle": "2022-12-14T21:07:56.801189Z", "shell.execute_reply": "2022-12-14T21:07:56.800365Z" }, "id": "UORIGWLy54-E" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/tmpfs/tmp/ipykernel_659720/998453860.py:5: DeprecationWarning: an integer is required (got type numpy.float32). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.\n", " fonts_dict['character'].append(chr(row[2].numpy()))\n" ] }, { "data": { "text/html": [ "
\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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
font_namecharacter
0BRITANNIC
1CENTURY
2ONYX
3BRITANNIC
4CENTURY
5ONYX
6BRITANNIC
7CENTURY
8ONYX
9BRITANNIC
\n", "
" ], "text/plain": [ " font_name character\n", "0 BRITANNIC \n", "1 CENTURY fl\n", "2 ONYX \n", "3 BRITANNIC \n", "4 CENTURY fi\n", "5 ONYX \n", "6 BRITANNIC ◊\n", "7 CENTURY \n", "8 ONYX \n", "9 BRITANNIC ≥" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fonts_dict = {'font_name':[], 'character':[]}\n", "\n", "for row in font_rows.take(10):\n", " fonts_dict['font_name'].append(row[0].numpy().decode())\n", " fonts_dict['character'].append(chr(row[2].numpy()))\n", "\n", "pd.DataFrame(fonts_dict)" ] }, { "cell_type": "markdown", "metadata": { "id": "mkKZa_HX8zAm" }, "source": [ "#### 공연\n" ] }, { "cell_type": "markdown", "metadata": { "id": "8BtGHraUApdJ" }, "source": [ "이전에 `tf.io.decode_csv`가 문자열 배치에서 실행될 때 더 효율적이라는 점을 언급했습니다.\n", "\n", "대형 배치 크기를 사용할 때 이 사실을 활용하여 CSV 로드 성능을 향상시킬 수 있습니다(단, 먼저 [캐싱](#caching)을 시도해야 함)." ] }, { "cell_type": "markdown", "metadata": { "id": "d35zWMH7MDL1" }, "source": [ "내장 로더 20을 사용할 경우 2048개의 예제 배치에 약 17초가 걸립니다. " ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:56.805715Z", "iopub.status.busy": "2022-12-14T21:07:56.805404Z", "iopub.status.idle": "2022-12-14T21:07:57.662505Z", "shell.execute_reply": "2022-12-14T21:07:57.661725Z" }, "id": "ieUVAPryjpJS" }, "outputs": [], "source": [ "BATCH_SIZE=2048\n", "fonts_ds = tf.data.experimental.make_csv_dataset(\n", " file_pattern = \"fonts/*.csv\",\n", " batch_size=BATCH_SIZE, num_epochs=1,\n", " num_parallel_reads=100)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:07:57.667214Z", "iopub.status.busy": "2022-12-14T21:07:57.666466Z", "iopub.status.idle": "2022-12-14T21:08:19.859032Z", "shell.execute_reply": "2022-12-14T21:08:19.858180Z" }, "id": "MUC2KW4LkQIz" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "." ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "CPU times: user 52.7 s, sys: 5.52 s, total: 58.2 s\n", "Wall time: 22.2 s\n" ] } ], "source": [ "%%time\n", "for i,batch in enumerate(fonts_ds.take(20)):\n", " print('.',end='')\n", "\n", "print()" ] }, { "cell_type": "markdown", "metadata": { "id": "5lhnh6rZEDS2" }, "source": [ "**텍스트 줄 배치**를 `decode_csv`에 전달하면 더 빠르게 약 5초 만에 실행됩니다." ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:08:19.863150Z", "iopub.status.busy": "2022-12-14T21:08:19.862421Z", "iopub.status.idle": "2022-12-14T21:08:20.513397Z", "shell.execute_reply": "2022-12-14T21:08:20.512610Z" }, "id": "4XbPZV1okVF9" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/autograph/pyct/static_analysis/liveness.py:83: Analyzer.lamba_check (from tensorflow.python.autograph.pyct.static_analysis.liveness) is deprecated and will be removed after 2023-09-23.\n", "Instructions for updating:\n", "Lambda fuctions will be no more assumed to be used in the statement where they are used, or at least in the same block. https://github.com/tensorflow/tensorflow/issues/56089\n" ] } ], "source": [ "fonts_files = tf.data.Dataset.list_files(\"fonts/*.csv\")\n", "fonts_lines = fonts_files.interleave(\n", " lambda fname:tf.data.TextLineDataset(fname).skip(1), \n", " cycle_length=100).batch(BATCH_SIZE)\n", "\n", "fonts_fast = fonts_lines.map(lambda x: tf.io.decode_csv(x, record_defaults=font_column_types))" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T21:08:20.517635Z", "iopub.status.busy": "2022-12-14T21:08:20.517099Z", "iopub.status.idle": "2022-12-14T21:08:21.364245Z", "shell.execute_reply": "2022-12-14T21:08:21.363500Z" }, "id": "te9C2km-qO8W" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "...................." ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "CPU times: user 5.12 s, sys: 65.2 ms, total: 5.18 s\n", "Wall time: 842 ms\n" ] } ], "source": [ "%%time\n", "for i,batch in enumerate(fonts_fast.take(20)):\n", " print('.',end='')\n", "\n", "print()" ] }, { "cell_type": "markdown", "metadata": { "id": "aebC1plsMeOi" }, "source": [ "대규모 배치를 사용하여 CSV 성능을 높이는 또 다른 예는 [과대적합과 과소적합 튜토리얼](../keras/overfit_and_underfit.ipynb)을 참조하세요.\n", "\n", "이러한 종류의 접근 방식이 효과가 있을 수 있지만 `Dataset.cache` 및 `tf.data.experimental.snapshot`과 같은 다른 옵션과 함께 데이터를 보다 간소화된 형식으로 다시 인코딩하는 방법도 고려하세요." ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "csv.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 }