{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "rwxGnsA92emp" }, "source": [ "##### Copyright 2018 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-15T02:49:48.780470Z", "iopub.status.busy": "2022-12-15T02:49:48.779896Z", "iopub.status.idle": "2022-12-15T02:49:48.784240Z", "shell.execute_reply": "2022-12-15T02:49:48.783575Z" }, "id": "CPII1rGR2rF9" }, "outputs": [], "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ] }, { "cell_type": "markdown", "metadata": { "id": "JtEZ1pCPn--z" }, "source": [ "# カスタム訓練:ウォークスルー" ] }, { "cell_type": "markdown", "metadata": { "id": "GV1F7tVTN3Dn" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
TensorFlow.org で表示 Google Colab で実行 GitHub でソースを表示ノートブックをダウンロード/a0}
" ] }, { "cell_type": "markdown", "metadata": { "id": "LDrzLFXE8T1l" }, "source": [ "このチュートリアルでは、カスタムトレーニングループを使って機械学習モデルをトレーニングし、ペンギンを種類別に*分類*する方法を説明します。このノートブックでは、TensorFlow を使用して、次の項目を達成します。\n", "\n", "1. データセットをインポートする\n", "2. 単純な線形モデルを構築する\n", "3. モデルをトレーニングする\n", "4. モデルの有効性を評価する\n", "5. トレーニングされたモデルを使用して予測を立てる\n", "\n", "## TensorFlow プログラミング\n", "\n", "このチュートリアルでは、次の TensorFlow プログラミングタスクを実演しています。\n", "\n", "- [TensorFlow Datasets API](https://www.tensorflow.org/datasets/overview#load_a_dataset) を使ってデータをインポートする\n", "- [Keras API](https://www.tensorflow.org/guide/keras/) を使ってモデルとレイヤーを構築する\n" ] }, { "cell_type": "markdown", "metadata": { "id": "Zx7wc0LuuxaJ" }, "source": [ "## ペンギンの分類の問題\n", "\n", "鳥類学者が、発見したペンギンを自動的に分類する方法を探していると仮定しましょう。機械学習では、ペンギンを静的に分類するためのアルゴリズムが多数用意されています。たとえば、高度な機械学習プログラムでは、写真を基にペンギンを分類できるものもあります。このチュートリアルで作成するモデルは、これよりも少しシンプルで、体重、フリッパーの長さ、くちばし、特に[ 嘴峰(しほう)](https://en.wikipedia.org/wiki/Beak#Culmen)の長さと幅に基づいてペンギンを分類します。\n", "\n", "ペンギンには 18 種ありますが、このチュートリアルでは次の 3 種のみを分類してみることにしましょう。\n", "\n", "- ヒゲペンギン\n", "- ジェンツーペンギン\n", "- アデリーペンギン\n", "\n", "\n", " \n", " \n", "
\"Petal
図 1. ヒゲペンギンジェンツー、およびアデリーペンギン(イラスト: @allison_horst, CC BY-SA 2.0)。
\n", "\n", "幸いにも、体重、フリッパーの長さ、くちばしの測定値とその他のデータで含む[334 羽のペンギンのデータセット](https://allisonhorst.github.io/palmerpenguins/)が調査チームによって既に作成されて共有されています。このデータセットは、[penguins](https://www.tensorflow.org/datasets/catalog/penguins) TensorFlow Dataset としても提供されています。 " ] }, { "cell_type": "markdown", "metadata": { "id": "1J3AuPBT9gyR" }, "source": [ "## セットアップ\n", "\n", "penguis データセットに使用する `tfds-nightly` パッケージをインストールします。`tfds-nightly` パッケージは毎晩リリースされる TensorFlow Datasets(TFDS)のバージョンです。TFDS の詳細については、[TensorFlow Datasets の概要](https://www.tensorflow.org/datasets/overview)をご覧ください。" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:49:48.788392Z", "iopub.status.busy": "2022-12-15T02:49:48.787837Z", "iopub.status.idle": "2022-12-15T02:49:53.437989Z", "shell.execute_reply": "2022-12-15T02:49:53.436931Z" }, "id": "4XXWn1eDZmET" }, "outputs": [], "source": [ "!pip install -q tfds-nightly" ] }, { "cell_type": "markdown", "metadata": { "id": "DtGeMicKRGzU" }, "source": [ "次に、Colab メニューから **Runtime > Restart Runtime** を選択して、Colab ランタイムを再起動します。\n", "\n", "ランタイムを再起動せずに、チュートリアルを先に進めないでください。" ] }, { "cell_type": "markdown", "metadata": { "id": "G9onjGZWZbA-" }, "source": [ "TensorFlow と他に必要な Python モジュールをインポートします。 " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:49:53.443331Z", "iopub.status.busy": "2022-12-15T02:49:53.442599Z", "iopub.status.idle": "2022-12-15T02:49:56.433565Z", "shell.execute_reply": "2022-12-15T02:49:56.432743Z" }, "id": "jElLULrDhQZR" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-15 02:49:54.529097: 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-15 02:49:54.529227: 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-15 02:49:54.529239: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "TensorFlow version: 2.11.0\n", "TensorFlow Datasets version: 4.7.0+nightly\n" ] } ], "source": [ "import os\n", "import tensorflow as tf\n", "import tensorflow_datasets as tfds\n", "import matplotlib.pyplot as plt\n", "\n", "print(\"TensorFlow version: {}\".format(tf.__version__))\n", "print(\"TensorFlow Datasets version: \",tfds.__version__)" ] }, { "cell_type": "markdown", "metadata": { "id": "3Px6KAg0Jowz" }, "source": [ "## データセットをインポートする\n", "\n", "デフォルトの [penguins/processed](https://www.tensorflow.org/datasets/catalog/penguins) TensorFlow Dataset はすでにクリーニングされて正規化が済んでおり、モデルを構築できる準備が整っています。processed データをダウンロードする前に、簡易バージョンをプレビューして、元のペンギン調査データを理解しておきましょう。\n" ] }, { "cell_type": "markdown", "metadata": { "id": "qnX1-aLors4S" }, "source": [ "### データをプレビューする\n", "\n", "TensorFlow Datasets [`tdfs.load`](https://www.tensorflow.org/datasets/api_docs/python/tfds/load) メソッドを使用して、penguins データセットの簡易バージョン(`penguins/simple`)をダウンロードします。このデータセットには 344 件のデータレコードが存在します。最初の 5 件のレコードを [`DataFrame`](https://www.tensorflow.org/datasets/api_docs/python/tfds/as_dataframe) オブジェクトに抽出し、このデータセットのサンプルの値を調べます。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:49:56.437808Z", "iopub.status.busy": "2022-12-15T02:49:56.436940Z", "iopub.status.idle": "2022-12-15T02:50:01.468007Z", "shell.execute_reply": "2022-12-15T02:50:01.467162Z" }, "id": "FQvb_JYdrpPm" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " body_mass_g culmen_depth_mm culmen_length_mm flipper_length_mm island \\\n", "0 4200.0 13.9 45.500000 210.0 0 \n", "1 4650.0 13.7 40.900002 214.0 0 \n", "2 5300.0 14.2 51.299999 218.0 0 \n", "3 5650.0 15.0 47.799999 215.0 0 \n", "4 5050.0 15.8 46.299999 215.0 0 \n", "\n", " sex species \n", "0 0 2 \n", "1 0 2 \n", "2 1 2 \n", "3 1 2 \n", "4 1 2 \n", "FeaturesDict({\n", " 'body_mass_g': float32,\n", " 'culmen_depth_mm': float32,\n", " 'culmen_length_mm': float32,\n", " 'flipper_length_mm': float32,\n", " 'island': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", " 'sex': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", " 'species': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", "})\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2022-12-15 02:50:01.396869: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n" ] } ], "source": [ "ds_preview, info = tfds.load('penguins/simple', split='train', with_info=True)\n", "df = tfds.as_dataframe(ds_preview.take(5), info)\n", "print(df)\n", "print(info.features)" ] }, { "cell_type": "markdown", "metadata": { "id": "kQhzD6P-uBoq" }, "source": [ "番号付きの行がデータレコードで、行ごとに 1 つの*[サンプル](https://developers.google.com/machine-learning/glossary/#example)*が含まれます。\n", "\n", "- 最初の 6 つのフィールドは、サンプルの特徴づける*[特徴量](https://developers.google.com/machine-learning/glossary/#feature)*です。ここでは、ペンギンの測定値を表す数字が含まれています。\n", "- 最後の列は*[ラベル](https://developers.google.com/machine-learning/glossary/#label)*です。予測しようとしている値がこれです。このデータセットでは、ペンギンの種名に対応する 0、1、または 2 の整数が示されます。" ] }, { "cell_type": "markdown", "metadata": { "id": "CCtwLoJhhDNc" }, "source": [ "このデータセットでは、ペンギンの種のラベルを数値で表現することにより、構築するモデルで扱いやすくしています。これらの数値は、次のペンギンの種に対応しています。\n", "\n", "- `0`: アデリーペンギン\n", "- `1`: ヒゲペンギン\n", "- `2`: ジェンツーペンギン\n", "\n", "この順序で、ペンギンの種名を含むリストを作成します。このリストは、分類モデルの出力を解釈するために使用します。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:01.472981Z", "iopub.status.busy": "2022-12-15T02:50:01.472227Z", "iopub.status.idle": "2022-12-15T02:50:01.476471Z", "shell.execute_reply": "2022-12-15T02:50:01.475662Z" }, "id": "sVNlJlUOhkoX" }, "outputs": [], "source": [ "class_names = ['Adélie', 'Chinstrap', 'Gentoo']" ] }, { "cell_type": "markdown", "metadata": { "id": "iav9kEgxpY0s" }, "source": [ "特徴量とラベルについての詳細は、[機械学習クラッシュコースの ML 用語セクション](https://developers.google.com/machine-learning/crash-course/framing/ml-terminology)をご覧ください。" ] }, { "cell_type": "markdown", "metadata": { "id": "PD33PxSmCrtL" }, "source": [ "### 前処理済みのデータセットをダウンロードする\n", "\n", "次に、`tfds.load` メソッドを使用して、前処理済みの penguins データセット(`penguins/processed`)をダウンロードします。すると、`tf.data.Dataset` オブジェクトのリストが返されます。`penguins/processed` データセットには独自のテストセットは用意されていないため、80:20 分割で、トレーニングセットとテストセットに[データセットをスライス](https://www.tensorflow.org/datasets/splits)します。テストデータセットは、後でモデルを検証する際に使用します。" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:01.480880Z", "iopub.status.busy": "2022-12-15T02:50:01.480168Z", "iopub.status.idle": "2022-12-15T02:50:02.639976Z", "shell.execute_reply": "2022-12-15T02:50:02.639161Z" }, "id": "EVV96zIYYAi8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "FeaturesDict({\n", " 'features': Tensor(shape=(4,), dtype=float32),\n", " 'species': ClassLabel(shape=(), dtype=int64, num_classes=3),\n", "})\n", "Test dataset sample: \n", " features species\n", "0 [0.6545454, 0.22619048, 0.89830506, 0.6388889] 2\n", "1 [0.36, 0.04761905, 0.6440678, 0.4027778] 2\n", "2 [0.68, 0.30952382, 0.91525424, 0.6944444] 2\n", "3 [0.6181818, 0.20238096, 0.8135593, 0.6805556] 2\n", "4 [0.5527273, 0.26190478, 0.84745765, 0.7083333] 2\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Train dataset sample: \n", " features species\n", "0 [0.49818182, 0.6904762, 0.42372882, 0.4027778] 0\n", "1 [0.48, 0.071428575, 0.6440678, 0.44444445] 2\n", "2 [0.7236364, 0.9047619, 0.6440678, 0.5833333] 1\n", "3 [0.34545454, 0.5833333, 0.33898306, 0.3472222] 0\n", "4 [0.10909091, 0.75, 0.3559322, 0.41666666] 0\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2022-12-15 02:50:02.465471: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n", "2022-12-15 02:50:02.619004: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n" ] } ], "source": [ "ds_split, info = tfds.load(\"penguins/processed\", split=['train[:20%]', 'train[20%:]'], as_supervised=True, with_info=True)\n", "\n", "ds_test = ds_split[0]\n", "ds_train = ds_split[1]\n", "assert isinstance(ds_test, tf.data.Dataset)\n", "\n", "print(info.features)\n", "df_test = tfds.as_dataframe(ds_test.take(5), info)\n", "print(\"Test dataset sample: \")\n", "print(df_test)\n", "\n", "df_train = tfds.as_dataframe(ds_train.take(5), info)\n", "print(\"Train dataset sample: \")\n", "print(df_train)\n", "\n", "ds_train_batch = ds_train.batch(32)" ] }, { "cell_type": "markdown", "metadata": { "id": "xX2NfLyQOK1y" }, "source": [ "このバージョンのデータセットは処理済みであるため、データが 4 つの正規化された特徴量と種ラベルに縮小されていることに注意してください。このフォーマットでは、データを素早く使用してモデルをトレーニングできるようになっているため、移行の処理は必要ありません。" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:02.644312Z", "iopub.status.busy": "2022-12-15T02:50:02.643525Z", "iopub.status.idle": "2022-12-15T02:50:02.803188Z", "shell.execute_reply": "2022-12-15T02:50:02.802406Z" }, "id": "iDuG94H-C122" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[0.49818182 0.6904762 0.42372882 0.4027778 ]\n", " [0.48 0.07142857 0.6440678 0.44444445]\n", " [0.7236364 0.9047619 0.6440678 0.5833333 ]\n", " [0.34545454 0.5833333 0.33898306 0.3472222 ]\n", " [0.10909091 0.75 0.3559322 0.41666666]\n", " [0.6690909 0.63095236 0.47457626 0.19444445]\n", " [0.8036364 0.9166667 0.4915254 0.44444445]\n", " [0.4909091 0.75 0.37288135 0.22916667]\n", " [0.33454546 0.85714287 0.37288135 0.2361111 ]\n", " [0.32 0.41666666 0.2542373 0.1388889 ]\n", " [0.41454545 0.5952381 0.5084746 0.19444445]\n", " [0.14909092 0.48809522 0.2542373 0.125 ]\n", " [0.23636363 0.4642857 0.27118644 0.05555556]\n", " [0.22181818 0.5952381 0.22033899 0.3472222 ]\n", " [0.24727273 0.5595238 0.15254237 0.25694445]\n", " [0.63272727 0.35714287 0.88135594 0.8194444 ]\n", " [0.47272727 0.15476191 0.6440678 0.4722222 ]\n", " [0.6036364 0.23809524 0.84745765 0.7361111 ]\n", " [0.26909092 0.5595238 0.27118644 0.16666667]\n", " [0.28 0.71428573 0.20338982 0.5416667 ]\n", " [0.10545454 0.5714286 0.33898306 0.2847222 ]\n", " [0.18545455 0.5952381 0.10169491 0.33333334]\n", " [0.47272727 0.16666667 0.7288136 0.6388889 ]\n", " [0.45090908 0.1904762 0.7118644 0.5972222 ]\n", " [0.49454546 0.5 0.3559322 0.25 ]\n", " [0.6363636 0.22619048 0.7457627 0.5694444 ]\n", " [0.08727273 0.5952381 0.2542373 0.05555556]\n", " [0.52 0.22619048 0.7457627 0.5555556 ]\n", " [0.5090909 0.23809524 0.7288136 0.6666667 ]\n", " [0.56 0.22619048 0.779661 0.625 ]\n", " [0.6363636 0.3452381 0.89830506 0.8333333 ]\n", " [0.15636364 0.47619048 0.20338982 0.04166667]], shape=(32, 4), dtype=float32)\n", "tf.Tensor([0 2 1 0 0 1 1 1 0 1 1 0 0 0 0 2 2 2 0 0 0 0 2 2 1 2 0 2 2 2 2 0], shape=(32,), dtype=int64)\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "2022-12-15 02:50:02.788857: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.\n" ] } ], "source": [ "features, labels = next(iter(ds_train_batch))\n", "\n", "print(features)\n", "print(labels)" ] }, { "cell_type": "markdown", "metadata": { "id": "E63mArnQaAGz" }, "source": [ "バッチのいくつかの特徴量をプロットして、クラスターを可視化できます。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:02.807474Z", "iopub.status.busy": "2022-12-15T02:50:02.806821Z", "iopub.status.idle": "2022-12-15T02:50:03.182024Z", "shell.execute_reply": "2022-12-15T02:50:03.181267Z" }, "id": "me5Wn-9FcyyO" }, "outputs": [ { "data": { "image/png": "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KioKX375ZYM7QERERNRQNl+Wys3NxbPPPov58+dXW//SSy/h1KlT2Lp1K+Li4rBkyRKMGTPGbkGJiIiIrGHzZSmDwYCUlBR06dKl2vr09HSEhYWhoKAAR48exYABA1BUVGTXsPbAy1JERETNj0MvS+n1euzcubPG+p07d0Kv1wOouqX7yv8TERERKcnmy1KzZs3C448/jpSUFAwYMAAA8Ntvv+G9997DCy+8AADYsmULQkND7RqUiIiIyBo2X5YCgI8++ghvvvkm0tLSAADdu3fHrFmzMGHCBABAaWmp5e6ppoaXpYiIiJofWz6/G1TcNGcsboiIiJofWz6/bb4sdUV5eTmys7OrPQoBADp06NDQQxIRERE1ms3FzbFjxzBlypQag4qvPC3cbDbbLRwRERGRrWwubiZPngwXFxd88803CAoKqnW2YiIiIiK12Fzc7N27FykpKejRo4cj8hARERE1is3z3PTq1Qu5ubmOyEJERETUaDYXNy+//DKee+45bN++HRcuXEBhYWG1hYiIiEhNNt8KrtFU1UPXjrVpLgOKeSs4ERFR8+PQW8G3bdvW4GBEREREjmZzcTNkyBBH5CAiIiKyC5vH3ADAzz//jEcffRSDBg3C2bNnAQAffPABduzYYddwRERERLayubj573//i+HDh6NVq1ZITU2FyWQCABQUFGDp0qV2D0hERERkC5uLm5deegmrVq3C6tWr4erqalk/ePBgpKam2jUcERERka1sLm7S0tJw22231VhvMBhw8eJFe2QiIiIiajCbi5vAwECkp6fXWL9jxw506tTJLqGIiIiIGsrm4mbatGl46qmnsHv3bkiShHPnzuGjjz7C7Nmz8cQTTzgiIxEREZHVbL4VfM6cOZBlGXfccQcuXbqE2267DTqdDrNnz8asWbMckZGIiIjIajbPUHxFeXk50tPTUVxcjF69ekGv1yM7Oxvt2rWzd0a74gzFREREzY9DZyi+ws3NDb169bK83rdvH/r379/kH79AREREzq1Bk/gRERERNVUNPnNDRNQYlbKM7X+cwOGcHLhptbj9hk7o1sZP7VhE5ARY3BCR4v537ixmffs1skpK4KLRQBYCr+z8GcNCbsDrw0fBW6dTOyIRNWNWFzf79++vd3taWlqjwxCR8zuedwGTvvgM5ZfH51XKsmXbT6f+wLSvP8f6ceMhSZJa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gCzL6NChA2bOnIk5c+bUus8rr7yCv//979iyZQtuvvlmm96vpc5zQ0RE1JzZ8vmt+uMXYmNjER0djfDwcERERCAhIQElJSWIiYkBAEyaNAnBwcGIj48HALz88stYsGABPv74Y4SEhFjG5nh6esLT01O1fhAREVHToHpxM378eOTk5GDBggXIzMxEaGgoEhMTLYOMMzIyql0uefvtt1FeXo6//OUv1Y4TFxeHhQsXKhmdiIiImiDVL0spjZeliIiImp9m9/gFIiIiInthcUNEREROhcUNERERORUWN0RERORUWNwQERGRU2FxQ0RERE6FxQ0RERE5FdUn8SNyBLPZjH3bDiH3bB58Awzod0dvuLjy252IqCXgT3tyOj9v3I2Vf1uDC+fyLesMbb3x1+WTcOfEISomIyIiJbC4Iaey88vfsPiB5cA1824X5BTileg3IWSBu6KHqpKNiIiUwTE35DRkWcbbsevqbfPu//0blRWVygQiIiJVsLghp3F09zFknsyucdbmagW5RUj5br9yoYiISHEsbshp5GcVWNcu86JjgxARkapY3JDT8AtubVW7Nla2IyKi5onFDTmNbuGd0b5bECRJqrONb6AP+t/RW8FURESkNBY35DQkScKMfz4GSKizwJnxjynQumgVTkZEREpicUNOJfyuvvj7phfQrktgtfX+HdtiwWezMeSBgSolIyIipUhCiHruLXE+hYWFMBgMKCgogLe3t9pxyEGEEDianI7cMxfgG2BAr0HdodGwliciaq5s+fzmJH7klCRJQs/IrkBkV7WjEBGRwvirLBERETkVFjdERETkVFjcEBERkVNhcUNEREROhcUNERERORUWN0RERORUWNwQERGRU2FxQ0RERE6FxQ0RERE5FRY3RERE5FT4+AVqkHJTBba8vw3fvLMVmSez4eXriaiJt2HMjBHwDfBROx4REbVgfHAm2ay0pAxz7lqCw7/+DgkSrnwLabQaeLX2xOs/LYaxe7DKKYmIyJnY8vmt+mWplStXIiQkBHq9HpGRkUhOTq6z7aFDhzBu3DiEhIRAkiQkJCQoF5Qs1r7wMY4mpwMCuLo2ls0yivKKsfiB19DCamYiImpCVC1uNmzYgNjYWMTFxSE1NRV9+/bF8OHDkZ2dXWv7S5cuoVOnTli2bBkCAwMVTksAUFpcim/X/ADZLNe6XTbL+OPg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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.scatter(features[:,0],\n", " features[:,2],\n", " c=labels,\n", " cmap='viridis')\n", "\n", "plt.xlabel(\"Body Mass\")\n", "plt.ylabel(\"Culmen Length\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "LsaVrtNM3Tx5" }, "source": [ "## 単純な線形モデルを構築する\n", "\n", "### なぜモデルか?\n", "\n", "*[モデル](https://developers.google.com/machine-learning/crash-course/glossary#model)*は、特徴量とラベルの関係です。ペンギンの分類問題においては、このモデルは体重、フリッパー、および嘴峰の測定値、および予測されるペンギンの種の関係を定義しています。単純なモデルは、数行の代数で記述することは可能ですが、複雑な機械学習モデルにはパラメータの数も多く、要約が困難です。\n", "\n", "機械学習を*使用せずに*、4 つの特徴量とペンギンの種の関係を判定することはできるのでしょうか。つまり、従来のプログラミング手法(多数の条件ステートメントを使用するなど)を使って、モデルを作成できるのでしょうか。おそらく、体重と嘴峰の測定値の関係を特定できるだけの長い時間を費やしてデータセットを分析すれば、特定の種に絞ることは可能かもしれません。これでは、複雑なデータセットでは不可能でなくとも困難極まりないことでしょう。適した機械学習アプローチであれば、*ユーザーに代わってモデルを判定*することができます。代表的なサンプルを適確な機械学習モデルタイプに十分にフィードすれば、プログラムによって関係を見つけ出すことができます。\n", "\n", "### モデルの選択\n", "\n", "次に、トレーニングするモデルの種類を選択する必要があります。選択できる種類は多数あり、最適な種類を 1 つ選ぶにはそれなりの経験が必要となります。このチュートリアルでは、ニューラルネットワークを使用して、ペンギンの分類問題を解決することにします。[*ニューラルネットワーク*](https://developers.google.com/machine-learning/glossary/#neural_network)は、特徴量とラベルの複雑な関係を見つけ出すことができます。非常に構造化されたグラフで、1 つ以上の[*非表示レイヤー*](https://developers.google.com/machine-learning/glossary/#hidden_layer)で編成されており、各非表示レイヤーは 1 つ以上の[*ニューロン*](https://developers.google.com/machine-learning/glossary/#neuron)で構成されています。ニューラルネットワークにはいくつかのカテゴリがありますが、このプログラムでは、Dense または[*全結合のニューラルネットワーク*](https://developers.google.com/machine-learning/glossary/#fully_connected_layer)を使用します。このネットワークでは、1 つのレイヤーのニューロンが前のレイヤーの*すべての*ユーロんから入力接続を受け取ります。たとえば、図 2 では、1 つの入力レイヤー、2 つの非表示レイヤー、および 1 つの出力レイヤーで構成される Dense ニューラルネットワークが示されています。\n", "\n", "\n", " \n", " \n", "
図2. 特徴量と隠れ層、予測をもつニューラルネットワーク
{nbsp}
\n", "\n", "図 2 のモデルをトレーニングし、ラベルなしのサンプルをフィードすると、このペンギンが特定のペンギン種であるという尤度によって 3 つの予測が生成されます。この予測は[*推論*](https://developers.google.com/machine-learning/crash-course/glossary#inference)と呼ばれます。この例では、出力予測の和は 1.0 です。図 2 の場合、この予測は、*アデリー*は `0.02`、*ヒゲペンギン*は `0.95`、*ジェンツー*は `0.03` となります。つまり、モデルは、95% の確率で、ラベル無しのサンプルペンギンは*ヒゲペンギン*であると予測していることになります。" ] }, { "cell_type": "markdown", "metadata": { "id": "W23DIMVPQEBt" }, "source": [ "### Keras を使ったモデル構築\n", "\n", "TensorFlow の [tf.keras](https://www.tensorflow.org/api_docs/python/tf/keras) API は、モデルと層を作成するためのおすすめの方法です。Keras がすべてを結びつけるという複雑さを引き受けてくれるため、モデルや実験の構築がかんたんになります。\n", "\n", "`tf.keras.Sequential` モデルは、レイヤーの線形スタックです。コンストラクタはレイヤーインスタンスのリスト(この場合は 2 つの `tf.keras.layers.Dense` レイヤー、各レイヤーの 10 個のノード、ラベルの予測である 3 つのノードを持つ出力レイヤー)を取ります。最初のレイヤーの `input_shape` パラメータはデータセットの特徴量の数に対応しており、必須です。" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.186516Z", "iopub.status.busy": "2022-12-15T02:50:03.185960Z", "iopub.status.idle": "2022-12-15T02:50:03.248221Z", "shell.execute_reply": "2022-12-15T02:50:03.247442Z" }, "id": "2fZ6oL2ig3ZK" }, "outputs": [], "source": [ "model = tf.keras.Sequential([\n", " tf.keras.layers.Dense(10, activation=tf.nn.relu, input_shape=(4,)), # input shape required\n", " tf.keras.layers.Dense(10, activation=tf.nn.relu),\n", " tf.keras.layers.Dense(3)\n", "])" ] }, { "cell_type": "markdown", "metadata": { "id": "FHcbEzMpxbHL" }, "source": [ "[*活性化関数(activation function)*](https://developers.google.com/machine-learning/crash-course/glossary#activation_function) は、そのレイヤーの各ノードの出力の形を決定します。この関数の非線形性は重要であり、それがなければモデルは 1層しかないものと等価になってしまいます。[利用可能な活性化関数](https://www.tensorflow.org/api_docs/python/tf/keras/activations) はたくさんありますが、隠れ層では [ReLU](https://developers.google.com/machine-learning/crash-course/glossary#ReLU) が一般的です。\n", "\n", "理想的な隠れ層の数やニューロンの数は問題やデータセットによって異なります。機械学習のさまざまな側面と同様に、ニューラルネットワークの最良の形を選択するには、知識と経験の両方が必要です。経験則から、一般的には隠れ層やニューロンの数を増やすとより強力なモデルを作ることができますが、効果的に訓練を行うためにより多くのデータを必要とします。" ] }, { "cell_type": "markdown", "metadata": { "id": "2wFKnhWCpDSS" }, "source": [ "### モデルを使用する\n", "\n", "それでは、このモデルが特徴量のバッチに対して何を行うかを見てみましょう。" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.253160Z", "iopub.status.busy": "2022-12-15T02:50:03.252411Z", "iopub.status.idle": "2022-12-15T02:50:03.613458Z", "shell.execute_reply": "2022-12-15T02:50:03.612731Z" }, "id": "xe6SQ5NrpB-I" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "predictions = model(features)\n", "predictions[:5]" ] }, { "cell_type": "markdown", "metadata": { "id": "wxyXOhwVr5S3" }, "source": [ "ご覧のように、サンプルのそれぞれは、各クラスの [ロジット(logit)](https://developers.google.com/machine-learning/crash-course/glossary#logits) 値を返します。\n", "\n", "これらのロジット値を各クラスの確率に変換するためには、 [softmax](https://developers.google.com/machine-learning/crash-course/glossary#softmax) 関数を使用します。" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.617259Z", "iopub.status.busy": "2022-12-15T02:50:03.616723Z", "iopub.status.idle": "2022-12-15T02:50:03.623770Z", "shell.execute_reply": "2022-12-15T02:50:03.623086Z" }, "id": "_tRwHZmTNTX2" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.nn.softmax(predictions[:5])" ] }, { "cell_type": "markdown", "metadata": { "id": "uRZmchElo481" }, "source": [ "クラスに渡って `tf.math.argmax` を取ると、クラスのインデックスの予測を得られますが、モデルはまだトレーニングされていないため、これは良い予測ではありません。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.627022Z", "iopub.status.busy": "2022-12-15T02:50:03.626516Z", "iopub.status.idle": "2022-12-15T02:50:03.632591Z", "shell.execute_reply": "2022-12-15T02:50:03.631882Z" }, "id": "-Jzm_GoErz8B" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Prediction: [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]\n", " Labels: [0 2 1 0 0 1 1 1 0 1 1 0 0 0 0 2 2 2 0 0 0 0 2 2 1 2 0 2 2 2 2 0]\n" ] } ], "source": [ "print(\"Prediction: {}\".format(tf.math.argmax(predictions, axis=1)))\n", "print(\" Labels: {}\".format(labels))" ] }, { "cell_type": "markdown", "metadata": { "id": "Vzq2E5J2QMtw" }, "source": [ "## モデルの訓練\n", "\n", "[*訓練(Training)*](https://developers.google.com/machine-learning/crash-course/glossary#training) は、機械学習において、モデルが徐々に最適化されていく、あるいはモデルがデータセットを*学習する*段階です。目的は、見たことのないデータについて予測を行うため、訓練用データセットの構造を十分に学習することです。訓練用データセットを学習*しすぎる*と、予測は見たことのあるデータに対してしか有効ではなく、一般化できません。この問題は [*過学習(overfitting)*](https://developers.google.com/machine-learning/crash-course/glossary#overfitting) と呼ばれ、問題の解き方を理解するのではなく答えを丸暗記するようなものです。\n", "\n", "ペンギンの分類問題は、[*教師あり機械学習*](https://developers.google.com/machine-learning/glossary/#supervised_machine_learning)の例であり、モデルはラベルを含むサンプルからトレーニングされています。サンプルにラベルを含まない場合は、[*教師なし機械学習*](https://developers.google.com/machine-learning/glossary/#unsupervised_machine_learning)と呼ばれ、モデルは通常、特徴量からパターンを見つけ出します。" ] }, { "cell_type": "markdown", "metadata": { "id": "RaKp8aEjKX6B" }, "source": [ "### 損失と勾配関数を定義する\n", "\n", "トレーニングと評価の段階では、モデルの[*損失*](https://developers.google.com/machine-learning/crash-course/glossary#loss)を計算する必要があります。これは、モデルの予測がどれくらい目標から外れているかを測定するものです。言い換えると、モデルのパフォーマンスがどれくらい劣っているかを示します。この値を最小化または最適化することが望まれます。\n", "\n", "モデルは、モデルのクラスの確率予測と目標のラベルを取り、サンプル間の平均的な損失を返す `tf.keras.losses.SparseCategoricalCrossentropy` 関数を使用して損失を計算します。" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.636359Z", "iopub.status.busy": "2022-12-15T02:50:03.635707Z", "iopub.status.idle": "2022-12-15T02:50:03.639357Z", "shell.execute_reply": "2022-12-15T02:50:03.638666Z" }, "id": "QOsi6b-1CXIn" }, "outputs": [], "source": [ "loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.642882Z", "iopub.status.busy": "2022-12-15T02:50:03.642294Z", "iopub.status.idle": "2022-12-15T02:50:03.661161Z", "shell.execute_reply": "2022-12-15T02:50:03.660276Z" }, "id": "tMAT4DcMPwI-" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Loss test: 1.1423850059509277\n" ] } ], "source": [ "def loss(model, x, y, training):\n", " # training=training is needed only if there are layers with different\n", " # behavior during training versus inference (e.g. Dropout).\n", " y_ = model(x, training=training)\n", "\n", " return loss_object(y_true=y, y_pred=y_)\n", "\n", "l = loss(model, features, labels, training=False)\n", "print(\"Loss test: {}\".format(l))" ] }, { "cell_type": "markdown", "metadata": { "id": "3IcPqA24QM6B" }, "source": [ "[tf.GradientTape](https://www.tensorflow.org/api_docs/python/tf/GradientTape) コンテキストを使って、モデルを最適化する際に使われる [*勾配(gradients)*](https://developers.google.com/machine-learning/crash-course/glossary#gradient) を計算しましょう。" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.665421Z", "iopub.status.busy": "2022-12-15T02:50:03.664735Z", "iopub.status.idle": "2022-12-15T02:50:03.669149Z", "shell.execute_reply": "2022-12-15T02:50:03.668471Z" }, "id": "x57HcKWhKkei" }, "outputs": [], "source": [ "def grad(model, inputs, targets):\n", " with tf.GradientTape() as tape:\n", " loss_value = loss(model, inputs, targets, training=True)\n", " return loss_value, tape.gradient(loss_value, model.trainable_variables)" ] }, { "cell_type": "markdown", "metadata": { "id": "lOxFimtlKruu" }, "source": [ "### オプティマイザの作成\n", "\n", "[*オプティマイザ*](https://developers.google.com/machine-learning/crash-course/glossary#optimizer)は、`loss` 関数を最小化するために、計算された勾配をモデルのパラメータに適用します。損失関数は、曲面(図 3 を参照)として考えることができ、その周辺を探りながら最低ポイントを見つけることができます。勾配は最も急な上昇に向かってポイントするため、逆方向に進んで曲面を下方向に移動します。バッチごとに損失と勾配を対話的に計算することで、トレーニング中にモデルの調整を行うことができます。モデルは徐々に、重みとバイアスの最適な組み合わせを見つけて損失を最小化できるようになります。損失が低いほど、モデルの予測が最適化されます。\n", "\n", "\n", " \n", " \n", "
\"Optimization
図3. 3次元空間における最適化アルゴリズムの時系列可視化。
(Source: Stanford class CS231n, MIT License, Image credit: Alec Radford)
\n", "\n", "TensorFlow には、トレーニングに使用できる多数の最適化アルゴリズムが用意されています。このチュートリアルでは、[*確率的勾配降下法*](https://developers.google.com/machine-learning/crash-course/glossary#gradient_descent)(SGD)アルゴリズムを実装する `tf.keras.optimizers.SGD` を使用しています。`learning_rate` パラメータは、曲面を下降するイテレーションごとに取るステップサイズを設定します。このレートは、一般的により良い結果を達成できるように調整する[*ハイパーパラメータ*](https://developers.google.com/machine-learning/glossary/#hyperparameter)です。" ] }, { "cell_type": "markdown", "metadata": { "id": "XkUd6UiZa_dF" }, "source": [ "オプティマイザを `0.01` の[*学習率*](https://developers.google.com/machine-learning/glossary#learning-rate)でインスタンス化します。これはトレーニングのイテレーションごとに、勾配が操作するスカラー値です。" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.672523Z", "iopub.status.busy": "2022-12-15T02:50:03.672254Z", "iopub.status.idle": "2022-12-15T02:50:03.680030Z", "shell.execute_reply": "2022-12-15T02:50:03.679330Z" }, "id": "8xxi2NNGKwG_" }, "outputs": [], "source": [ "optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)" ] }, { "cell_type": "markdown", "metadata": { "id": "pJVRZ0hP52ZB" }, "source": [ "次に、このオブジェクトを使用して、1 つの最適化ステップを計算します。" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:03.683952Z", "iopub.status.busy": "2022-12-15T02:50:03.683364Z", "iopub.status.idle": "2022-12-15T02:50:04.122171Z", "shell.execute_reply": "2022-12-15T02:50:04.121400Z" }, "id": "rxRNTFVe56RG" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Step: 0, Initial Loss: 1.1423850059509277\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:5 out of the last 5 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:6 out of the last 6 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "WARNING:tensorflow:6 out of the last 6 calls to triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Step: 1, Loss: 1.1399683952331543\n" ] } ], "source": [ "loss_value, grads = grad(model, features, labels)\n", "\n", "print(\"Step: {}, Initial Loss: {}\".format(optimizer.iterations.numpy(),\n", " loss_value.numpy()))\n", "\n", "optimizer.apply_gradients(zip(grads, model.trainable_variables))\n", "\n", "print(\"Step: {}, Loss: {}\".format(optimizer.iterations.numpy(),\n", " loss(model, features, labels, training=True).numpy()))" ] }, { "cell_type": "markdown", "metadata": { "id": "7Y2VSELvwAvW" }, "source": [ "### 訓練ループ\n", "\n", "すべての部品が揃ったので、モデルの訓練ができるようになりました。訓練ループは、モデルにデータセットのサンプルを供給し、モデルがよりよい予測を行えるようにします。下記のコードブロックは、この訓練のステップを構成します。\n", "\n", "1. *epoch(エポック)* をひとつずつ繰り返します。エポックとは、データセットをひととおり処理するということです。\n", "2. エポック内では、訓練用の `Dataset(データセット)` のサンプルひとつずつから、その *features(特徴量)* (`x`) と *label(ラベル)* (`y`) を取り出して繰り返し処理します。\n", "3. サンプルの特徴量を使って予測を行い、ラベルと比較します。予測の不正確度を測定し、それを使ってモデルの損失と勾配を計算します。\n", "4. `optimizer` を使って、モデルのパラメータを更新します。\n", "5. 可視化のためにいくつかの統計量を記録します。\n", "6. これをエポックごとに繰り返します。\n", "\n", "`num_epochs` 変数は、データセットコレクションをループする回数です。以下のコードでは、`num_epochs` は 201 に設定されているため、このトレーニングループは 201 回実行します。直感に反し、モデルをより長くトレーニングしても、モデルがさらに最適化されることは保証されません。`num_epochs` は、ユーザーが調整できる[*ハイパーパラメータ*](https://developers.google.com/machine-learning/glossary/#hyperparameter)です。通常、適切な数値を選択するには、経験と実験の両方が必要です。" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:04.126202Z", "iopub.status.busy": "2022-12-15T02:50:04.125453Z", "iopub.status.idle": "2022-12-15T02:50:37.775601Z", "shell.execute_reply": "2022-12-15T02:50:37.774755Z" }, "id": "AIgulGRUhpto" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 000: Loss: 1.140, Accuracy: 18.727%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 050: Loss: 0.716, Accuracy: 79.026%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 100: Loss: 0.462, Accuracy: 80.899%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 150: Loss: 0.332, Accuracy: 90.637%\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 200: Loss: 0.234, Accuracy: 95.880%\n" ] } ], "source": [ "## Note: Rerunning this cell uses the same model parameters\n", "\n", "# Keep results for plotting\n", "train_loss_results = []\n", "train_accuracy_results = []\n", "\n", "num_epochs = 201\n", "\n", "for epoch in range(num_epochs):\n", " epoch_loss_avg = tf.keras.metrics.Mean()\n", " epoch_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()\n", "\n", " # Training loop - using batches of 32\n", " for x, y in ds_train_batch:\n", " # Optimize the model\n", " loss_value, grads = grad(model, x, y)\n", " optimizer.apply_gradients(zip(grads, model.trainable_variables))\n", "\n", " # Track progress\n", " epoch_loss_avg.update_state(loss_value) # Add current batch loss\n", " # Compare predicted label to actual label\n", " # training=True is needed only if there are layers with different\n", " # behavior during training versus inference (e.g. Dropout).\n", " epoch_accuracy.update_state(y, model(x, training=True))\n", "\n", " # End epoch\n", " train_loss_results.append(epoch_loss_avg.result())\n", " train_accuracy_results.append(epoch_accuracy.result())\n", "\n", " if epoch % 50 == 0:\n", " print(\"Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}\".format(epoch,\n", " epoch_loss_avg.result(),\n", " epoch_accuracy.result()))" ] }, { "cell_type": "markdown", "metadata": { "id": "Diep-ROEuKyl" }, "source": [ "または、組み込みの Keras [`Model.fit(ds_train_batch)`](https://www.tensorflow.org/api_docs/python/tf/keras/Model#fit) メソッドを使用して、モデルをトレーニングすることもできます。 " ] }, { "cell_type": "markdown", "metadata": { "id": "2FQHVUnm_rjw" }, "source": [ "### 時間の経過に対する損失関数の可視化" ] }, { "cell_type": "markdown", "metadata": { "id": "j3wdbmtLVTyr" }, "source": [ "モデルのトレーニングの進行状況を出力することは役立ちますが、TensorFlow に同梱された [TensorBoard](https://www.tensorflow.org/tensorboard) という可視化とメトリクスツールを使って進行状況を可視化することもできます。この単純な例では、`matplotlib` モジュールを使用して基本的なグラフを作成できます。\n", "\n", "これらのグラフを解釈するには経験が必要ですが、一般的に、*損失*の減少と*精度*の上昇に注目できます。" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:37.779949Z", "iopub.status.busy": "2022-12-15T02:50:37.779306Z", "iopub.status.idle": "2022-12-15T02:50:38.066433Z", "shell.execute_reply": "2022-12-15T02:50:38.065645Z" }, "id": "agjvNd2iUGFn" }, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+4AAAL8CAYAAAB+je+aAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAACbUklEQVR4nOzdd3iV9f3/8dc5J8nJTsieJMwgWxkRkKVUnNVqFWsVxFHlJ7YVawvWbSttqX6piqLWbVXcdaIIBAQRFETZATJJyB4ne5xzfn8EDqQJgZOEnJPk+biuc4Xzue/73O+Tw3rlswx2u90uAAAAAADgloyuLgAAAAAAAJwYwR0AAAAAADdGcAcAAAAAwI0R3AEAAAAAcGMEdwAAAAAA3BjBHQAAAAAAN0ZwBwAAAADAjRHcAQAAAABwYwR3AAAAAADcGMEdAIAucsMNNygxMbFd1z744IMyGAydW1A315HvJwAA3QnBHQDQ6xkMhlN6pKSkuLpUl7jhhhtkMBgUGBiompqaFsf379/v+B7985//dPr1q6ur9eCDD/ba7y8AACfj4eoCAABwtddee63Z81dffVWrVq1q0X7GGWd06D7PP/+8bDZbu6699957tXDhwg7dvyM8PDxUXV2tjz/+WFdffXWzY//5z3/k7e2t2tradr12dXW1HnroIUnStGnTTvm6jnw/AQDoTgjuAIBe77rrrmv2/Ntvv9WqVatatP+v6upq+fr6nvJ9PD0921Wf1BScPTxc98+22WzWpEmT9Oabb7YI7m+88YYuvvhivffee11SS1VVlfz8/Dr0/QQAoDthqDwAAKdg2rRpGj58uLZu3aopU6bI19dX99xzjyTpv//9ry6++GLFxMTIbDZrwIABeuSRR2S1Wpu9xv/Oyc7IyHAML3/uuec0YMAAmc1mjRs3Tt99912za1ub424wGDR//nx9+OGHGj58uMxms4YNG6aVK1e2qD8lJUVjx46Vt7e3BgwYoGeffdbpefPXXnutPv/8c5WVlTnavvvuO+3fv1/XXnttq9eUlZXp97//veLj42U2mzVw4ED9/e9/d/SUZ2RkKDw8XJL00EMPOYbcP/jgg47vmb+/vw4ePKiLLrpIAQEB+vWvf93q91OSbDab/vWvf2nEiBHy9vZWeHi4LrjgAn3//feOc1atWqVzzjlHwcHB8vf3V1JSkuOzBADAHdHjDgDAKSouLtaFF16oa665Rtddd50iIyMlSS+//LL8/f21YMEC+fv7a82aNbr//vtlsVi0ZMmSk77uG2+8oYqKCt16660yGAz6xz/+oSuuuEJpaWkn7VXesGGD3n//ff2///f/FBAQoCeeeEJXXnmlsrKyFBoaKkn64YcfdMEFFyg6OloPPfSQrFarHn74YUdgPlVXXHGFbrvtNr3//vu68cYbHbUPGTJEZ511Vovzq6urNXXqVOXk5OjWW29V37599c0332jRokU6fPiwli5dqvDwcD3zzDOaN2+efvGLX+iKK66QJI0cOdLxOo2NjZo5c6bOOecc/fOf/2xzlMNNN92kl19+WRdeeKFuvvlmNTY26uuvv9a3336rsWPHateuXbrkkks0cuRIPfzwwzKbzTpw4IA2btzo1PcCAICuRHAHAOAU5eXlafny5br11lubtb/xxhvy8fFxPL/tttt022236emnn9Zf/vIXmc3mNl83KytL+/fvV58+fSRJSUlJuuyyy/TFF1/okksuafPaPXv2aPfu3RowYIAkafr06Ro1apTefPNNzZ8/X5L0wAMPyGQyaePGjYqJiZEkXX311U7P2Q8ICNAll1yiN954QzfeeKNsNpveeustzZs3r9XzH3/8cR08eFA//PCDBg0aJEm69dZbFRMToyVLluiuu+5SfHy8fvnLX2revHkaOXJkq9MT6urqdNVVV2nx4sVt1rd27Vq9/PLL+u1vf6t//etfjva77rpLdrtdUlNve319vT7//HOFhYU59f4BAHAVhsoDAHCKzGaz5s6d26L9+NBeUVGhoqIiTZ48WdXV1dq7d+9JX3fWrFmO0C5JkydPliSlpaWd9NoZM2Y4QrvU1FMdGBjouNZqteqrr77S5Zdf7gjtkjRw4EBdeOGFJ339/3XttdcqJSVFeXl5WrNmjfLy8k44TP6dd97R5MmT1adPHxUVFTkeM2bMkNVq1fr160/5vif64cDx3nvvPRkMBj3wwAMtjh2dEhAcHCypaXoDC9sBALoLgjsAAKcoNjZWXl5eLdp37dqlX/ziFwoKClJgYKDCw8MdPcfl5eUnfd2+ffs2e340xJeWljp97dHrj15bUFCgmpoaDRw4sMV5rbWdzNF55itWrNB//vMfjRs37oSvs3//fq1cuVLh4eHNHjNmzHDUdio8PDwUFxd30vMOHjyomJgYhYSEnPCcWbNmadKkSbr55psVGRmpa665Rm+//TYhHgDg1hgqDwDAKTq+Z/2osrIyTZ06VYGBgXr44Yc1YMAAeXt7a9u2bfrTn/50SoHQZDK12n50ePfpurY9zGazrrjiCr3yyitKS0tzLCLXGpvNpp/97Gf64x//2OrxwYMHn/I9jcbO6Wvw8fHR+vXrtXbtWn366adauXKlVqxYoXPPPVdffvnlCb+fAAC4EsEdAIAOSElJUXFxsd5//31NmTLF0Z6enu7Cqo6JiIiQt7e3Dhw40OJYa22n4tprr9WLL74oo9Goa6655oTnDRgwQJWVlY4e9hNxZmX7tgwYMEBffPGFSkpK2ux1NxqNOu+883Teeefp8ccf16OPPqo///nPWrt27UlrBQDAFRgqDwBABxztoT2+h7u+vl5PP/20q0pqxmQyacaMGfrwww+Vm5vraD9w4IA+//zzdr3m9OnT9cgjj+ipp55SVFTUCc+7+uqrtWnTJn3xxRctjpWVlamxsVGSHKvEH7/NXHtceeWVstvteuihh1ocO/r5lJSUtDg2evRoSU2L4AEA4I7ocQcAoAMmTpyoPn36aM6cOfrtb38rg8Gg11577bQNVW+PBx98UF9++aUmTZqkefPmyWq16qmnntLw4cO1fft2p1/PaDTq3nvvPel5d999tz766CNdcskluuGGGzRmzBhVVVVpx44devfdd5WRkaGwsDD5+Pho6NChWrFihQYPHqyQkBANHz5cw4cPd6qu6dOn6/rrr9cTTzyh/fv364ILLpDNZtPXX3+t6dOna/78+Xr44Ye1fv16XXzxxUpISFBBQYGefvppxcXF6ZxzznH6ewEAQFcguAMA0AGhoaH65JNPdNddd+nee+9Vnz59dN111+m8887TzJkzXV2eJGnMmDH6/PPP9Yc//EH33Xef4uPj9fDDD2vPnj2ntOp9e/n6+mrdunV69NFH9c477+jVV19VYGCgBg8erIceekhBQUGOc//973/rjjvu0J133qn6+no98MADTgd3SXrppZc0cuRIvfDCC7r77rsVFBSksWPHauLEiZKkn//858rIyNCLL76ooqIihYWFaerUqS3qAQDAnRjs7tQlAAAAuszll1+uXbt2af/+/a4uBQAAtIE57gAA9AI1NTXNnu/fv1+fffaZpk2b5pqCAADAKaPHHQCA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64c//KFXH2zbts3z3m9/+1v961//0oYNG/Tee+/pq6++0m233ebHajunnTt3evVRTk6OJOmnP/2ppw1jyfeqqqo0YsQILV++vNn3H3/8cf31r3/Vs88+q+3btyssLExpaWmqqanxtJkxY4Y++eQT5eTk6M0339T777+vX/3qV746BNtrqY+qq6u1a9cuLVq0SLt27dKrr76qwsJC3XzzzU3aPvroo17j64EHHvBF+Z1Ga2NJkiZPnuzVBy+//LLX+4yl9tdaP327f44eParVq1fL4XDo9ttv92rHeGo/bTn/bu3crqGhQVOnTlVdXZ0+/PBDvfDCC3r++ee1ePFifxzSxTHoEMaPH2/mzp3r+bqhocHEx8ebrKwsP1aFRseOHTOSzHvvvefZdt1115l58+b5ryiYzMxMM2LEiGbfKysrM126dDEbNmzwbPvss8+MJJOXl+ejCtGcefPmmQEDBhi3222MYSxZgSTz2muveb52u90mLi7OPPHEE55tZWVlxuVymZdfftkYY8ynn35qJJmdO3d62rz99tvG4XCYI0eO+Kz2zuK7fdScHTt2GEnm0KFDnm0JCQnmqaeeat/i4NFcP82aNcvccsstF9yHseR7bRlPt9xyi7nhhhu8tjGefOu7599tObd76623jNPpNCUlJZ42K1asMOHh4aa2tta3B3CRuOLeAdTV1Sk/P18pKSmebU6nUykpKcrLy/NjZWhUXl4uSYqKivLa/tJLLyk6OlpDhw7VwoULVV1d7Y/yOrV9+/YpPj5e/fv314wZM1RcXCxJys/PV319vde4Gjx4sPr27cu48qO6ujqtXbtWv/zlL+VwODzbGUvWcvDgQZWUlHiNn4iICCUlJXnGT15eniIjIzV27FhPm5SUFDmdTm3fvt3nNeP8zyqHw6HIyEiv7UuXLtUVV1yhUaNG6YknnugQt4zazZYtWxQTE6Mrr7xS9957r06ePOl5j7FkPaWlpfr3v/+tu+66q8l7jCff+e75d1vO7fLy8jRs2DDFxsZ62qSlpamiokKffPKJD6u/eIH+LgCtO3HihBoaGrz+g0lSbGysPv/8cz9VhUZut1sPPvigrrnmGg0dOtSz/ec//7kSEhIUHx+vPXv2aMGCBSosLNSrr77qx2o7l6SkJD3//PO68sordfToUS1ZskQTJkzQ3r17VVJSoqCgoCYnsLGx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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))\n", "fig.suptitle('Training Metrics')\n", "\n", "axes[0].set_ylabel(\"Loss\", fontsize=14)\n", "axes[0].plot(train_loss_results)\n", "\n", "axes[1].set_ylabel(\"Accuracy\", fontsize=14)\n", "axes[1].set_xlabel(\"Epoch\", fontsize=14)\n", "axes[1].plot(train_accuracy_results)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "Zg8GoMZhLpGH" }, "source": [ "## モデルの有効性評価\n", "\n", "モデルがトレーニングが完了したため、パフォーマンスの統計を取得できるようになりました。\n", "\n", "*評価*とは、モデルがどれくらい効果的に予測を立てられるかを判定することです。ペンギンの分類においてモデルの有効性を判定するには、測定値をモデルに渡し、それが表すペンギンの種をモデルに問います。次に、モデルの予測を実際のラベルと比較します。たとえば、入力サンプルの半数で正しい種を選択したモデルであれば、その[*精度*](https://developers.google.com/machine-learning/glossary/#accuracy)は `0.5` となります。図 4 には、わずかに有効性の高いモデルが示されており、80% の精度で、5 回の予測の内 4 回が正解となっています。\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", " \n", " \n", " \n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", "
サンプルの特徴量ラベルモデルの予測値
5.93.04.31.511
6.93.15.42.122
5.13.31.70.500
6.0 3.4 4.5 1.6 12
5.52.54.01.311
図 4. 80% 正確なペンギンの分類器
" ] }, { "cell_type": "markdown", "metadata": { "id": "z-EvK7hGL0d8" }, "source": [ "### テストセットをセットアップする\n", "\n", "モデルの評価はモデルの訓練と同様です。もっとも大きな違いは、サンプルが訓練用データセットではなく[*テスト用データセット(test set)*](https://developers.google.com/machine-learning/crash-course/glossary#test_set) からのものであるという点です。モデルの有効性を正しく評価するには、モデルの評価に使うサンプルは訓練用データセットのものとは違うものでなければなりません。\n", "\n", "penguin データセットには、別途テストデータセットが用意されていないため、当然、前述のデータセットのダウンロードセクションのデータセットにもテストデータセットはありません。そこで、元のデータセットをテストデータセットとトレーニングデータセットに分割します。評価には、`ds_test_batch` データセットを使用してください。" ] }, { "cell_type": "markdown", "metadata": { "id": "HFuOKXJdMAdm" }, "source": [ "### テスト用データセットでのモデルの評価\n", "\n", "トレーニングの段階とは異なり、このモデルはテストデータの 1 つの[エポック](https://developers.google.com/machine-learning/glossary/#epoch)しか評価しません。次のコードはテストセットの各サンプルを反復し、モデルの予測を実際のラベルに比較します。この比較は、テストセット全体におけるモデルの精度を測定するために使用されます。" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:38.071598Z", "iopub.status.busy": "2022-12-15T02:50:38.070736Z", "iopub.status.idle": "2022-12-15T02:50:38.304717Z", "shell.execute_reply": "2022-12-15T02:50:38.303822Z" }, "id": "Tw03-MK1cYId" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Test set accuracy: 95.522%\n" ] } ], "source": [ "test_accuracy = tf.keras.metrics.Accuracy()\n", "ds_test_batch = ds_test.batch(10)\n", "\n", "for (x, y) in ds_test_batch:\n", " # training=False is needed only if there are layers with different\n", " # behavior during training versus inference (e.g. Dropout).\n", " logits = model(x, training=False)\n", " prediction = tf.math.argmax(logits, axis=1, output_type=tf.int64)\n", " test_accuracy(prediction, y)\n", "\n", "print(\"Test set accuracy: {:.3%}\".format(test_accuracy.result()))" ] }, { "cell_type": "markdown", "metadata": { "id": "Fel8ql2qzGlK" }, "source": [ "また、`model.evaluate(ds_test, return_dict=True)` Keras 関数を使用して、テストデータセットの精度情報を取得することもできます。 " ] }, { "cell_type": "markdown", "metadata": { "id": "HcKEZMtCOeK-" }, "source": [ "たとえば、最後のバッチを調べて、モデルの予測が通常正しい予測であることを観察することができます。\n" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:38.308828Z", "iopub.status.busy": "2022-12-15T02:50:38.308194Z", "iopub.status.idle": "2022-12-15T02:50:38.315407Z", "shell.execute_reply": "2022-12-15T02:50:38.314708Z" }, "id": "uNwt2eMeOane" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.stack([y,prediction],axis=1)" ] }, { "cell_type": "markdown", "metadata": { "id": "7Li2r1tYvW7S" }, "source": [ "## 訓練済みモデルを使った予測\n", "\n", "モデルをトレーニングし、ペンギンの種を分類する上でモデルが良好であることを「証明」しました(ただし、完璧ではありません)。では、トレーニング済みのモデルを使用して、[*ラベルなしのサンプル*](https://developers.google.com/machine-learning/glossary/#unlabeled_example)、つまりラベルのない特徴量を含むサンプルで予測を立ててみましょう。\n", "\n", "実際には、ラベルなしのサンプルは、アプリ、CSV ファイル、データフィードといったさまざまなソースから取得される場合がありますが、このチュートリアルでは、ラベルなしのサンプルを手動で提供して、それぞれのラベルを予測することにします。ラベル番号は、次のように指定されていることを思い出してください。\n", "\n", "- `0`: アデリーペンギン\n", "- `1`: ヒゲペンギン\n", "- `2`: ジェンツーペンギン" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2022-12-15T02:50:38.319199Z", "iopub.status.busy": "2022-12-15T02:50:38.318584Z", "iopub.status.idle": "2022-12-15T02:50:38.333315Z", "shell.execute_reply": "2022-12-15T02:50:38.332575Z" }, "id": "kesTS5Lzv-M2" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Example 0 prediction: Adélie (77.2%)\n", "Example 1 prediction: Gentoo (97.7%)\n", "Example 2 prediction: Chinstrap (67.9%)\n" ] } ], "source": [ "predict_dataset = tf.convert_to_tensor([\n", " [0.3, 0.8, 0.4, 0.5,],\n", " [0.4, 0.1, 0.8, 0.5,],\n", " [0.7, 0.9, 0.8, 0.4]\n", "])\n", "\n", "# training=False is needed only if there are layers with different\n", "# behavior during training versus inference (e.g. Dropout).\n", "predictions = model(predict_dataset, training=False)\n", "\n", "for i, logits in enumerate(predictions):\n", " class_idx = tf.math.argmax(logits).numpy()\n", " p = tf.nn.softmax(logits)[class_idx]\n", " name = class_names[class_idx]\n", " print(\"Example {} prediction: {} ({:4.1f}%)\".format(i, name, 100*p))" ] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "custom_training_walkthrough.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" } }, "nbformat": 4, "nbformat_minor": 0 }