{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "iPpI7RaYoZuE"
   },
   "source": [
    "##### Copyright 2018 The TensorFlow Authors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "cellView": "form",
    "execution": {
     "iopub.execute_input": "2024-08-16T02:30:56.341518Z",
     "iopub.status.busy": "2024-08-16T02:30:56.340976Z",
     "iopub.status.idle": "2024-08-16T02:30:56.344669Z",
     "shell.execute_reply": "2024-08-16T02:30:56.344124Z"
    },
    "id": "hro2InpHobKk"
   },
   "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": "U9i2Dsh-ziXr"
   },
   "source": [
    "# Customization basics: tensors and operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Hndw-YcxoOJK"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/customization/basics\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\" />View on TensorFlow.org</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs/blob/master/site/en/tutorials/customization/basics.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/tensorflow/docs/blob/master/site/en/tutorials/customization/basics.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/docs/site/en/tutorials/customization/basics.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6sILUVbHoSgH"
   },
   "source": [
    "This is an introductory TensorFlow tutorial that shows how to:\n",
    "\n",
    "* Import the required package.\n",
    "* Create and use tensors.\n",
    "* Use GPU acceleration.\n",
    "* Build a data pipeline with `tf.data.Dataset`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "z1JcS5iBXMRO"
   },
   "source": [
    "## Import TensorFlow\n",
    "\n",
    "To get started, import the `tensorflow` module. As of TensorFlow 2, eager execution is turned on by default. Eager execution enables a more interactive frontend to TensorFlow, which you will later explore in more detail."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:30:56.348575Z",
     "iopub.status.busy": "2024-08-16T02:30:56.348049Z",
     "iopub.status.idle": "2024-08-16T02:30:58.698400Z",
     "shell.execute_reply": "2024-08-16T02:30:58.697666Z"
    },
    "id": "vjBPmYjLdFmk"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-08-16 02:30:56.601166: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "2024-08-16 02:30:56.622608: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "2024-08-16 02:30:56.629164: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "H9UySOPLXdaw"
   },
   "source": [
    "## Tensors\n",
    "\n",
    "A Tensor is a multi-dimensional array. Similar to NumPy `ndarray` objects, `tf.Tensor` objects have a data type and a shape. Additionally, `tf.Tensor`s can reside in accelerator memory (like a GPU). TensorFlow offers a rich library of operations (for example, `tf.math.add`, `tf.linalg.matmul`, and `tf.linalg.inv`) that consume and produce `tf.Tensor`s. These operations automatically convert built-in Python types. For example:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "cellView": "code",
    "execution": {
     "iopub.execute_input": "2024-08-16T02:30:58.702978Z",
     "iopub.status.busy": "2024-08-16T02:30:58.702447Z",
     "iopub.status.idle": "2024-08-16T02:31:00.907532Z",
     "shell.execute_reply": "2024-08-16T02:31:00.906788Z"
    },
    "id": "ngUe237Wt48W"
   },
   "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(13, shape=(), dtype=int32)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
      "I0000 00:00:1723775459.220860   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.224736   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.228526   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.231708   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.243472   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.247007   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.250510   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.253505   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.256964   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.260375   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.263839   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775459.266764   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.484960   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.487122   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.489159   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.491212   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.493195   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.495178   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.497138   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.499106   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.500943   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.502910   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.504850   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.506819   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.545061   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.547158   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.549140   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.551249   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.553080   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.555080   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.557010   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.558972   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.560817   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.563305   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.565638   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n",
      "I0000 00:00:1723775460.568007   70727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355\n"
     ]
    }
   ],
   "source": [
    "print(tf.math.add(1, 2))\n",
    "print(tf.math.add([1, 2], [3, 4]))\n",
    "print(tf.math.square(5))\n",
    "print(tf.math.reduce_sum([1, 2, 3]))\n",
    "\n",
    "# Operator overloading is also supported\n",
    "print(tf.math.square(2) + tf.math.square(3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IDY4WsYRhP81"
   },
   "source": [
    "Each `tf.Tensor` has a shape and a datatype:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:00.911410Z",
     "iopub.status.busy": "2024-08-16T02:31:00.911125Z",
     "iopub.status.idle": "2024-08-16T02:31:00.915973Z",
     "shell.execute_reply": "2024-08-16T02:31:00.915351Z"
    },
    "id": "srYWH1MdJNG7"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor([[2 3]], shape=(1, 2), dtype=int32)\n",
      "(1, 2)\n",
      "<dtype: 'int32'>\n"
     ]
    }
   ],
   "source": [
    "x = tf.linalg.matmul([[1]], [[2, 3]])\n",
    "print(x)\n",
    "print(x.shape)\n",
    "print(x.dtype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "eBPw8e8vrsom"
   },
   "source": [
    "The most obvious differences between NumPy arrays and `tf.Tensor`s are:\n",
    "\n",
    "1. Tensors can be backed by accelerator memory (like GPU, TPU).\n",
    "2. Tensors are immutable."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Dwi1tdW3JBw6"
   },
   "source": [
    "### NumPy compatibility\n",
    "\n",
    "Converting between a TensorFlow `tf.Tensor` and a NumPy `ndarray` is easy:\n",
    "\n",
    "* TensorFlow operations automatically convert NumPy ndarrays to Tensors.\n",
    "* NumPy operations automatically convert Tensors to NumPy ndarrays.\n",
    "\n",
    "Tensors are explicitly converted to NumPy ndarrays using their `.numpy()` method. These conversions are typically cheap since the array and `tf.Tensor` share the underlying memory representation, if possible. However, sharing the underlying representation isn't always possible since the `tf.Tensor` may be hosted in GPU memory while NumPy arrays are always backed by host memory, and the conversion involves a copy from GPU to host memory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:00.919071Z",
     "iopub.status.busy": "2024-08-16T02:31:00.918828Z",
     "iopub.status.idle": "2024-08-16T02:31:00.929627Z",
     "shell.execute_reply": "2024-08-16T02:31:00.929042Z"
    },
    "id": "lCUWzso6mbqR"
   },
   "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=float64)\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": [
    "import numpy as np\n",
    "\n",
    "ndarray = np.ones([3, 3])\n",
    "\n",
    "print(\"TensorFlow operations convert numpy arrays to Tensors automatically\")\n",
    "tensor = tf.math.multiply(ndarray, 42)\n",
    "print(tensor)\n",
    "\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": {
    "id": "PBNP8yTRfu_X"
   },
   "source": [
    "## GPU acceleration\n",
    "\n",
    "Many TensorFlow operations are accelerated using the GPU for computation. Without any annotations, TensorFlow automatically decides whether to use the GPU or CPU for an operation—copying the tensor between CPU and GPU memory, if necessary. Tensors produced by an operation are typically backed by the memory of the device on which the operation executed. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "cellView": "code",
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:00.932518Z",
     "iopub.status.busy": "2024-08-16T02:31:00.932299Z",
     "iopub.status.idle": "2024-08-16T02:31:00.937748Z",
     "shell.execute_reply": "2024-08-16T02:31:00.937174Z"
    },
    "id": "3Twf_Rw-gQFM"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Is there a GPU available: \n",
      "[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:2', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:3', device_type='GPU')]\n",
      "Is the Tensor on GPU #0:  \n",
      "True\n"
     ]
    }
   ],
   "source": [
    "x = tf.random.uniform([3, 3])\n",
    "\n",
    "print(\"Is there a GPU available: \"),\n",
    "print(tf.config.list_physical_devices(\"GPU\"))\n",
    "\n",
    "print(\"Is the Tensor on GPU #0:  \"),\n",
    "print(x.device.endswith('GPU:0'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vpgYzgVXW2Ud"
   },
   "source": [
    "### Device names\n",
    "\n",
    "The `Tensor.device` property provides a fully qualified string name of the device hosting the contents of the tensor. This name encodes many details, such as an identifier of the network address of the host on which this program is executing and the device within that host. This is required for distributed execution of a TensorFlow program. The string ends with `GPU:<N>` if the tensor is placed on the `N`-th GPU on the host."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ZWZQCimzuqyP"
   },
   "source": [
    "### Explicit device placement\n",
    "\n",
    "In TensorFlow, *placement* refers to how individual operations are assigned (placed on) a device for execution. As mentioned, when there is no explicit guidance provided, TensorFlow automatically decides which device to execute an operation and copies tensors to that device, if needed.\n",
    "\n",
    "However, TensorFlow operations can be explicitly placed on specific devices using the `tf.device` context manager. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:00.940981Z",
     "iopub.status.busy": "2024-08-16T02:31:00.940608Z",
     "iopub.status.idle": "2024-08-16T02:31:01.031612Z",
     "shell.execute_reply": "2024-08-16T02:31:01.030949Z"
    },
    "id": "RjkNZTuauy-Q"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "On CPU:\n",
      "10 loops: 43.71ms\n",
      "On GPU:\n",
      "10 loops: 38.91ms\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "def time_matmul(x):\n",
    "  start = time.time()\n",
    "  for loop in range(10):\n",
    "    tf.linalg.matmul(x, x)\n",
    "\n",
    "  result = time.time()-start\n",
    "\n",
    "  print(\"10 loops: {:0.2f}ms\".format(1000*result))\n",
    "\n",
    "# Force execution on CPU\n",
    "print(\"On CPU:\")\n",
    "with tf.device(\"CPU:0\"):\n",
    "  x = tf.random.uniform([1000, 1000])\n",
    "  assert x.device.endswith(\"CPU:0\")\n",
    "  time_matmul(x)\n",
    "\n",
    "# Force execution on GPU #0 if available\n",
    "if tf.config.list_physical_devices(\"GPU\"):\n",
    "  print(\"On GPU:\")\n",
    "  with tf.device(\"GPU:0\"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.\n",
    "    x = tf.random.uniform([1000, 1000])\n",
    "    assert x.device.endswith(\"GPU:0\")\n",
    "    time_matmul(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "o1K4dlhhHtQj"
   },
   "source": [
    "## Datasets\n",
    "\n",
    "This section uses the `tf.data.Dataset` API to build a pipeline for feeding data to your model. `tf.data.Dataset` is used to build performant, complex input pipelines from simple, re-usable pieces that will feed your model's training or evaluation loops. (Refer to the [tf.data: Build TensorFlow input pipelines](../../guide/data.ipynb) guide to learn more.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zI0fmOynH-Ne"
   },
   "source": [
    "### Create a source `Dataset`\n",
    "\n",
    "Create a *source* dataset using one of the factory functions like `tf.data.Dataset.from_tensors`, `tf.data.Dataset.from_tensor_slices`, or using objects that read from files like `tf.data.TextLineDataset` or `tf.data.TFRecordDataset`. Refer to the _Reading input data_ section of the [tf.data: Build TensorFlow input pipelines](../../guide/data.ipynb) guide for more information."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:01.034880Z",
     "iopub.status.busy": "2024-08-16T02:31:01.034641Z",
     "iopub.status.idle": "2024-08-16T02:31:01.054294Z",
     "shell.execute_reply": "2024-08-16T02:31:01.053633Z"
    },
    "id": "F04fVOHQIBiG"
   },
   "outputs": [],
   "source": [
    "ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])\n",
    "\n",
    "# Create a CSV file\n",
    "import tempfile\n",
    "_, filename = tempfile.mkstemp()\n",
    "\n",
    "with open(filename, 'w') as f:\n",
    "  f.write(\"\"\"Line 1\n",
    "Line 2\n",
    "Line 3\n",
    "  \"\"\")\n",
    "\n",
    "ds_file = tf.data.TextLineDataset(filename)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vbxIhC-5IPdf"
   },
   "source": [
    "### Apply transformations\n",
    "\n",
    "Use the transformations functions like `tf.data.Dataset.map`, `tf.data.Dataset.batch`, and `tf.data.Dataset.shuffle` to apply transformations to dataset records."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:01.057854Z",
     "iopub.status.busy": "2024-08-16T02:31:01.057276Z",
     "iopub.status.idle": "2024-08-16T02:31:01.071743Z",
     "shell.execute_reply": "2024-08-16T02:31:01.071168Z"
    },
    "id": "uXSDZWE-ISsd"
   },
   "outputs": [],
   "source": [
    "ds_tensors = ds_tensors.map(tf.math.square).shuffle(2).batch(2)\n",
    "\n",
    "ds_file = ds_file.batch(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "A8X1GNfoIZKJ"
   },
   "source": [
    "### Iterate\n",
    "\n",
    "`tf.data.Dataset` objects support iteration to loop over records:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2024-08-16T02:31:01.075147Z",
     "iopub.status.busy": "2024-08-16T02:31:01.074578Z",
     "iopub.status.idle": "2024-08-16T02:31:01.126484Z",
     "shell.execute_reply": "2024-08-16T02:31:01.125706Z"
    },
    "id": "ws-WKRk5Ic6-"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Elements of ds_tensors:\n",
      "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",
      "\n",
      "Elements in ds_file:\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)\n",
      "tf.Tensor([b'Line 3' b'  '], shape=(2,), dtype=string)\n"
     ]
    }
   ],
   "source": [
    "print('Elements of ds_tensors:')\n",
    "for x in ds_tensors:\n",
    "  print(x)\n",
    "\n",
    "print('\\nElements in ds_file:')\n",
    "for x in ds_file:\n",
    "  print(x)"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "name": "basics.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.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
