{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "[IAML] Tutorial Head API.ipynb", "version": "0.3.2", "views": {}, "default_view": {}, "provenance": [], "collapsed_sections": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "accelerator": "GPU" }, "cells": [ { "metadata": { "id": "dIXDTvwosP5I", "colab_type": "text" }, "cell_type": "markdown", "source": [ "# Multi-task learning TensorFlow with the Head API\n", "\n", "This notebook is a companion to the following blog post: \n", "https://iaml.it/blog/multitask-learning-tensorflow/" ] }, { "metadata": { "id": "BAFgGCKOscr-", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Prerequisites" ] }, { "metadata": { "id": "I2u1K6eO7U6_", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 952 }, "outputId": "4e2c9153-64ef-4f82-d25a-c51e00beedba", "executionInfo": { "status": "ok", "timestamp": 1523349001426, "user_tz": -120, "elapsed": 38616, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Install all necessary packages\n", "!pip install tensorflow tqdm requests --upgrade" ], "execution_count": 1, "outputs": [ { "output_type": "stream", "text": [ "Collecting tensorflow\n", " Downloading tensorflow-1.7.0-cp36-cp36m-manylinux1_x86_64.whl (48.0MB)\n", "\u001b[K 100% |████████████████████████████████| 48.0MB 29kB/s \n", "\u001b[?25hCollecting tqdm\n", " Downloading tqdm-4.21.0-py2.py3-none-any.whl (42kB)\n", "\u001b[K 100% |████████████████████████████████| 51kB 10.9MB/s \n", "\u001b[?25hRequirement already up-to-date: requests in /usr/local/lib/python3.6/dist-packages\n", "Requirement already up-to-date: astor>=0.6.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow)\n", "Requirement already up-to-date: six>=1.10.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow)\n", "Requirement already up-to-date: absl-py>=0.1.6 in /usr/local/lib/python3.6/dist-packages (from tensorflow)\n", "Collecting grpcio>=1.8.6 (from tensorflow)\n", " Downloading grpcio-1.10.1-cp36-cp36m-manylinux1_x86_64.whl (7.7MB)\n", "\u001b[K 100% |████████████████████████████████| 7.7MB 182kB/s \n", "\u001b[?25hRequirement already up-to-date: termcolor>=1.1.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow)\n", "Collecting tensorboard<1.8.0,>=1.7.0 (from tensorflow)\n", " Downloading tensorboard-1.7.0-py3-none-any.whl (3.1MB)\n", "\u001b[K 100% |████████████████████████████████| 3.1MB 441kB/s \n", "\u001b[?25hCollecting wheel>=0.26 (from tensorflow)\n", " Downloading wheel-0.31.0-py2.py3-none-any.whl (41kB)\n", "\u001b[K 100% |████████████████████████████████| 51kB 11.1MB/s \n", "\u001b[?25hCollecting protobuf>=3.4.0 (from tensorflow)\n", " Downloading protobuf-3.5.2.post1-cp36-cp36m-manylinux1_x86_64.whl (6.4MB)\n", "\u001b[K 100% |████████████████████████████████| 6.4MB 207kB/s \n", "\u001b[?25hRequirement already up-to-date: gast>=0.2.0 in /usr/local/lib/python3.6/dist-packages (from tensorflow)\n", "Requirement already up-to-date: numpy>=1.13.3 in /usr/local/lib/python3.6/dist-packages (from tensorflow)\n", "Requirement already up-to-date: idna<2.7,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests)\n", "Requirement already up-to-date: urllib3<1.23,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests)\n", "Requirement already up-to-date: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests)\n", "Requirement already up-to-date: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests)\n", "Requirement already up-to-date: markdown>=2.6.8 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.8.0,>=1.7.0->tensorflow)\n", "Requirement already up-to-date: html5lib==0.9999999 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.8.0,>=1.7.0->tensorflow)\n", "Requirement already up-to-date: werkzeug>=0.11.10 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.8.0,>=1.7.0->tensorflow)\n", "Requirement already up-to-date: bleach==1.5.0 in /usr/local/lib/python3.6/dist-packages (from tensorboard<1.8.0,>=1.7.0->tensorflow)\n", "Collecting setuptools (from protobuf>=3.4.0->tensorflow)\n", " Downloading setuptools-39.0.1-py2.py3-none-any.whl (569kB)\n", "\u001b[K 100% |████████████████████████████████| 573kB 2.3MB/s \n", "\u001b[?25hInstalling collected packages: setuptools, protobuf, grpcio, wheel, tensorboard, tensorflow, tqdm\n", " Found existing installation: setuptools 36.2.7\n", " Not uninstalling setuptools at /usr/lib/python3/dist-packages, outside environment /usr\n", " Found existing installation: protobuf 3.5.2\n", " Uninstalling protobuf-3.5.2:\n", " Successfully uninstalled protobuf-3.5.2\n", " Found existing installation: grpcio 1.10.0\n", " Uninstalling grpcio-1.10.0:\n", " Successfully uninstalled grpcio-1.10.0\n", " Found existing installation: wheel 0.30.0\n", " Uninstalling wheel-0.30.0:\n", " Successfully uninstalled wheel-0.30.0\n", " Found existing installation: tensorboard 1.6.0\n", " Uninstalling tensorboard-1.6.0:\n", " Successfully uninstalled tensorboard-1.6.0\n" ], "name": "stdout" }, { "output_type": "stream", "text": [ " Found existing installation: tensorflow 1.6.0\n", " Uninstalling tensorflow-1.6.0:\n", " Successfully uninstalled tensorflow-1.6.0\n", "Successfully installed grpcio-1.10.1 protobuf-3.5.2.post1 setuptools-39.0.1 tensorboard-1.7.0 tensorflow-1.7.0 tqdm-4.21.0 wheel-0.31.0\n" ], "name": "stdout" } ] }, { "metadata": { "id": "LgWC6pqx8dsN", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Data download" ] }, { "metadata": { "id": "QS7cpKjW7vI2", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 34 }, "outputId": "aa8511a5-47eb-48f1-d018-cd3a23d129cf", "executionInfo": { "status": "ok", "timestamp": 1523350544090, "user_tz": -120, "elapsed": 1542624, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Dataset is taken from here: http://mmlab.ie.cuhk.edu.hk/projects/TCDCN.html\n", "# Small code is taken from this StackOverflow thread: https://stackoverflow.com/questions/22676/how-do-i-download-a-file-over-http-using-python\n", "# This could take a while!\n", "\n", "from tqdm import tqdm\n", "import requests\n", "\n", "url = \"http://mmlab.ie.cuhk.edu.hk/projects/TCDCN/data/MTFL.zip\"\n", "response = requests.get(url, stream=True)\n", "\n", "with open(\"MTFL\", \"wb\") as handle:\n", " for data in tqdm(response.iter_content(), unit=' KB'):\n", " handle.write(data)" ], "execution_count": 2, "outputs": [ { "output_type": "stream", "text": [ "150152960 KB [25:41, 97417.50 KB/s]\n" ], "name": "stderr" } ] }, { "metadata": { "id": "L68VPXP1B5S7", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# Unzip all files\n", "import zipfile\n", "zip_ref = zipfile.ZipFile('MTFL', 'r')\n", "zip_ref.extractall()\n", "zip_ref.close()" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "vqhQv5NIDGmB", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 34 }, "outputId": "01d5cf6d-66de-4cde-a4f2-326cf964771d", "executionInfo": { "status": "ok", "timestamp": 1523350550840, "user_tz": -120, "elapsed": 1425, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "!ls" ], "execution_count": 4, "outputs": [ { "output_type": "stream", "text": [ "AFLW datalab lfw_5590 MTFL net_7876 readme.txt testing.txt training.txt\r\n" ], "name": "stdout" } ] }, { "metadata": { "id": "VkksetbBslN8", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Data loading in Pandas" ] }, { "metadata": { "id": "irEagJdmDJ2Z", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# Import dataset in Pandas\n", "import pandas as pd\n", "train_data = pd.read_csv('training.txt', sep=' ', header=None, skipinitialspace=True, nrows=10000)\n", "test_data = pd.read_csv('testing.txt', sep=' ', header=None, skipinitialspace=True, nrows=2995)" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "k7R8CpmbDZCZ", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 305 }, "outputId": "25855091-15f2-4f40-9ba1-ba85d7b4b6b0", "executionInfo": { "status": "ok", "timestamp": 1523109020133, "user_tz": -120, "elapsed": 470, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "train_data.iloc[0]" ], "execution_count": 7, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "0 lfw_5590\\Aaron_Eckhart_0001.jpg\n", "1 107.25\n", "2 147.75\n", "3 126.25\n", "4 106.25\n", "5 140.75\n", "6 108.75\n", "7 113.25\n", "8 143.75\n", "9 158.75\n", "10 162.75\n", "11 1\n", "12 2\n", "13 2\n", "14 3\n", "Name: 0, dtype: object" ] }, "metadata": { "tags": [] }, "execution_count": 7 } ] }, { "metadata": { "id": "ljtpu_GNkjEq", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "train_data.iloc[:, 0] = train_data.iloc[:, 0].apply(lambda s: s.replace('\\\\', '/')) # Needed for filename convention\n", "test_data.iloc[:, 0] = test_data.iloc[:, 0].apply(lambda s: s.replace('\\\\', '/')) # Needed for filename convention" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "YxTTMzFq-SRO", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "from sklearn import preprocessing\n", "train_data.iloc[:, 1:11] = preprocessing.MinMaxScaler().fit_transform(train_data.iloc[:, 1:11])\n", "test_data.iloc[:, 1:11] = preprocessing.MinMaxScaler().fit_transform(test_data.iloc[:, 1:11])" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "OoXmkV3KFIzx", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Data loading with tf.data" ] }, { "metadata": { "id": "N8aOYmorDcAg", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "import numpy as np\n", "import tensorflow as tf" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "1cYVCq3nuheK", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 34 }, "outputId": "0e083323-02fe-4dfc-ffa7-a954a4472d3d", "executionInfo": { "status": "ok", "timestamp": 1523353399399, "user_tz": -120, "elapsed": 523, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Example code for handling datasets\n", "\n", "filenames = tf.constant(train_data.iloc[:, 0].tolist())\n", "labels = tf.constant(train_data.iloc[:, 1:].values)\n", "\n", "dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))\n", "\n", "it = dataset.batch(64).make_one_shot_iterator().get_next()\n", "\n", "with tf.Session() as sess:\n", " (imgs, labels) = sess.run(it)\n", " print(imgs[0])" ], "execution_count": 23, "outputs": [ { "output_type": "stream", "text": [ "b'lfw_5590/Aaron_Eckhart_0001.jpg'\n" ], "name": "stdout" } ] }, { "metadata": { "id": "oc8R1cCVkbXj", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# Reads an image from a file, decodes it into a dense tensor, and resizes it\n", "# to a fixed shape.\n", "def _parse_function(filename, label):\n", " image_string = tf.read_file(filename) \n", " image_decoded = tf.image.decode_jpeg(image_string, channels=3) # Channels needed because some test images are b/w\n", " image_resized = tf.image.resize_images(image_decoded, [40, 40])\n", " return {\"x\": image_resized}, label" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "c74OEdVaEi_v", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# This snippet is adapted from here: https://www.tensorflow.org/programmers_guide/datasets\n", "\n", "def input_fn(data, is_eval=False):\n", "\n", " # Path delle immagini\n", " filenames = tf.constant(data.iloc[:, 0].tolist())\n", "\n", " # Etichette delle immagini\n", " labels = tf.constant(data.iloc[:, 1:].values.astype(np.float32))\n", "\n", " # Costruisco il dataset\n", " dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))\n", " dataset = dataset.map(_parse_function)\n", "\n", " # Logica di training / testing\n", " if is_eval:\n", " dataset = dataset.batch(64)\n", " else:\n", " dataset = dataset.repeat().shuffle(1000).batch(64)\n", " \n", " # Costruisco l'iteratore\n", " return dataset.make_one_shot_iterator().get_next()\n", " \n", " #for (filename, label) in tfe.Iterator(dataset):\n", " # d = _parse_function(filename, label)" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "yZKbUwaUEjwf", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 398 }, "outputId": "e35f4353-e9b7-4092-da8f-f47557cd36a6", "executionInfo": { "status": "ok", "timestamp": 1523354055189, "user_tz": -120, "elapsed": 1107, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "import matplotlib.pyplot as plt\n", "with tf.Session() as sess:\n", " (imgs, labels) = sess.run(input_fn(train_data, True))\n", " plt.imshow(imgs[\"x\"][0] / 255)\n", " print(labels[0])" ], "execution_count": 63, "outputs": [ { "output_type": "stream", "text": [ "[0.33482143 0.32603687 0.3471564 0.3612805 0.2852697 0.4357639\n", " 0.47532895 0.41169155 0.35 0.36334747 1. 2.\n", " 2. 3. ]\n" ], "name": "stdout" }, { "output_type": "display_data", "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "npKsVLjwNjD0", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Standard classical estimator (single-task only!)" ] }, { "metadata": { "id": "pVnf_A-rX3Fb", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "def extract_features(features):\n", " # Input Layer\n", " input_layer = tf.reshape(features[\"x\"], [-1, 40, 40, 3])\n", "\n", " # Primo layer convolutivo\n", " conv1 = tf.layers.conv2d(inputs=input_layer, filters=16, kernel_size=[5, 5], padding=\"same\", activation=tf.nn.relu)\n", " pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)\n", "\n", " # Secondo layer convolutivo\n", " conv2 = tf.layers.conv2d(inputs=pool1, filters=48, kernel_size=[3, 3], padding=\"same\", activation=tf.nn.relu)\n", " pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)\n", "\n", " # Terzo layer convolutivo\n", " conv3 = tf.layers.conv2d(inputs=pool2, filters=64, kernel_size=[3, 3], padding=\"same\", activation=tf.nn.relu)\n", " pool3 = tf.layers.max_pooling2d(inputs=conv3, pool_size=[2, 2], strides=2)\n", " \n", " # Quarto layer convolutivo\n", " conv4 = tf.layers.conv2d(inputs=pool3, filters=64, kernel_size=[2, 2], padding=\"same\", activation=tf.nn.relu)\n", " \n", " # Dense Layer\n", " flat = tf.reshape(conv4, [-1, 5 * 5 * 64])\n", " dense = tf.layers.dense(inputs=flat, units=100, activation=tf.nn.relu)\n", " \n", " return dense" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "LWkCaYrfM7qu", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# Adapted from here: https://www.tensorflow.org/tutorials/layers\n", "\n", "def single_task_cnn_model_fn(features, labels, mode):\n", " \n", " dense = extract_features(features)\n", " \n", " # Predizioni\n", " predictions = tf.layers.dense(inputs=dense, units=2)\n", "\n", " outputs = {\n", " \"predictions\": predictions\n", " }\n", "\n", " if mode == tf.estimator.ModeKeys.PREDICT:\n", " return tf.estimator.EstimatorSpec(mode=mode, predictions=outputs)\n", "\n", " # Funzione costo (errore quadratico medio)\n", " loss = tf.losses.mean_squared_error(labels=labels[:, 2:8:5], predictions=predictions)\n", "\n", " # Ottimizzazione\n", " if mode == tf.estimator.ModeKeys.TRAIN:\n", " optimizer = tf.train.AdamOptimizer()\n", " train_op = optimizer.minimize(loss=loss, global_step=tf.train.get_global_step())\n", " return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)\n", "\n", " # Valutazione del modello\n", " eval_metric_ops = {\n", " \"rmse\": tf.metrics.root_mean_squared_error(\n", " labels=labels[:, 2:8:5], predictions=outputs[\"predictions\"])}\n", " return tf.estimator.EstimatorSpec(\n", " mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "jcuFLCpMPDX-", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 71 }, "outputId": "51e24a93-7b35-402f-aae1-7958b72345db", "executionInfo": { "status": "ok", "timestamp": 1523366853307, "user_tz": -120, "elapsed": 534, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Create the Estimator\n", "single_task_classifier = tf.estimator.Estimator(\n", " model_fn=single_task_cnn_model_fn, model_dir=\"/tmp/cnn_nose\")" ], "execution_count": 189, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Using default config.\n", "INFO:tensorflow:Using config: {'_model_dir': '/tmp/cnn_nose', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_service': None, '_cluster_spec': , '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}\n" ], "name": "stdout" } ] }, { "metadata": { "id": "ow5mfv11PX6M", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 510 }, "outputId": "49aeb9ee-c664-4eb1-8668-f8c31e966a5b", "executionInfo": { "status": "ok", "timestamp": 1523367163425, "user_tz": -120, "elapsed": 306620, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Train the model\n", "single_task_classifier.train(input_fn=lambda: input_fn(train_data), steps=1000)" ], "execution_count": 190, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Create CheckpointSaverHook.\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "INFO:tensorflow:Saving checkpoints for 1 into /tmp/cnn_nose/model.ckpt.\n", "INFO:tensorflow:loss = 168.66652, step = 1\n", "INFO:tensorflow:global_step/sec: 3.21662\n", "INFO:tensorflow:loss = 0.07332276, step = 101 (31.090 sec)\n", "INFO:tensorflow:global_step/sec: 3.4082\n", "INFO:tensorflow:loss = 0.029060293, step = 201 (29.342 sec)\n", "INFO:tensorflow:global_step/sec: 3.24658\n", "INFO:tensorflow:loss = 0.04251621, step = 301 (30.803 sec)\n", "INFO:tensorflow:global_step/sec: 3.27862\n", "INFO:tensorflow:loss = 0.042185806, step = 401 (30.498 sec)\n", "INFO:tensorflow:global_step/sec: 3.36051\n", "INFO:tensorflow:loss = 0.017348655, step = 501 (29.760 sec)\n", "INFO:tensorflow:global_step/sec: 3.23404\n", "INFO:tensorflow:loss = 0.04518965, step = 601 (30.920 sec)\n", "INFO:tensorflow:global_step/sec: 3.31534\n", "INFO:tensorflow:loss = 0.043051306, step = 701 (30.163 sec)\n", "INFO:tensorflow:global_step/sec: 3.31508\n", "INFO:tensorflow:loss = 0.014098421, step = 801 (30.163 sec)\n", "INFO:tensorflow:global_step/sec: 3.2097\n", "INFO:tensorflow:loss = 0.051925942, step = 901 (31.157 sec)\n", "INFO:tensorflow:Saving checkpoints for 1000 into /tmp/cnn_nose/model.ckpt.\n", "INFO:tensorflow:Loss for final step: 0.039091345.\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { "text/plain": [ "" ] }, "metadata": { "tags": [] }, "execution_count": 190 } ] }, { "metadata": { "id": "E_TSHz9glrew", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 187 }, "outputId": "dffacd45-08bb-4202-b13c-98c1a1349daf", "executionInfo": { "status": "ok", "timestamp": 1523367174466, "user_tz": -120, "elapsed": 6976, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "single_task_classifier.evaluate(input_fn=lambda: input_fn(test_data, is_eval=True))" ], "execution_count": 191, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Starting evaluation at 2018-04-10-13:32:48\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Restoring parameters from /tmp/cnn_nose/model.ckpt-1000\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "INFO:tensorflow:Finished evaluation at 2018-04-10-13:32:54\n", "INFO:tensorflow:Saving dict for global step 1000: global_step = 1000, loss = 0.031888474, rmse = 0.17859857\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { "text/plain": [ "{'global_step': 1000, 'loss': 0.031888474, 'rmse': 0.17859857}" ] }, "metadata": { "tags": [] }, "execution_count": 191 } ] }, { "metadata": { "id": "kwPRL-A-6ZaQ", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# Funzione di input per predizioni (hack, si potrebbe migliorare!)\n", "def input_fn_predict(data):\n", "\n", " # Path delle immagini\n", " filenames = tf.constant(data.iloc[:, 0].tolist())\n", "\n", " # Etichette delle immagini\n", " labels = tf.constant(data.iloc[:, 1:].values)\n", "\n", " # Costruisco il dataset\n", " dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))\n", " dataset = dataset.map(_parse_function)\n", " dataset = dataset.batch(64)\n", " \n", " # Costruisco l'iteratore\n", " f, _ = dataset.make_one_shot_iterator().get_next()\n", " return f\n", " \n", " #for (filename, label) in tfe.Iterator(dataset):\n", " # d = _parse_function(filename, label)" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "-PlmCyy763AA", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 449 }, "outputId": "c9a57ba6-9274-4cbb-d2b7-974d3391f832", "executionInfo": { "status": "ok", "timestamp": 1523367423612, "user_tz": -120, "elapsed": 6899, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Valutiamo una singola predizione\n", "p = list(single_task_classifier.predict(lambda: input_fn_predict(test_data)))\n", "\n", "with tf.Session() as sess:\n", " imgs = sess.run(input_fn_predict(test_data))\n", " img_idx = 2\n", " plt.imshow(imgs[\"x\"][img_idx] / 255)\n", " plt.scatter(p[img_idx]['predictions'][0] * 40, p[img_idx]['predictions'][1] * 40, 500, marker='x', color='red', linewidth=5)" ], "execution_count": 198, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Restoring parameters from /tmp/cnn_nose/model.ckpt-1000\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n" ], "name": "stdout" }, { "output_type": "display_data", "data": { "image/png": "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\n2WG6mb/OAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] }, { "metadata": { "id": "7qxMQV2iBXFa", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Simplify the code with the Head API" ] }, { "metadata": { "id": "SZlF0pOQlztD", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "# Check the code here: https://www.tensorflow.org/api_docs/python/tf/contrib/estimator/regression_head\n", "\n", "def single_head_cnn_model_fn(features, labels, mode):\n", " \n", " dense = extract_features(features)\n", " \n", " # Predizioni\n", " predictions = tf.layers.dense(inputs=dense, units=2)\n", "\n", " # Ottimizzatore\n", " optimizer = tf.train.AdamOptimizer()\n", " \n", " # Modello finale\n", " regression_head = tf.contrib.estimator.regression_head(label_dimension=2)\n", " return regression_head.create_estimator_spec(features, mode, predictions, labels[:, 2:8:5], lambda x: optimizer.minimize(x, global_step = tf.train.get_or_create_global_step()))" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "NUm7W9-tu3Ij", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 71 }, "outputId": "cfedd949-a683-4ce0-f9e2-23ddd18fc846", "executionInfo": { "status": "ok", "timestamp": 1523354829827, "user_tz": -120, "elapsed": 515, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Create the Estimator\n", "cnn_classifier = tf.estimator.Estimator(\n", " model_fn=single_head_cnn_model_fn, model_dir=\"/tmp/cnn_single_head\")" ], "execution_count": 82, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Using default config.\n", "INFO:tensorflow:Using config: {'_model_dir': '/tmp/cnn_single_head', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_service': None, '_cluster_spec': , '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}\n" ], "name": "stdout" } ] }, { "metadata": { "id": "PwienXlvvHsN", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 275 }, "outputId": "8d5da45f-598c-4f18-bc31-60d4a38b3906", "executionInfo": { "status": "ok", "timestamp": 1523354872051, "user_tz": -120, "elapsed": 38294, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Train the model\n", "cnn_classifier.train(input_fn=lambda: input_fn(train_data), steps=1000)" ], "execution_count": 83, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/contrib/learn/python/learn/datasets/base.py:198: retry (from tensorflow.contrib.learn.python.learn.datasets.base) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use the retry module or similar alternatives.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Create CheckpointSaverHook.\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "INFO:tensorflow:Saving checkpoints for 1 into /tmp/cnn_single_head/model.ckpt.\n", "INFO:tensorflow:loss = 19280.736, step = 1\n", "INFO:tensorflow:Saving checkpoints for 100 into /tmp/cnn_single_head/model.ckpt.\n", "INFO:tensorflow:Loss for final step: 14.961566.\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { "text/plain": [ "" ] }, "metadata": { "tags": [] }, "execution_count": 83 } ] }, { "metadata": { "id": "ZqfxV8_hDxT0", "colab_type": "text" }, "cell_type": "markdown", "source": [ "## Multi-task learning with the Head API" ] }, { "metadata": { "id": "fA-cTIx5ZXSp", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "def multihead_input_fn(data, is_eval=False):\n", " features, labels = input_fn(data, is_eval=is_eval)\n", " return features, {'head_nose': labels[:, 2:8:5], 'head_pose': tf.cast(labels[:, -1] - 1.0, tf.int32)}" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "BHKg4Zu3vLdr", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 } } }, "cell_type": "code", "source": [ "def multi_head_cnn_model_fn(features, labels, mode):\n", " \n", " dense = extract_features(features)\n", " \n", " # Predizioni della rete (per ciascun task)\n", " predictions_nose = tf.layers.dense(inputs=dense, units=2)\n", " predictions_pose = tf.layers.dense(inputs=dense, units=5)\n", " logits = {'head_nose': predictions_nose, 'head_pose': predictions_pose}\n", " \n", " # Ottimizzatore\n", " optimizer = tf.train.AdamOptimizer()\n", " \n", " # Definiamo le due head\n", " regression_head = tf.contrib.estimator.regression_head(name='head_nose', label_dimension=2)\n", " classification_head = tf.contrib.estimator.multi_class_head(name='head_pose', n_classes=5)\n", " \n", " multi_head = tf.contrib.estimator.multi_head([regression_head, classification_head])\n", " \n", " return multi_head.create_estimator_spec(features, mode, logits, labels, lambda x: optimizer.minimize(x, global_step = tf.train.get_or_create_global_step()))" ], "execution_count": 0, "outputs": [] }, { "metadata": { "id": "Tq3qi_S8Z8vt", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 71 }, "outputId": "982d738a-6ead-4a5c-c14e-5b73b90d2968", "executionInfo": { "status": "ok", "timestamp": 1523367599414, "user_tz": -120, "elapsed": 500, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Create the Estimator\n", "multitask_classifier = tf.estimator.Estimator(\n", " model_fn=multi_head_cnn_model_fn, model_dir=\"/tmp/cnn_tmp\")" ], "execution_count": 212, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Using default config.\n", "INFO:tensorflow:Using config: {'_model_dir': '/tmp/cnn_tmp', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_service': None, '_cluster_spec': , '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}\n" ], "name": "stdout" } ] }, { "metadata": { "id": "vLBmvRJhaAJ6", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 510 }, "outputId": "aadaefb2-bc2b-4bdf-e463-b3bdc2403185", "executionInfo": { "status": "ok", "timestamp": 1523367910344, "user_tz": -120, "elapsed": 310524, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "# Train the model\n", "multitask_classifier.train(input_fn=lambda: multihead_input_fn(train_data), steps=1000)" ], "execution_count": 213, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Create CheckpointSaverHook.\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "INFO:tensorflow:Saving checkpoints for 1 into /tmp/cnn_tmp/model.ckpt.\n", "INFO:tensorflow:loss = 116749.75, step = 1\n", "INFO:tensorflow:global_step/sec: 3.18767\n", "INFO:tensorflow:loss = 77.51071, step = 101 (31.373 sec)\n", "INFO:tensorflow:global_step/sec: 3.34664\n", "INFO:tensorflow:loss = 51.99946, step = 201 (29.883 sec)\n", "INFO:tensorflow:global_step/sec: 3.1784\n", "INFO:tensorflow:loss = 89.16292, step = 301 (31.460 sec)\n", "INFO:tensorflow:global_step/sec: 3.21144\n", "INFO:tensorflow:loss = 40.797005, step = 401 (31.138 sec)\n", "INFO:tensorflow:global_step/sec: 3.3237\n", "INFO:tensorflow:loss = 39.19834, step = 501 (30.088 sec)\n", "INFO:tensorflow:global_step/sec: 3.19385\n", "INFO:tensorflow:loss = 62.40456, step = 601 (31.310 sec)\n", "INFO:tensorflow:global_step/sec: 3.27872\n", "INFO:tensorflow:loss = 44.629475, step = 701 (30.499 sec)\n", "INFO:tensorflow:global_step/sec: 3.28512\n", "INFO:tensorflow:loss = 23.16358, step = 801 (30.443 sec)\n", "INFO:tensorflow:global_step/sec: 3.21363\n", "INFO:tensorflow:loss = 47.13872, step = 901 (31.115 sec)\n", "INFO:tensorflow:Saving checkpoints for 1000 into /tmp/cnn_tmp/model.ckpt.\n", "INFO:tensorflow:Loss for final step: 29.839733.\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { "text/plain": [ "" ] }, "metadata": { "tags": [] }, "execution_count": 213 } ] }, { "metadata": { "id": "LlhkKD5haCg0", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 309 }, "outputId": "0cc3edd0-9a3b-45cf-c17c-636eaf5375f7", "executionInfo": { "status": "ok", "timestamp": 1523367932692, "user_tz": -120, "elapsed": 6825, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ " multitask_classifier.evaluate(input_fn=lambda: multihead_input_fn(test_data, is_eval=True))" ], "execution_count": 214, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Starting evaluation at 2018-04-10-13:45:26\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Restoring parameters from /tmp/cnn_tmp/model.ckpt-1000\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "INFO:tensorflow:Finished evaluation at 2018-04-10-13:45:32\n", "INFO:tensorflow:Saving dict for global step 1000: accuracy/head_pose = 0.6290484, average_loss/head_nose = 0.0408225, average_loss/head_pose = 1.1491545, global_step = 1000, loss = 78.43075, loss/head_nose = 5.2026973, loss/head_pose = 73.22804\n" ], "name": "stdout" }, { "output_type": "execute_result", "data": { "text/plain": [ "{'accuracy/head_pose': 0.6290484,\n", " 'average_loss/head_nose': 0.0408225,\n", " 'average_loss/head_pose': 1.1491545,\n", " 'global_step': 1000,\n", " 'loss': 78.43075,\n", " 'loss/head_nose': 5.2026973,\n", " 'loss/head_pose': 73.22804}" ] }, "metadata": { "tags": [] }, "execution_count": 214 } ] }, { "metadata": { "id": "Ih8VI410nPf1", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 170 }, "outputId": "7477cc29-7c1d-4a23-b8fa-9b8c0061570b", "executionInfo": { "status": "ok", "timestamp": 1523367995953, "user_tz": -120, "elapsed": 6132, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "p = list(multitask_classifier.predict(lambda: input_fn_predict(test_data)))\n", "print(p[0])" ], "execution_count": 216, "outputs": [ { "output_type": "stream", "text": [ "INFO:tensorflow:Calling model_fn.\n", "INFO:tensorflow:Done calling model_fn.\n", "INFO:tensorflow:Graph was finalized.\n", "INFO:tensorflow:Restoring parameters from /tmp/cnn_tmp/model.ckpt-1000\n", "INFO:tensorflow:Running local_init_op.\n", "INFO:tensorflow:Done running local_init_op.\n", "{('head_nose', 'predictions'): array([0.3372714 , 0.45653588], dtype=float32), ('head_pose', 'logits'): array([-2.9481742 , 1.0806224 , 2.5040638 , 0.86770856, -1.2734869 ],\n", " dtype=float32), ('head_pose', 'probabilities'): array([0.0029306 , 0.16468 , 0.6836497 , 0.13309863, 0.01564099],\n", " dtype=float32), ('head_pose', 'class_ids'): array([2]), ('head_pose', 'classes'): array([b'2'], dtype=object)}\n" ], "name": "stdout" } ] }, { "metadata": { "id": "PylNZUlnGKHS", "colab_type": "code", "colab": { "autoexec": { "startup": false, "wait_interval": 0 }, "base_uri": "https://localhost:8080/", "height": 347 }, "outputId": "d7497f36-08fa-4064-d9b8-847456af6fbb", "executionInfo": { "status": "ok", "timestamp": 1523368063321, "user_tz": -120, "elapsed": 1720, "user": { "displayName": "Simone Scardapane", "photoUrl": "//lh6.googleusercontent.com/-ZK0nd0iCe7w/AAAAAAAAAAI/AAAAAAAAA_o/pNhWxdOsGTI/s50-c-k-no/photo.jpg", "userId": "115632300554726808471" } } }, "cell_type": "code", "source": [ "with tf.Session() as sess:\n", " imgs = sess.run(input_fn_predict(test_data))\n", " \n", " font = {'family': 'serif',\n", " 'color': 'white',\n", " 'weight': 'bold',\n", " 'size': 16,\n", " }\n", "\n", " img_idx = 8\n", "\n", " prediction_eye = p[img_idx][(('head_nose', 'predictions'))]\n", " prediction_pose = p[img_idx][(('head_pose', 'class_ids'))]\n", " \n", " plt.imshow(imgs[\"x\"][img_idx] / 255)\n", " plt.scatter(prediction_eye[0] * 40, prediction_eye[1] * 40, 500, marker='x', color='red', linewidth=5)\n", " plt.text(5, 3, 'Predicted pose: {}'.format(prediction_pose), fontdict=font)" ], "execution_count": 227, "outputs": [ { "output_type": "display_data", "data": { "image/png": "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\neAAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": { "tags": [] } } ] } ] }