{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# CS 20 : TensorFlow for Deep Learning Research\n", "## Lecture 04 : Eager execution\n", "### Eager execution\n", "You no longer need to worry about...\n", "\n", "1. placeholders\n", "2. sessions\n", "3. control dependencies\n", "4. \"lazy loading\"\n", "5. {name, variable, op} scopes \n", " \n", " \n", "* Reference\n", " + https://www.tensorflow.org/tutorials/eager/eager_basics?hl=ko\n", "\n", "### Notice\n", "#### Main changes in TF 2.0\n", "\n", "The API for Variables will then change in the following ways for TF 2.0:\n", "\n", "* ***tf.Variable will become an abstract base class with a well-defined interface and a scoped factory to construct instances***\n", " * ***users will be able to implement their own variable-like objects by subclassing tf.Variable and adding a scoped factory function to use those variables***\n", "* ***variable_scope and get_variable will be removed***\n", " * the tf 1.0 version of variable_scope and get_variable will be left in tf.compat.v1\n", " * ***to control variable naming users can use tf.name_scope + tf.Variable***\n", " * whether a variable is shared across sessions / processes will be controlled by a constructor argument to tf.Variable; no other type of scope reuse will be done in the framework\n", " * scoped partitioning will be implemented as a factory function at first\n", " * libraries and users are encouraged to reuse variables by reusing their objects, like Keras layers do\n", " * custom_getters will have the following API: [variable_creator_scope](https://github.com/tensorflow/tensorflow/blob/567189980f7a1c2aa09a5170bd8d01a6ec37d303/tensorflow/python/ops/variable_scope.py#L2402)\n", "* the default implementation of the tf.Variable interface will be ResourceVariable\n", " * RefVariable will be kept in tf.compat.v1 and will be the default implementation for tf.compat.v1.Variable\n", " * tf.compat.v1.Variable will have a use_resource argument to control whether a resource variable or a ref variable will be created\n", "* symbols like tf.assign* will be removed in favor of methods in tf.Variable\n", " * in tf.compat.v1 these symbols will be marked as deprecated and will call the corresponding methods in the Variable object instead\n", "https://github.com/tensorflow/community/blob/master/rfcs/20180817-variables-20.md" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setup" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.12.0\n" ] } ], "source": [ "from __future__ import absolute_import, division, print_function\n", "import numpy as np\n", "import tensorflow as tf\n", "tf.enable_eager_execution()\n", "\n", "print(tf.__version__)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Boilerplate\n", "```python\n", "x = tf.placeholder(dtype = tf.float32, shape = [1, 1])\n", "m = tf.matmul(x, x)\n", "\n", "print(m)\n", "with tf.Session() as sess:\n", " m_out = sess.run(m, feed_dict = {x : [[2.]]})\n", " print(m_out, m_out.shape)\n", "```\n", "\n", "```python\n", "Tensor(\"mul:0\", shape=(1, 1), dtype=float32)\n", "[[4.]] (1, 1)\n", "```\n", "\n", "**When using `tf.enable_eager_execution()`, Bolierplate changes as belows**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([[4.]], shape=(1, 1), dtype=float32)\n", "[]\n" ] } ], "source": [ "x = [[2.]]\n", "m = tf.matmul(x, x)\n", "print(m) # No sessions()!\n", "print(tf.get_default_graph().get_operations()) # No graphs!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lazy Loading\n", "Each iteration adds nodes to the graph\n", "\n", "```python\n", "x = tf.constant(value = [[1,2],[3,4]], dtype = tf.int32)\n", "\n", "with tf.Session() as sess:\n", " for i in range(x.shape[0]):\n", " for j in range(x.shape[1]):\n", " print(sess.run(x[i, j]))\n", "```\n", "\n", "```python\n", "1\n", "2\n", "3\n", "4\n", "```\n", "\n", "**When using `tf.enable_eager_execution()`, not graph**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(1, shape=(), dtype=int32)\n", "tf.Tensor(2, shape=(), dtype=int32)\n", "tf.Tensor(3, shape=(), dtype=int32)\n", "tf.Tensor(4, shape=(), dtype=int32)\n", "[]\n" ] } ], "source": [ "x = tf.constant(value = [[1,2],[3,4]], dtype = tf.int32)\n", "\n", "for i in range(x.shape[0]):\n", " for j in range(x.shape[1]):\n", " print(x[i, j])\n", " \n", "print(tf.get_default_graph().get_operations())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tensors act like numpy arrays\n", "The most obvious differences between NumPy arrays and TensorFlow Tensors are:\n", "\n", "1. Tensors can be backed by accelerator memory (like GPU, TPU)\n", "2. Tensors are **immutable**" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1. 4. 9.]]\n", "tf.Tensor(1.0, shape=(), dtype=float32)\n", "tf.Tensor(2.0, shape=(), dtype=float32)\n", "tf.Tensor(3.0, shape=(), dtype=float32)\n" ] } ], "source": [ "# Tensors are backed by NumPy arrays\n", "# Tensors are compatible with NumPy functions\n", "x = tf.constant(value = [[1.,2.,3]])\n", "assert type(x.numpy()) == np.ndarray\n", "squared = np.square(x)\n", "print(squared)\n", "\n", "# Tensors are iterable!\n", "for i in x[0]:\n", " print(i)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(3, shape=(), dtype=int32)\n", "tf.Tensor([4 6], shape=(2,), dtype=int32)\n", "tf.Tensor(25, shape=(), dtype=int32)\n", "tf.Tensor(6, shape=(), dtype=int32)\n", "tf.Tensor(b'aGVsbG8gd29ybGQ', shape=(), dtype=string)\n", "tf.Tensor(13, shape=(), dtype=int32)\n" ] } ], "source": [ "print(tf.add(1, 2))\n", "print(tf.add([1, 2], [3, 4]))\n", "print(tf.square(5))\n", "print(tf.reduce_sum([1, 2, 3]))\n", "print(tf.encode_base64(\"hello world\"))\n", "\n", "# Operator overloading is also supported\n", "print(tf.square(2) + tf.square(3))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1, 2)\n", "<dtype: 'int32'>\n" ] } ], "source": [ "# Each Tensor has a shape and a datatype\n", "x = tf.matmul([[1]], [[2, 3]])\n", "print(x.shape)\n", "print(x.dtype)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Numpy Compatibility\n", "* TensorsFlow operations automatically convert NumPy ndarrays to Tensors.\n", "* NumPy operations automatically convert Tensors to NumPy ndarrays.\n", "\n", "***Tensors can be explicitly converted to NumPy ndarrays by invoking the .numpy() method on them.*** These conversions are typically cheap as the array and Tensor share the underlying memory representation if possible. ***However, sharing the underlying representation isn't always possible since the Tensor may be hosted in GPU memory while NumPy arrays are always backed by host memory, and the conversion will thus involve a copy from GPU to host memory.***" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TensorFlow operations convert numpy arrays to Tensors automatically\n", "tf.Tensor(\n", "[[42. 42. 42.]\n", " [42. 42. 42.]\n", " [42. 42. 42.]], shape=(3, 3), dtype=float32)\n", "And NumPy operations convert Tensors to numpy arrays automatically\n", "[[43. 43. 43.]\n", " [43. 43. 43.]\n", " [43. 43. 43.]]\n", "The .numpy() method explicitly converts a Tensor to a numpy array\n", "[[42. 42. 42.]\n", " [42. 42. 42.]\n", " [42. 42. 42.]]\n" ] } ], "source": [ "ndarray = np.ones([3,3], dtype = np.float32)\n", "\n", "print(\"TensorFlow operations convert numpy arrays to Tensors automatically\")\n", "tensor = tf.multiply(ndarray, 42)\n", "print(tensor)\n", "\n", "print(\"And NumPy operations convert Tensors to numpy arrays automatically\")\n", "print(np.add(tensor, 1))\n", "\n", "print(\"The .numpy() method explicitly converts a Tensor to a numpy array\")\n", "print(tensor.numpy())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### GPU acceleration" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Is there a GPU available: \n", "False\n", "Is the Tensor on GPU #0: \n", "False\n" ] } ], "source": [ "x = tf.random_uniform(shape = [3, 3])\n", "\n", "print(\"Is there a GPU available: \"),\n", "print(tf.test.is_gpu_available())\n", "\n", "print(\"Is the Tensor on GPU #0: \"),\n", "print(x.device.endswith('GPU:0'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Device Names" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'/job:localhost/replica:0/task:0/device:CPU:0'" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.device" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Explicit Device Placement" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/job:localhost/replica:0/task:0/device:CPU:0\n" ] } ], "source": [ "with tf.device(\"CPU:0\"):\n", " y = tf.ones([1,1])\n", " print(y.device)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/job:localhost/replica:0/task:0/device:CPU:0\n", "/job:localhost/replica:0/task:0/device:CPU:0\n" ] } ], "source": [ "print(x.device)\n", "z = x.cpu()\n", "print(z.device)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[0.5488272 0.9693705 0.47811544]\n", " [0.13793623 0.53724563 0.9553573 ]\n", " [0.9873563 0.27607608 0.21941674]], shape=(3, 3), dtype=float32) \n", " tf.Tensor(\n", "[[0.5488272 0.9693705 0.47811544]\n", " [0.13793623 0.53724563 0.9553573 ]\n", " [0.9873563 0.27607608 0.21941674]], shape=(3, 3), dtype=float32)\n" ] } ], "source": [ "print(x, '\\n',z)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "<tf.Tensor: id=98, shape=(3, 3), dtype=bool, numpy=\n", "array([[ True, True, True],\n", " [ True, True, True],\n", " [ True, True, True]])>" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.equal(x, z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Datasets\n", "We recommend using the Datasets API for building performant, complex input pipelines from simple, re-usable pieces that will feed your model's training or evaluation loops.\n", "\n", "If you're familiar with TensorFlow graphs, the API for constructing the Dataset object remains exactly the same when eager execution is enabled, but the process of iterating over elements of the dataset is slightly simpler. ***You can use Python iteration over the `tf.data.Dataset` object and do not need to explicitly create an `tf.data.Iterator` object.*** As a result, the discussion on iterators in the TensorFlow Guide is not relevant when eager execution is enabled." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])\n", "tensors = tensors.map(np.square) # Numpy Compatibility magic!\n", "tensors = tensors.shuffle(2).batch(2)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([4 1], shape=(2,), dtype=int32)\n", "tf.Tensor([16 9], shape=(2,), dtype=int32)\n", "tf.Tensor([25 36], shape=(2,), dtype=int32)\n" ] } ], "source": [ "for mb_tensor in tensors:\n", " print(mb_tensor)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "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.6.6" } }, "nbformat": 4, "nbformat_minor": 2 }