blob: 4a1f1aad923d36b4e0026f655114d9e7e92ad904 [file] [log] [blame]
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"name": "mnist_tensorflow.ipynb",
"provenance": [],
"collapsed_sections": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "PZtRtMMUZHJS"
},
"source": [
"##### Copyright 2020 Google LLC.\n",
"\n",
"Licensed under the Apache License, Version 2.0 (the \"License\");"
]
},
{
"cell_type": "code",
"metadata": {
"cellView": "form",
"id": "TouZL3JZZSQe"
},
"source": [
"#@title License header\n",
"# Copyright 2020 Google LLC\n",
"#\n",
"# 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."
],
"execution_count": 1,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "O6c3qfq5Zv57"
},
"source": [
"# MNIST Model TensorFlow Training, IREE Execution\n",
"\n",
"## Overview\n",
"\n",
"This notebook creates and trains a TensorFlow 2.0 model for recognizing handwritten digits using the [MNIST dataset](https://en.wikipedia.org/wiki/MNIST_database), then compiles and executes that trained model using IREE.\n",
"\n",
"## Running Locally\n",
"\n",
"* Refer to [using_colab.md](https://google.github.io/iree/using-iree/using-colab) for general information\n",
"* Ensure that you have a recent version of TensorFlow 2.0 [installed on your system](https://www.tensorflow.org/install)\n",
"* Enable IREE/TF integration by adding to your user.bazelrc: `build --define=iree_tensorflow=true`\n",
"* Start colab by running `python colab/start_colab_kernel.py` (see that file for additional instructions)\n",
"* Note: you may need to restart your runtime in order to re-run certain cells. Some of the APIs are not yet stable enough for repeated invocations"
]
},
{
"cell_type": "code",
"metadata": {
"cellView": "both",
"id": "EPF7RGQDYK-M",
"outputId": "524db42f-b1d0-4f26-c911-3dc32bb19ba0",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 68
}
},
"source": [
"#@title Imports and Setup\n",
"\n",
"from pyiree import rt as ireert\n",
"from pyiree.tf import compiler as ireec\n",
"from pyiree.tf.support import module_utils\n",
"\n",
"from matplotlib import pyplot as plt\n",
"import numpy as np\n",
"import os\n",
"import tempfile\n",
"import tensorflow as tf\n",
"\n",
"ARTIFACTS_DIR = os.path.join(tempfile.gettempdir(), 'iree', 'modules')\n",
"print(\"Artifacts directory is: \", ARTIFACTS_DIR)\n",
"\n",
"plt.style.use(\"seaborn-whitegrid\")\n",
"plt.rcParams[\"font.family\"] = \"monospace\"\n",
"\n",
"# Print version information for future notebook users to reference.\n",
"print(\"TensorFlow version: \", tf.__version__)\n",
"print(\"Numpy version: \", np.__version__)"
],
"execution_count": 2,
"outputs": [
{
"output_type": "stream",
"text": [
"Artifacts directory is: C:\\Users\\Scott\\AppData\\Local\\Temp\\iree\\modules\n",
"TensorFlow version: 2.5.0-dev20200626\n",
"Numpy version: 1.18.4\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "5vkQOMOMbXdy"
},
"source": [
"# Create and Train MNIST Model in TensorFlow\n",
"\n",
"The specific details of the training process here aren't critical to the model compilation and execution through IREE."
]
},
{
"cell_type": "code",
"metadata": {
"cellView": "both",
"id": "XPo8ATGqqZbW",
"outputId": "acfd2492-a7c5-484a-e9af-7d1a58579dc2",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 314
}
},
"source": [
"#@title Load MNIST dataset, setup training and evaluation\n",
"\n",
"# Keras datasets don't provide metadata.\n",
"NUM_CLASSES = 10\n",
"NUM_ROWS, NUM_COLS = 28, 28\n",
"\n",
"(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()\n",
"\n",
"# Reshape into grayscale images:\n",
"x_train = np.reshape(x_train, (-1, NUM_ROWS, NUM_COLS, 1))\n",
"x_test = np.reshape(x_test, (-1, NUM_ROWS, NUM_COLS, 1))\n",
"\n",
"# Rescale uint8 pixel values into floats:\n",
"x_train = x_train / 255\n",
"x_test = x_test / 255\n",
"\n",
"# Explicitly cast to float32 because numpy defaults to double precision and\n",
"# IREE uses single precision:\n",
"x_train = x_train.astype(np.float32)\n",
"x_test = x_test.astype(np.float32)\n",
"\n",
"print(\"Sample image from the dataset:\")\n",
"sample_index = np.random.randint(x_train.shape[0])\n",
"plt.imshow(x_train[sample_index].reshape(NUM_ROWS, NUM_COLS), cmap=\"gray\")\n",
"plt.title(f\"Sample #{sample_index}, label: {y_train[sample_index]}\")\n",
"plt.axis(\"off\")\n",
"plt.tight_layout()"
],
"execution_count": 3,
"outputs": [
{
"output_type": "stream",
"text": [
"Sample image from the dataset:\n"
],
"name": "stdout"
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {
"tags": []
}
}
]
},
{
"cell_type": "code",
"metadata": {
"cellView": "both",
"id": "tHq96SIJcNfx"
},
"source": [
"#@title Define a DNN model using tf.keras API\n",
"\n",
"def simple_dnn(num_classes):\n",
" \"\"\"Creates a simple multi-layer perceptron model.\"\"\"\n",
"\n",
" model = tf.keras.models.Sequential()\n",
" # Flatten to a 1d array (e.g. 28x28x1 -> 784).\n",
" model.add(tf.keras.layers.Flatten())\n",
" # Fully-connected neural layer with 128 neurons, RELU activation.\n",
" model.add(tf.keras.layers.Dense(128, activation=\"relu\"))\n",
" # Fully-connected neural layer returning probability scores for each class.\n",
" model.add(tf.keras.layers.Dense(num_classes, activation=\"softmax\"))\n",
" return model"
],
"execution_count": 4,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"cellView": "both",
"id": "43BH_9YcsGs8"
},
"source": [
"#@markdown ### Training Parameters\n",
"\n",
"batch_size = 32 #@param { type: \"slider\", min: 10, max: 400 }\n",
"num_epochs = 8 #@param { type: \"slider\", min: 1, max: 20 }"
],
"execution_count": 5,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"cellView": "both",
"id": "7Gdxh7qWcPSO",
"outputId": "4017f6c9-9ca0-4e72-dc8a-104465231644",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 306
}
},
"source": [
"#@title Train the Keras model\n",
"\n",
"tf_model = simple_dnn(NUM_CLASSES)\n",
"# Stateful optimizers like Adam create variable incompatible with compilation as\n",
"# currently implemented.\n",
"tf_model.compile(\n",
" optimizer=\"sgd\", loss=\"sparse_categorical_crossentropy\", metrics=\"accuracy\")\n",
"tf_model.fit(x_train, y_train, batch_size, num_epochs, validation_split=0.1)"
],
"execution_count": 6,
"outputs": [
{
"output_type": "stream",
"text": [
"Epoch 1/8\n",
"1688/1688 [==============================] - 1s 657us/step - loss: 0.6559 - accuracy: 0.8389 - val_loss: 0.3182 - val_accuracy: 0.9182\n",
"Epoch 2/8\n",
"1688/1688 [==============================] - 1s 542us/step - loss: 0.3476 - accuracy: 0.9031 - val_loss: 0.2620 - val_accuracy: 0.9287\n",
"Epoch 3/8\n",
"1688/1688 [==============================] - 1s 539us/step - loss: 0.2992 - accuracy: 0.9163 - val_loss: 0.2299 - val_accuracy: 0.9368\n",
"Epoch 4/8\n",
"1688/1688 [==============================] - 1s 542us/step - loss: 0.2687 - accuracy: 0.9249 - val_loss: 0.2095 - val_accuracy: 0.9428\n",
"Epoch 5/8\n",
"1688/1688 [==============================] - 1s 541us/step - loss: 0.2456 - accuracy: 0.9308 - val_loss: 0.1965 - val_accuracy: 0.9423\n",
"Epoch 6/8\n",
"1688/1688 [==============================] - 1s 538us/step - loss: 0.2269 - accuracy: 0.9362 - val_loss: 0.1806 - val_accuracy: 0.9500\n",
"Epoch 7/8\n",
"1688/1688 [==============================] - 1s 542us/step - loss: 0.2106 - accuracy: 0.9409 - val_loss: 0.1685 - val_accuracy: 0.9548\n",
"Epoch 8/8\n",
"1688/1688 [==============================] - 1s 545us/step - loss: 0.1971 - accuracy: 0.9444 - val_loss: 0.1601 - val_accuracy: 0.9588\n"
],
"name": "stdout"
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x15e010aac40>"
]
},
"metadata": {
"tags": []
},
"execution_count": 6
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nZdVUd_dgTtc"
},
"source": [
"# Compile and Execute MNIST Model using IREE"
]
},
{
"cell_type": "code",
"metadata": {
"id": "DmespEaFcSEL"
},
"source": [
"#@title Wrap the model in a tf.Module with IREE-compatible settings and convert to MLIR.\n",
"\n",
"# Since the model was written in sequential style, explicitly wrap in a module.\n",
"inference_module = tf.Module()\n",
"inference_module.model = tf_model\n",
"\n",
"# Hack: Convert to static shape. Won't be necessary once dynamic shapes are in.\n",
"input_shape = list(tf_model.inputs[0].shape)\n",
"input_shape[0] = 1 # Make fixed (batch=1)\n",
"\n",
"# Produce a concrete function to compile.\n",
"inference_module.predict = tf.function(input_signature=[\n",
" tf.TensorSpec(input_shape, tf_model.inputs[0].dtype)\n",
"])(lambda x: tf_model.call(x, training=False))\n",
"\n",
"# Only try to compile the function we care about:\n",
"exported_names = [\"predict\"]"
],
"execution_count": 7,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "G7v-2EbjyggO"
},
"source": [
"#@markdown ### Backend Configuration\n",
"\n",
"backend_choice = \"iree_vmla (CPU)\" #@param [ \"iree_vmla (CPU)\", \"iree_llvmjit (CPU)\", \"iree_vulkan (GPU/SwiftShader)\" ]\n",
"backend_choice = backend_choice.split(\" \")[0]\n",
"backend = module_utils.BackendInfo(backend_choice)"
],
"execution_count": 8,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "IDHI7h3khJr9",
"outputId": "2d4117fb-f1d4-4788-8ad4-cd50bdf0e5a5",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 459
}
},
"source": [
"#@title Compile the mhlo MLIR to an IREE backend and prepare a context to execute it\n",
"\n",
"iree_module = module_utils.IreeCompiledModule.create_from_instance(\n",
" inference_module, backend, exported_names, ARTIFACTS_DIR)\n",
"\n",
"print(\"* Module compiled! See intermediate .mlir files in\", ARTIFACTS_DIR, \"*\")"
],
"execution_count": 9,
"outputs": [
{
"output_type": "stream",
"text": [
"WARNING:tensorflow:AutoGraph could not transform <function <lambda> at 0x0000015E0A89D160> and will run it as-is.\n",
"Cause: could not parse the source code:\n",
"\n",
"])(lambda x: tf_model.call(x, training=False))\n",
"\n",
"This error may be avoided by creating the lambda in a standalone statement.\n",
"\n",
"To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert\n",
"WARNING: AutoGraph could not transform <function <lambda> at 0x0000015E0A89D160> and will run it as-is.\n",
"Cause: could not parse the source code:\n",
"\n",
"])(lambda x: tf_model.call(x, training=False))\n",
"\n",
"This error may be avoided by creating the lambda in a standalone statement.\n",
"\n",
"To silence this warning, decorate the function with @tf.autograph.experimental.do_not_convert\n",
"WARNING:tensorflow:From c:\\users\\scott\\scoop\\apps\\python\\current\\lib\\site-packages\\tensorflow\\python\\training\\tracking\\tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.\n",
"Instructions for updating:\n",
"This property should not be used in TensorFlow 2.0, as updates are applied automatically.\n",
"WARNING:tensorflow:From c:\\users\\scott\\scoop\\apps\\python\\current\\lib\\site-packages\\tensorflow\\python\\training\\tracking\\tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.\n",
"Instructions for updating:\n",
"This property should not be used in TensorFlow 2.0, as updates are applied automatically.\n",
"INFO:tensorflow:Assets written to: C:\\Users\\Scott\\AppData\\Local\\Temp\\tmpd667eaqu\\assets\n",
"* Module compiled! See intermediate .mlir files in C:\\Users\\Scott\\AppData\\Local\\Temp\\iree\\modules *\n"
],
"name": "stdout"
},
{
"output_type": "stream",
"text": [
"Created IREE driver vmla: <pyiree.rt.binding.HalDriver object at 0x0000015E0AB1D570>\n",
"SystemContext driver=<pyiree.rt.binding.HalDriver object at 0x0000015E0AB1D570>\n"
],
"name": "stderr"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "S2FYao92Xd6r",
"outputId": "734f8b72-e752-43c4-efb8-4a301f8d8624",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 297
}
},
"source": [
"#@title Execute the compiled module and compare the results with TensorFlow\n",
"\n",
"# Invoke the 'predict' function with a single image as an argument\n",
"iree_prediction = iree_module.predict(x_train[sample_index][None, :])[0]\n",
"tf_prediction = tf_model.predict(x_train[sample_index][None, :])[0]\n",
"error = tf_prediction - iree_prediction\n",
"\n",
"fig, axs = plt.subplots(1, 2)\n",
"fig.set_figwidth(12)\n",
"\n",
"ax = axs[0]\n",
"ax.plot(iree_prediction, linewidth=2, label=backend.backend_name)\n",
"ax.plot(tf_prediction, linewidth=2, label=\"tf\")\n",
"\n",
"ax.set_title(\"Predictions\")\n",
"ax.set_ylabel(\"Softmax 'Probability'\")\n",
"ax.set_xlabel(\"Digit\")\n",
"ax.set_ylim(0, 1)\n",
"ax.set_xlim(0, 9)\n",
"ax.legend(frameon=True)\n",
"\n",
"\n",
"ax = axs[1]\n",
"ax.plot(error)\n",
"\n",
"ax.set_title(\"Error\")\n",
"ax.set_ylabel(\"Numerical between TF and IREE\")\n",
"ax.set_xlabel(\"Digit\")\n",
"ylim = 1.25 * np.max(np.abs(error))\n",
"ax.set_ylim(-ylim, ylim)\n",
"ax.set_xlim(0, 9)\n",
"\n",
"fig.tight_layout()"
],
"execution_count": 10,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 864x288 with 2 Axes>"
],
"image/png": "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bR5bREQk2BmmabbdQp6gv//973zyySfk5uYSGxvLihUrmD59OmefffZx75ufnx+IqCIiEoROPfVUqyMcE7VNIiLhpaP2KWA9WIfqtlmzZgGwYsUKDMM4oX1DpbEVEZHwobZJRES+L2AXHCUlJVFZWdl6v6qqisTExBPeV0REREREJFgFrAdr+PDhbNu2jerqalwuF7t372bIkCEAPProowDcdtttHe4rIiIiIiISKgJWYDmdTubOnds67G/+/PmtswJ+v7eqo31FRERERERCRcAmufCn5cuX8/jjj2MYBvPmzWPSpElWR2rTwoULeffdd4mPj+e9996zOk67KioquPnmm6mrqyMyMpK5c+dy5plnWh3rCDU1Nfz85z/H7XZjGAY33ngj5557rtWx2lVfX8+UKVO45ppr+PnPf251nHbl5OQwePBgAE477TTuvvtuixO1bcOGDdx999243W4GDx7ME088YXWkI6xevZpFixa13i8qKuLNN99scwZUqz333HO88847eL1epk6dyg033GB1pHY99thjrFy5koiICK6//vqg/rtX++Rfap8CIxTaJ7VN/qX2yf861TaZQa65udk855xzzMrKSnPXrl3m5MmTTY/HY3WsNuXn55sFBQXmhRdeaHWUo6qsrDQLCwtN0zTN0tJSc/z48RYnapvL5TLr6+tN0zTN6upq88wzzwza371pmuYjjzxiXnfddeZzzz1ndZSjGjlypNUROuT1es3zzz/fXLdunWmavt9/sKuoqDDPO+88q2O0qby83Dz33HNNl8tlNjc3m5MmTTJ37txpdaw2FRQUmJdeeqnZ0tJiVldXmxMmTDD3799vdaw2qX3yP7VPgREK7ZPapsBR+3TiOts2Bf04vO+vkZWamtq6RlYwGjVqFHFxcVbH6FBCQgLZ2dkApKWl4Xa7cblcFqc6UkREBN27dwd8Z99cLhdut9viVG0rLi5m79695ObmWh3lpLBx40bi4uIYPXo0APHx8RYn6tjy5cu54IILrI7RLo/Hg8vlwuVyERERQY8ePayO1KaSkhJycnJwOBzEx8eTnJzMxo0brY7VJrVP/qf2yf/UPvlPKLZNoPbJHzrbNgV9gVVZWUliYiKvvvoqy5cvJyEhgT179lgd66SxevVqhg4ditPptDpKm+rr67n44ou55JJLuPfee4M256JFi4K2S/uH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\n"
},
"metadata": {
"tags": []
}
}
]
}
]
}