{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "Tce3stUlHN0L" }, "source": [ "##### Copyright 2020 The TensorFlow Authors." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "cellView": "form", "execution": { "iopub.execute_input": "2022-12-14T22:29:59.478272Z", "iopub.status.busy": "2022-12-14T22:29:59.478022Z", "iopub.status.idle": "2022-12-14T22:29:59.481855Z", "shell.execute_reply": "2022-12-14T22:29:59.481317Z" }, "id": "tuOe1ymfHZPu" }, "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": "qFdPvlXBOdUN" }, "source": [ "# 张量简介" ] }, { "cell_type": "markdown", "metadata": { "id": "MfBg1C5NB3X0" }, "source": [ "\n", " \n", " \n", " \n", " \n", "
在 TensorFlow.org 上查看在 Google Colab 中运行 在 GitHub 上查看源代码下载笔记本
" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:29:59.485119Z", "iopub.status.busy": "2022-12-14T22:29:59.484659Z", "iopub.status.idle": "2022-12-14T22:30:01.440857Z", "shell.execute_reply": "2022-12-14T22:30:01.440061Z" }, "id": "AL2hzxorJiWy" }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "2022-12-14 22:30:00.433530: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 22:30:00.433623: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory\n", "2022-12-14 22:30:00.433633: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.\n" ] } ], "source": [ "import tensorflow as tf\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": { "id": "VQ3s2J8Vgowq" }, "source": [ "张量是具有统一类型(称为 `dtype`)的多维数组。您可以在 `tf.dtypes.DType` 中查看所有支持的 `dtypes`。\n", "\n", "如果您熟悉 [NumPy](https://numpy.org/devdocs/user/quickstart.html){:.external},就会知道张量与 `np.arrays` 有一定的相似性。\n", "\n", "就像 Python 数值和字符串一样,所有张量都是不可变的:永远无法更新张量的内容,只能创建新的张量。\n" ] }, { "cell_type": "markdown", "metadata": { "id": "DRK5-9EpYbzG" }, "source": [ "## 基础知识\n", "\n", "首先,创建一些基本张量。" ] }, { "cell_type": "markdown", "metadata": { "id": "uSHRFT6LJbxq" }, "source": [ "下面是一个“标量”(或称“0 秩”张量)。标量包含单个值,但没有“轴”。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:01.445466Z", "iopub.status.busy": "2022-12-14T22:30:01.445015Z", "iopub.status.idle": "2022-12-14T22:30:04.803476Z", "shell.execute_reply": "2022-12-14T22:30:04.802725Z" }, "id": "d5JcgLFR6gHv" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(4, shape=(), dtype=int32)\n" ] } ], "source": [ "# This will be an int32 tensor by default; see \"dtypes\" below.\n", "rank_0_tensor = tf.constant(4)\n", "print(rank_0_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "tdmPAn9fWYs5" }, "source": [ "“向量”(或称“1 秩”张量)就像一个值列表。向量有 1 个轴:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.807061Z", "iopub.status.busy": "2022-12-14T22:30:04.806521Z", "iopub.status.idle": "2022-12-14T22:30:04.815072Z", "shell.execute_reply": "2022-12-14T22:30:04.814416Z" }, "id": "oZos8o_R6oE7" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([2. 3. 4.], shape=(3,), dtype=float32)\n" ] } ], "source": [ "# Let's make this a float tensor.\n", "rank_1_tensor = tf.constant([2.0, 3.0, 4.0])\n", "print(rank_1_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "G3IJG-ug_H4u" }, "source": [ "“矩阵”(或称“2 秩”张量)有 2 个轴:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.818192Z", "iopub.status.busy": "2022-12-14T22:30:04.817723Z", "iopub.status.idle": "2022-12-14T22:30:04.823164Z", "shell.execute_reply": "2022-12-14T22:30:04.822562Z" }, "id": "cnOIA_xb6u0M" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[1. 2.]\n", " [3. 4.]\n", " [5. 6.]], shape=(3, 2), dtype=float16)\n" ] } ], "source": [ "# If you want to be specific, you can set the dtype (see below) at creation time\n", "rank_2_tensor = tf.constant([[1, 2],\n", " [3, 4],\n", " [5, 6]], dtype=tf.float16)\n", "print(rank_2_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "19m72qEPkfxi" }, "source": [ "\n", "\n", " \n", " \n", " \n", "\n", "\n", " \n", " \n", " \n", "\n", "
标量,形状:[] 向量,形状:[3] 矩阵,形状:[3, 2]
\"A \"The \"A
\n" ] }, { "cell_type": "markdown", "metadata": { "id": "fjFvzcn4_ehD" }, "source": [ "张量的轴可能更多,下面是一个包含 3 个轴的张量:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.825996Z", "iopub.status.busy": "2022-12-14T22:30:04.825766Z", "iopub.status.idle": "2022-12-14T22:30:04.830516Z", "shell.execute_reply": "2022-12-14T22:30:04.829925Z" }, "id": "sesW7gw6JkXy" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[[ 0 1 2 3 4]\n", " [ 5 6 7 8 9]]\n", "\n", " [[10 11 12 13 14]\n", " [15 16 17 18 19]]\n", "\n", " [[20 21 22 23 24]\n", " [25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)\n" ] } ], "source": [ "# There can be an arbitrary number of\n", "# axes (sometimes called \"dimensions\")\n", "rank_3_tensor = tf.constant([\n", " [[0, 1, 2, 3, 4],\n", " [5, 6, 7, 8, 9]],\n", " [[10, 11, 12, 13, 14],\n", " [15, 16, 17, 18, 19]],\n", " [[20, 21, 22, 23, 24],\n", " [25, 26, 27, 28, 29]],])\n", "\n", "print(rank_3_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "rM2sTGIkoE3S" }, "source": [ "对于包含 2 个以上的轴的张量,您可以通过多种方式加以呈现。" ] }, { "cell_type": "markdown", "metadata": { "id": "NFiYfNMMhDgL" }, "source": [ "\n", "\n", " \n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", "\n", "
3 轴张量,形状:[3, 2, 5]
" ] }, { "cell_type": "markdown", "metadata": { "id": "oWAc0U8OZwNb" }, "source": [ "通过使用 `np.array` 或 `tensor.numpy` 方法,您可以将张量转换为 NumPy 数组:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.833810Z", "iopub.status.busy": "2022-12-14T22:30:04.833436Z", "iopub.status.idle": "2022-12-14T22:30:04.839692Z", "shell.execute_reply": "2022-12-14T22:30:04.839090Z" }, "id": "J5u6_6ZYaS7B" }, "outputs": [ { "data": { "text/plain": [ "array([[1., 2.],\n", " [3., 4.],\n", " [5., 6.]], dtype=float16)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.array(rank_2_tensor)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.842566Z", "iopub.status.busy": "2022-12-14T22:30:04.842087Z", "iopub.status.idle": "2022-12-14T22:30:04.846258Z", "shell.execute_reply": "2022-12-14T22:30:04.845698Z" }, "id": "c6Taz2gIaZeo" }, "outputs": [ { "data": { "text/plain": [ "array([[1., 2.],\n", " [3., 4.],\n", " [5., 6.]], dtype=float16)" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rank_2_tensor.numpy()" ] }, { "cell_type": "markdown", "metadata": { "id": "hnz19F0ocEKD" }, "source": [ "张量通常包含浮点型和整型数据,但是还有许多其他数据类型,包括:\n", "\n", "- 复杂的数值\n", "- 字符串\n", "\n", "`tf.Tensor` 基类要求张量是“矩形”,也就是说,每个轴上的每一个元素大小相同。但是,有可以处理不同形状的特殊类型张量:\n", "\n", "- 不规则张量(请参阅下文中的 [RaggedTensor](#ragged_tensors))\n", "- 稀疏张量(请参阅下文中的 [SparseTensor](#sparse_tensors))" ] }, { "cell_type": "markdown", "metadata": { "id": "SDC7OGeAIJr8" }, "source": [ "您可以对张量执行基本数学运算,包括加法、逐元素乘法和矩阵乘法。" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.849322Z", "iopub.status.busy": "2022-12-14T22:30:04.849088Z", "iopub.status.idle": "2022-12-14T22:30:04.857876Z", "shell.execute_reply": "2022-12-14T22:30:04.857218Z" }, "id": "-DTkjwDOIIDa" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[2 3]\n", " [4 5]], shape=(2, 2), dtype=int32) \n", "\n", "tf.Tensor(\n", "[[1 2]\n", " [3 4]], shape=(2, 2), dtype=int32) \n", "\n", "tf.Tensor(\n", "[[3 3]\n", " [7 7]], shape=(2, 2), dtype=int32) \n", "\n" ] } ], "source": [ "a = tf.constant([[1, 2],\n", " [3, 4]])\n", "b = tf.constant([[1, 1],\n", " [1, 1]]) # Could have also said `tf.ones([2,2])`\n", "\n", "print(tf.add(a, b), \"\\n\")\n", "print(tf.multiply(a, b), \"\\n\")\n", "print(tf.matmul(a, b), \"\\n\")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.861002Z", "iopub.status.busy": "2022-12-14T22:30:04.860413Z", "iopub.status.idle": "2022-12-14T22:30:04.865059Z", "shell.execute_reply": "2022-12-14T22:30:04.864481Z" }, "id": "2smoWeUz-N2q" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[2 3]\n", " [4 5]], shape=(2, 2), dtype=int32) \n", "\n", "tf.Tensor(\n", "[[1 2]\n", " [3 4]], shape=(2, 2), dtype=int32) \n", "\n", "tf.Tensor(\n", "[[3 3]\n", " [7 7]], shape=(2, 2), dtype=int32) \n", "\n" ] } ], "source": [ "print(a + b, \"\\n\") # element-wise addition\n", "print(a * b, \"\\n\") # element-wise multiplication\n", "print(a @ b, \"\\n\") # matrix multiplication" ] }, { "cell_type": "markdown", "metadata": { "id": "S3_vIAl2JPVc" }, "source": [ "各种运算都可以使用张量。" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.868373Z", "iopub.status.busy": "2022-12-14T22:30:04.867801Z", "iopub.status.idle": "2022-12-14T22:30:04.876558Z", "shell.execute_reply": "2022-12-14T22:30:04.875980Z" }, "id": "Gp4WUYzGIbnv" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(10.0, shape=(), dtype=float32)\n", "tf.Tensor([1 0], shape=(2,), dtype=int64)\n", "tf.Tensor(\n", "[[2.6894143e-01 7.3105854e-01]\n", " [9.9987662e-01 1.2339458e-04]], shape=(2, 2), dtype=float32)\n" ] } ], "source": [ "c = tf.constant([[4.0, 5.0], [10.0, 1.0]])\n", "\n", "# Find the largest value\n", "print(tf.reduce_max(c))\n", "# Find the index of the largest value\n", "print(tf.math.argmax(c))\n", "# Compute the softmax\n", "print(tf.nn.softmax(c))" ] }, { "cell_type": "markdown", "metadata": { "id": "0MNM-q7-MZLz" }, "source": [ "注:通常,在 TensorFlow 函数需要 `Tensor` 作为输入的任何地方,该函数也将接受可使用 `tf.convert_to_tensor` 转换为 `Tensor` 的任何内容。请参见下面的示例。" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.879574Z", "iopub.status.busy": "2022-12-14T22:30:04.879141Z", "iopub.status.idle": "2022-12-14T22:30:04.884125Z", "shell.execute_reply": "2022-12-14T22:30:04.883557Z" }, "id": "_wch0N8xNEt-" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.convert_to_tensor([1,2,3])" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.887053Z", "iopub.status.busy": "2022-12-14T22:30:04.886499Z", "iopub.status.idle": "2022-12-14T22:30:04.893859Z", "shell.execute_reply": "2022-12-14T22:30:04.893308Z" }, "id": "ngqIeWYeNJVI" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.reduce_max([1,2,3])" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.896846Z", "iopub.status.busy": "2022-12-14T22:30:04.896211Z", "iopub.status.idle": "2022-12-14T22:30:04.903243Z", "shell.execute_reply": "2022-12-14T22:30:04.902644Z" }, "id": "ThVMxqbVNOq3" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.reduce_max(np.array([1,2,3]))" ] }, { "cell_type": "markdown", "metadata": { "id": "NvSAbowVVuRr" }, "source": [ "## 形状简介" ] }, { "cell_type": "markdown", "metadata": { "id": "hkaBIqkTCcGY" }, "source": [ "张量有形状。下面是几个相关术语:\n", "\n", "- **形状**:张量的每个轴的长度(元素数量)。\n", "- **秩**:张量轴数。标量的秩为 0,向量的秩为 1,矩阵的秩为 2。\n", "- **轴**或**维度**:张量的一个特殊维度。\n", "- **大小**:张量的总项数,即形状矢量元素的乘积\n" ] }, { "cell_type": "markdown", "metadata": { "id": "E9L3-kCQq2f6" }, "source": [ "注:虽然您可能会看到“二维张量”之类的表述,但 2 秩张量通常并不是用来描述二维空间。" ] }, { "cell_type": "markdown", "metadata": { "id": "VFOyG2tn8LhW" }, "source": [ "张量和 `tf.TensorShape` 对象提供了方便的属性来访问:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.906656Z", "iopub.status.busy": "2022-12-14T22:30:04.906087Z", "iopub.status.idle": "2022-12-14T22:30:04.910665Z", "shell.execute_reply": "2022-12-14T22:30:04.910106Z" }, "id": "RyD3yewUKdnK" }, "outputs": [], "source": [ "rank_4_tensor = tf.zeros([3, 2, 4, 5])" ] }, { "cell_type": "markdown", "metadata": { "id": "oTZZW9ziq4og" }, "source": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", " \n", "
4 秩张量,形状:[3, 2, 4, 5]
\"A \"A
\n" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.914140Z", "iopub.status.busy": "2022-12-14T22:30:04.913668Z", "iopub.status.idle": "2022-12-14T22:30:04.918259Z", "shell.execute_reply": "2022-12-14T22:30:04.917562Z" }, "id": "MHm9vSqogsBk" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Type of every element: \n", "Number of axes: 4\n", "Shape of tensor: (3, 2, 4, 5)\n", "Elements along axis 0 of tensor: 3\n", "Elements along the last axis of tensor: 5\n", "Total number of elements (3*2*4*5): 120\n" ] } ], "source": [ "print(\"Type of every element:\", rank_4_tensor.dtype)\n", "print(\"Number of axes:\", rank_4_tensor.ndim)\n", "print(\"Shape of tensor:\", rank_4_tensor.shape)\n", "print(\"Elements along axis 0 of tensor:\", rank_4_tensor.shape[0])\n", "print(\"Elements along the last axis of tensor:\", rank_4_tensor.shape[-1])\n", "print(\"Total number of elements (3*2*4*5): \", tf.size(rank_4_tensor).numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "2ZGZp_JOOPOv" }, "source": [ "但请注意,`Tensor.ndim` 和 `Tensor.shape` 特性不返回 `Tensor` 对象。如果您需要 `Tensor`,请使用 `tf.rank` 或 `tf.shape` 函数。这种差异不易察觉,但在构建计算图时(稍后)可能非常重要。" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.921360Z", "iopub.status.busy": "2022-12-14T22:30:04.920890Z", "iopub.status.idle": "2022-12-14T22:30:04.924955Z", "shell.execute_reply": "2022-12-14T22:30:04.924402Z" }, "id": "Ptq0-y6APCpD" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.rank(rank_4_tensor)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.928000Z", "iopub.status.busy": "2022-12-14T22:30:04.927339Z", "iopub.status.idle": "2022-12-14T22:30:04.932386Z", "shell.execute_reply": "2022-12-14T22:30:04.931839Z" }, "id": "HslrDOEBPICN" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.shape(rank_4_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "bQmE_Vx5JilS" }, "source": [ "虽然通常用索引来指代轴,但是您始终要记住每个轴的含义。轴一般按照从全局到局部的顺序进行排序:首先是批次轴,随后是空间维度,最后是每个位置的特征。这样,在内存中,特征向量就会位于连续的区域。\n", "\n", "\n", "\n", "\n", "\n", "\n", " \n", "\n", "
典型的轴顺序
\"Keep
" ] }, { "cell_type": "markdown", "metadata": { "id": "FlPoVvJS75Bb" }, "source": [ "## 索引" ] }, { "cell_type": "markdown", "metadata": { "id": "apOkCKqCZIZu" }, "source": [ "### 单轴索引\n", "\n", "TensorFlow 遵循标准 Python 索引编制规则(类似于[在 Python 中为列表或字符串编制索引](https://docs.python.org/3/tutorial/introduction.html#strings){:.external})以及 NumPy 索引编制的基本规则。\n", "\n", "- 索引从 `0` 开始编制\n", "- 负索引表示按倒序编制索引\n", "- 冒号 `:` 用于切片:`start:stop:step`\n" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.935747Z", "iopub.status.busy": "2022-12-14T22:30:04.935162Z", "iopub.status.idle": "2022-12-14T22:30:04.939093Z", "shell.execute_reply": "2022-12-14T22:30:04.938447Z" }, "id": "SQ-CrJxLXTIM" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0 1 1 2 3 5 8 13 21 34]\n" ] } ], "source": [ "rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])\n", "print(rank_1_tensor.numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "mQYYL56PXSak" }, "source": [ "使用标量编制索引会移除轴:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.942312Z", "iopub.status.busy": "2022-12-14T22:30:04.941737Z", "iopub.status.idle": "2022-12-14T22:30:04.948508Z", "shell.execute_reply": "2022-12-14T22:30:04.947893Z" }, "id": "n6tqHciOWMt5" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "First: 0\n", "Second: 1\n", "Last: 34\n" ] } ], "source": [ "print(\"First:\", rank_1_tensor[0].numpy())\n", "print(\"Second:\", rank_1_tensor[1].numpy())\n", "print(\"Last:\", rank_1_tensor[-1].numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "qJLHU_a2XwpG" }, "source": [ "使用 `:` 切片编制索引会保留轴:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.951422Z", "iopub.status.busy": "2022-12-14T22:30:04.950937Z", "iopub.status.idle": "2022-12-14T22:30:04.963645Z", "shell.execute_reply": "2022-12-14T22:30:04.963048Z" }, "id": "giVPPcfQX-cu" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Everything: [ 0 1 1 2 3 5 8 13 21 34]\n", "Before 4: [0 1 1 2]\n", "From 4 to the end: [ 3 5 8 13 21 34]\n", "From 2, before 7: [1 2 3 5 8]\n", "Every other item: [ 0 1 3 8 21]\n", "Reversed: [34 21 13 8 5 3 2 1 1 0]\n" ] } ], "source": [ "print(\"Everything:\", rank_1_tensor[:].numpy())\n", "print(\"Before 4:\", rank_1_tensor[:4].numpy())\n", "print(\"From 4 to the end:\", rank_1_tensor[4:].numpy())\n", "print(\"From 2, before 7:\", rank_1_tensor[2:7].numpy())\n", "print(\"Every other item:\", rank_1_tensor[::2].numpy())\n", "print(\"Reversed:\", rank_1_tensor[::-1].numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "elDSxXi7X-Bh" }, "source": [ "### 多轴索引" ] }, { "cell_type": "markdown", "metadata": { "id": "Cgk0uRUYZiai" }, "source": [ "更高秩的张量通过传递多个索引来编制索引。\n", "\n", "对于高秩张量的每个单独的轴,遵循与单轴情形完全相同的规则。" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.966789Z", "iopub.status.busy": "2022-12-14T22:30:04.966328Z", "iopub.status.idle": "2022-12-14T22:30:04.969903Z", "shell.execute_reply": "2022-12-14T22:30:04.969327Z" }, "id": "Tc5X_WlsZXmd" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1. 2.]\n", " [3. 4.]\n", " [5. 6.]]\n" ] } ], "source": [ "print(rank_2_tensor.numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "w07U9vq5ipQk" }, "source": [ "为每个索引传递一个整数,结果是一个标量。" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.972913Z", "iopub.status.busy": "2022-12-14T22:30:04.972447Z", "iopub.status.idle": "2022-12-14T22:30:04.977464Z", "shell.execute_reply": "2022-12-14T22:30:04.976910Z" }, "id": "PvILXc1PjqTM" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4.0\n" ] } ], "source": [ "# Pull out a single value from a 2-rank tensor\n", "print(rank_2_tensor[1, 1].numpy())" ] }, { "cell_type": "markdown", "metadata": { "id": "3RLCzAOHjfEH" }, "source": [ "您可以使用整数与切片的任意组合编制索引:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.980623Z", "iopub.status.busy": "2022-12-14T22:30:04.980161Z", "iopub.status.idle": "2022-12-14T22:30:04.991570Z", "shell.execute_reply": "2022-12-14T22:30:04.990986Z" }, "id": "YTqNqsfJkJP_" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Second row: [3. 4.]\n", "Second column: [2. 4. 6.]\n", "Last row: [5. 6.]\n", "First item in last column: 2.0\n", "Skip the first row:\n", "[[3. 4.]\n", " [5. 6.]] \n", "\n" ] } ], "source": [ "# Get row and column tensors\n", "print(\"Second row:\", rank_2_tensor[1, :].numpy())\n", "print(\"Second column:\", rank_2_tensor[:, 1].numpy())\n", "print(\"Last row:\", rank_2_tensor[-1, :].numpy())\n", "print(\"First item in last column:\", rank_2_tensor[0, -1].numpy())\n", "print(\"Skip the first row:\")\n", "print(rank_2_tensor[1:, :].numpy(), \"\\n\")" ] }, { "cell_type": "markdown", "metadata": { "id": "P45TwSUVSK6G" }, "source": [ "下面是一个 3 轴张量的示例:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:04.994485Z", "iopub.status.busy": "2022-12-14T22:30:04.994019Z", "iopub.status.idle": "2022-12-14T22:30:04.999103Z", "shell.execute_reply": "2022-12-14T22:30:04.998480Z" }, "id": "GuLoMoCVSLxK" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ 4 9]\n", " [14 19]\n", " [24 29]], shape=(3, 2), dtype=int32)\n" ] } ], "source": [ "print(rank_3_tensor[:, :, 4])" ] }, { "cell_type": "markdown", "metadata": { "id": "9NgmHq27TJOE" }, "source": [ "\n", "\n", "\n", "\n", "\n", " \n", " \n", "\n", "
选择批次中每个示例的所有位置的最后一个特征
\"A \"The
" ] }, { "cell_type": "markdown", "metadata": { "id": "t9V83-thHn89" }, "source": [ "请参阅[张量切片指南](https://tensorflow.org/guide/tensor_slicing),了解如何应用索引编制以操作张量中的各个元素。" ] }, { "cell_type": "markdown", "metadata": { "id": "fpr7R0t4SVb0" }, "source": [ "## 操作形状\n", "\n", "改变张量的形状很有用。\n" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.001983Z", "iopub.status.busy": "2022-12-14T22:30:05.001761Z", "iopub.status.idle": "2022-12-14T22:30:05.005294Z", "shell.execute_reply": "2022-12-14T22:30:05.004738Z" }, "id": "EMeTtga5Wq8j" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(3, 1)\n" ] } ], "source": [ "# Shape returns a `TensorShape` object that shows the size along each axis\n", "x = tf.constant([[1], [2], [3]])\n", "print(x.shape)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.008105Z", "iopub.status.busy": "2022-12-14T22:30:05.007598Z", "iopub.status.idle": "2022-12-14T22:30:05.010860Z", "shell.execute_reply": "2022-12-14T22:30:05.010317Z" }, "id": "38jc2RXziT3W" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[3, 1]\n" ] } ], "source": [ "# You can convert this object into a Python list, too\n", "print(x.shape.as_list())" ] }, { "cell_type": "markdown", "metadata": { "id": "J_xRlHZMKYnF" }, "source": [ "通过重构可以改变张量的形状。`tf.reshape` 运算的速度很快,资源消耗很低,因为不需要复制底层数据。" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.013581Z", "iopub.status.busy": "2022-12-14T22:30:05.013380Z", "iopub.status.idle": "2022-12-14T22:30:05.017481Z", "shell.execute_reply": "2022-12-14T22:30:05.016917Z" }, "id": "pa9JCgMLWy87" }, "outputs": [], "source": [ "# You can reshape a tensor to a new shape.\n", "# Note that you're passing in a list\n", "reshaped = tf.reshape(x, [1, 3])" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.020501Z", "iopub.status.busy": "2022-12-14T22:30:05.020034Z", "iopub.status.idle": "2022-12-14T22:30:05.023279Z", "shell.execute_reply": "2022-12-14T22:30:05.022733Z" }, "id": "Mcq7iXOkW3LK" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(3, 1)\n", "(1, 3)\n" ] } ], "source": [ "print(x.shape)\n", "print(reshaped.shape)" ] }, { "cell_type": "markdown", "metadata": { "id": "gIB2tOkoVr6E" }, "source": [ "数据在内存中的布局保持不变,同时使用请求的形状创建一个指向同一数据的新张量。TensorFlow 采用 C 样式的“行优先”内存访问顺序,即最右侧的索引值递增对应于内存中的单步位移。" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.026260Z", "iopub.status.busy": "2022-12-14T22:30:05.025723Z", "iopub.status.idle": "2022-12-14T22:30:05.029226Z", "shell.execute_reply": "2022-12-14T22:30:05.028624Z" }, "id": "7kMfM0RpUgI8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[[ 0 1 2 3 4]\n", " [ 5 6 7 8 9]]\n", "\n", " [[10 11 12 13 14]\n", " [15 16 17 18 19]]\n", "\n", " [[20 21 22 23 24]\n", " [25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)\n" ] } ], "source": [ "print(rank_3_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "TcDtfQkJWzIx" }, "source": [ "如果您展平张量,则可以看到它在内存中的排列顺序。" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.032074Z", "iopub.status.busy": "2022-12-14T22:30:05.031679Z", "iopub.status.idle": "2022-12-14T22:30:05.035264Z", "shell.execute_reply": "2022-12-14T22:30:05.034716Z" }, "id": "COnHEPuaWDQp" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n", " 24 25 26 27 28 29], shape=(30,), dtype=int32)\n" ] } ], "source": [ "# A `-1` passed in the `shape` argument says \"Whatever fits\".\n", "print(tf.reshape(rank_3_tensor, [-1]))" ] }, { "cell_type": "markdown", "metadata": { "id": "jJZRira2W--c" }, "source": [ "一般来说,`tf.reshape` 唯一合理的用途是用于合并或拆分相邻轴(或添加/移除 `1`)。\n", "\n", "对于 3x2x5 张量,重构为 (3x2)x5 或 3x(2x5) 都合理,因为切片不会混淆:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.038098Z", "iopub.status.busy": "2022-12-14T22:30:05.037867Z", "iopub.status.idle": "2022-12-14T22:30:05.042380Z", "shell.execute_reply": "2022-12-14T22:30:05.041823Z" }, "id": "zP2Iqc7zWu_J" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ 0 1 2 3 4]\n", " [ 5 6 7 8 9]\n", " [10 11 12 13 14]\n", " [15 16 17 18 19]\n", " [20 21 22 23 24]\n", " [25 26 27 28 29]], shape=(6, 5), dtype=int32) \n", "\n", "tf.Tensor(\n", "[[ 0 1 2 3 4 5 6 7 8 9]\n", " [10 11 12 13 14 15 16 17 18 19]\n", " [20 21 22 23 24 25 26 27 28 29]], shape=(3, 10), dtype=int32)\n" ] } ], "source": [ "print(tf.reshape(rank_3_tensor, [3*2, 5]), \"\\n\")\n", "print(tf.reshape(rank_3_tensor, [3, -1]))" ] }, { "cell_type": "markdown", "metadata": { "id": "6ZsZRUhihlDB" }, "source": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "
一些正确的重构示例。
\"A \"The \"The
\n" ] }, { "cell_type": "markdown", "metadata": { "id": "nOcRxDC3jNIU" }, "source": [ "重构可以处理总元素个数相同的任何新形状,但是如果不遵从轴的顺序,则不会发挥任何作用。\n", "\n", "利用 `tf.reshape` 无法实现轴的交换,要交换轴,您需要使用 `tf.transpose`。\n" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.045302Z", "iopub.status.busy": "2022-12-14T22:30:05.044833Z", "iopub.status.idle": "2022-12-14T22:30:05.050284Z", "shell.execute_reply": "2022-12-14T22:30:05.049742Z" }, "id": "I9qDL_8u7cBH" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[[ 0 1 2 3 4]\n", " [ 5 6 7 8 9]\n", " [10 11 12 13 14]]\n", "\n", " [[15 16 17 18 19]\n", " [20 21 22 23 24]\n", " [25 26 27 28 29]]], shape=(2, 3, 5), dtype=int32) \n", "\n", "tf.Tensor(\n", "[[ 0 1 2 3 4 5]\n", " [ 6 7 8 9 10 11]\n", " [12 13 14 15 16 17]\n", " [18 19 20 21 22 23]\n", " [24 25 26 27 28 29]], shape=(5, 6), dtype=int32) \n", "\n", "InvalidArgumentError: {{function_node __wrapped__Reshape_device_/job:localhost/replica:0/task:0/device:GPU:0}} Input to reshape is a tensor with 30 values, but the requested shape requires a multiple of 7 [Op:Reshape]\n" ] } ], "source": [ "# Bad examples: don't do this\n", "\n", "# You can't reorder axes with reshape.\n", "print(tf.reshape(rank_3_tensor, [2, 3, 5]), \"\\n\") \n", "\n", "# This is a mess\n", "print(tf.reshape(rank_3_tensor, [5, 6]), \"\\n\")\n", "\n", "# This doesn't work at all\n", "try:\n", " tf.reshape(rank_3_tensor, [7, -1])\n", "except Exception as e:\n", " print(f\"{type(e).__name__}: {e}\")" ] }, { "cell_type": "markdown", "metadata": { "id": "qTM9-5eh68oo" }, "source": [ "\n", "\n", "\n", " \n", " \n", " \n", "\n", "
一些错误的重构示例。
\"You \"Anything \"The
" ] }, { "cell_type": "markdown", "metadata": { "id": "N9r90BvHCbTt" }, "source": [ "您可能会遇到非完全指定的形状。要么是形状包含 `None`(轴长度未知),要么是整个形状为 `None`(张量的秩未知)。\n", "\n", "除 [tf.RaggedTensor](#ragged_tensors) 外,此类形状只会在 TensorFlow 的符号化计算图构建 API 环境中出现:\n", "\n", "- [tf.function](function.ipynb)\n", "- [Keras 函数式 API](https://tensorflow.google.cn/guide/keras/functional)。\n" ] }, { "cell_type": "markdown", "metadata": { "id": "fDmFtFM7k0R2" }, "source": [ "## `DTypes` 详解\n", "\n", "使用 `Tensor.dtype` 属性可以检查 `tf.Tensor` 的数据类型。\n", "\n", "从 Python 对象创建 `tf.Tensor` 时,您可以选择指定数据类型。\n", "\n", "如果不指定,TensorFlow 会选择一个可以表示您的数据的数据类型。TensorFlow 将 Python 整数转换为 `tf.int32`,将 Python 浮点数转换为 `tf.float32`。另外,当转换为数组时,TensorFlow 会采用与 NumPy 相同的规则。\n", "\n", "数据类型可以相互转换。" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.053532Z", "iopub.status.busy": "2022-12-14T22:30:05.053075Z", "iopub.status.idle": "2022-12-14T22:30:05.060370Z", "shell.execute_reply": "2022-12-14T22:30:05.059786Z" }, "id": "5mSTDWbelUvu" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([2 3 4], shape=(3,), dtype=uint8)\n" ] } ], "source": [ "the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)\n", "the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)\n", "# Now, cast to an uint8 and lose the decimal precision\n", "the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)\n", "print(the_u8_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "s1yBlJsVlFSu" }, "source": [ "## 广播\n", "\n", "广播是从 [NumPy 中的等效功能](https://numpy.org/doc/stable/user/basics.broadcasting.html){:.external}借用的一个概念。简而言之,在一定条件下,对一组张量执行组合运算时,为了适应大张量,会对小张量进行“扩展”。\n", "\n", "最简单和最常见的例子是尝试将张量与标量相乘或相加。在这种情况下会对标量进行广播,使其变成与其他参数相同的形状。 " ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.063446Z", "iopub.status.busy": "2022-12-14T22:30:05.062862Z", "iopub.status.idle": "2022-12-14T22:30:05.067828Z", "shell.execute_reply": "2022-12-14T22:30:05.067251Z" }, "id": "P8sypqmagHQN" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([2 4 6], shape=(3,), dtype=int32)\n", "tf.Tensor([2 4 6], shape=(3,), dtype=int32)\n", "tf.Tensor([2 4 6], shape=(3,), dtype=int32)\n" ] } ], "source": [ "x = tf.constant([1, 2, 3])\n", "\n", "y = tf.constant(2)\n", "z = tf.constant([2, 2, 2])\n", "# All of these are the same computation\n", "print(tf.multiply(x, 2))\n", "print(x * y)\n", "print(x * z)" ] }, { "cell_type": "markdown", "metadata": { "id": "o0SBoR6voWcb" }, "source": [ "同样,可以扩展长度为 1 的轴,使其匹配其他参数。在同一个计算中可以同时扩展两个参数。\n", "\n", "在本例中,一个 3x1 的矩阵与一个 1x4 进行元素级乘法运算,从而产生一个 3x4 的矩阵。注意前导 1 是可选的:y 的形状是 `[4]`。" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.070883Z", "iopub.status.busy": "2022-12-14T22:30:05.070418Z", "iopub.status.idle": "2022-12-14T22:30:05.075380Z", "shell.execute_reply": "2022-12-14T22:30:05.074868Z" }, "id": "6sGmkPg3XANr" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[1]\n", " [2]\n", " [3]], shape=(3, 1), dtype=int32) \n", "\n", "tf.Tensor([1 2 3 4], shape=(4,), dtype=int32) \n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ 1 2 3 4]\n", " [ 2 4 6 8]\n", " [ 3 6 9 12]], shape=(3, 4), dtype=int32)\n" ] } ], "source": [ "# These are the same computations\n", "x = tf.reshape(x,[3,1])\n", "y = tf.range(1, 5)\n", "print(x, \"\\n\")\n", "print(y, \"\\n\")\n", "print(tf.multiply(x, y))" ] }, { "cell_type": "markdown", "metadata": { "id": "t_7sh-EUYLrE" }, "source": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
广播相加:[3, 1] 乘以 [1, 4] 的结果是 [3,4]
\"Adding
\n" ] }, { "cell_type": "markdown", "metadata": { "id": "9V3KgSJcKDRz" }, "source": [ "下面是不使用广播的同一运算:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.078446Z", "iopub.status.busy": "2022-12-14T22:30:05.077939Z", "iopub.status.idle": "2022-12-14T22:30:05.082545Z", "shell.execute_reply": "2022-12-14T22:30:05.081987Z" }, "id": "elrF6v63igY8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[ 1 2 3 4]\n", " [ 2 4 6 8]\n", " [ 3 6 9 12]], shape=(3, 4), dtype=int32)\n" ] } ], "source": [ "x_stretch = tf.constant([[1, 1, 1, 1],\n", " [2, 2, 2, 2],\n", " [3, 3, 3, 3]])\n", "\n", "y_stretch = tf.constant([[1, 2, 3, 4],\n", " [1, 2, 3, 4],\n", " [1, 2, 3, 4]])\n", "\n", "print(x_stretch * y_stretch) # Again, operator overloading" ] }, { "cell_type": "markdown", "metadata": { "id": "14KobqYu85gi" }, "source": [ "在大多数情况下,广播的时间和空间效率更高,因为广播运算不会在内存中具体化扩展的张量。\n", "\n", "使用 `tf.broadcast_to` 可以了解广播的运算方式。" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.085460Z", "iopub.status.busy": "2022-12-14T22:30:05.084994Z", "iopub.status.idle": "2022-12-14T22:30:05.090086Z", "shell.execute_reply": "2022-12-14T22:30:05.089500Z" }, "id": "GW2Q59_r8hZ6" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[1 2 3]\n", " [1 2 3]\n", " [1 2 3]], shape=(3, 3), dtype=int32)\n" ] } ], "source": [ "print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))" ] }, { "cell_type": "markdown", "metadata": { "id": "Z2bAMMQY-jpP" }, "source": [ "与数学运算不同,`broadcast_to` 并不会节省内存。在这个示例中,您将具体化张量。\n", "\n", "这可能会变得更复杂。Jake VanderPlas 的 Python 数据科学手册一书中的这一节{:.external}介绍了更多广播技巧(同样使用 NumPy)。" ] }, { "cell_type": "markdown", "metadata": { "id": "o4Rpz0xAsKSI" }, "source": [ "## tf.convert_to_tensor\n", "\n", "大部分运算(如 `tf.matmul` 和 `tf.reshape`)会使用 `tf.Tensor` 类的参数。不过,在上面的示例中,您会发现形状类似于张量的 Python 对象也可以接受。\n", "\n", "大部分(但并非全部)运算会在非张量参数上调用 `convert_to_tensor`。我们提供了一个转换注册表,大多数对象类(如 NumPy 的 `ndarray`、`TensorShape`、Python 列表和 `tf.Variable`)都可以自动转换。\n", "\n", "有关更多详细信息,请参阅 `tf.register_tensor_conversion_function`。如果您有自己的类型,则可能希望自动转换为张量。" ] }, { "cell_type": "markdown", "metadata": { "id": "05bBVBVYV0y6" }, "source": [ "## 不规则张量\n", "\n", "如果张量的某个轴上的元素个数可变,则称为“不规则”张量。对于不规则数据,请使用 `tf.ragged.RaggedTensor`。\n", "\n", "例如,下面的例子无法用规则张量表示:" ] }, { "cell_type": "markdown", "metadata": { "id": "VPc3jGoeJqB7" }, "source": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
“tf.RaggedTensor”,形状:[4, None]
\"A
" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.093424Z", "iopub.status.busy": "2022-12-14T22:30:05.092955Z", "iopub.status.idle": "2022-12-14T22:30:05.095933Z", "shell.execute_reply": "2022-12-14T22:30:05.095392Z" }, "id": "VsbTjoFfNVBF" }, "outputs": [], "source": [ "ragged_list = [\n", " [0, 1, 2, 3],\n", " [4, 5],\n", " [6, 7, 8],\n", " [9]]" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.098829Z", "iopub.status.busy": "2022-12-14T22:30:05.098324Z", "iopub.status.idle": "2022-12-14T22:30:05.101935Z", "shell.execute_reply": "2022-12-14T22:30:05.101309Z" }, "id": "p4xKTo57tutG" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ValueError: Can't convert non-rectangular Python sequence to Tensor.\n" ] } ], "source": [ "try:\n", " tensor = tf.constant(ragged_list)\n", "except Exception as e:\n", " print(f\"{type(e).__name__}: {e}\")" ] }, { "cell_type": "markdown", "metadata": { "id": "0cm9KuEeMLGI" }, "source": [ "应使用 `tf.ragged.constant` 来创建 `tf.RaggedTensor`:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.104995Z", "iopub.status.busy": "2022-12-14T22:30:05.104426Z", "iopub.status.idle": "2022-12-14T22:30:05.109071Z", "shell.execute_reply": "2022-12-14T22:30:05.108434Z" }, "id": "XhF3QV3jiqTj" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "ragged_tensor = tf.ragged.constant(ragged_list)\n", "print(ragged_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "sFgHduHVNoIE" }, "source": [ "`tf.RaggedTensor` 的形状将包含一些具有未知长度的轴:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.112160Z", "iopub.status.busy": "2022-12-14T22:30:05.111604Z", "iopub.status.idle": "2022-12-14T22:30:05.114810Z", "shell.execute_reply": "2022-12-14T22:30:05.114263Z" }, "id": "Eo_3wJUWNgqB" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(4, None)\n" ] } ], "source": [ "print(ragged_tensor.shape)" ] }, { "cell_type": "markdown", "metadata": { "id": "V9njclVkkN7G" }, "source": [ "## 字符串张量\n", "\n", "`tf.string` 是一种 `dtype`,也就是说,在张量中,您可以用字符串(可变长度字节数组)来表示数据。\n", "\n", "字符串是原子类型,无法像 Python 字符串一样编制索引。字符串的长度并不是张量的一个轴。有关操作字符串的函数,请参阅 `tf.strings`。" ] }, { "cell_type": "markdown", "metadata": { "id": "5P_8spEGQ0wp" }, "source": [ "下面是一个标量字符串张量:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.118086Z", "iopub.status.busy": "2022-12-14T22:30:05.117568Z", "iopub.status.idle": "2022-12-14T22:30:05.122035Z", "shell.execute_reply": "2022-12-14T22:30:05.121471Z" }, "id": "sBosmM8MkIh4" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(b'Gray wolf', shape=(), dtype=string)\n" ] } ], "source": [ "# Tensors can be strings, too here is a scalar string.\n", "scalar_string_tensor = tf.constant(\"Gray wolf\")\n", "print(scalar_string_tensor)" ] }, { "cell_type": "markdown", "metadata": { "id": "CMFBSl1FQ3vE" }, "source": [ "下面是一个字符串向量:" ] }, { "cell_type": "markdown", "metadata": { "id": "IO-c3Tq3RC1L" }, "source": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
字符串向量,形状:[3,]
\"The
" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.125062Z", "iopub.status.busy": "2022-12-14T22:30:05.124593Z", "iopub.status.idle": "2022-12-14T22:30:05.128245Z", "shell.execute_reply": "2022-12-14T22:30:05.127640Z" }, "id": "41Dv2kL9QrtO" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([b'Gray wolf' b'Quick brown fox' b'Lazy dog'], shape=(3,), dtype=string)\n" ] } ], "source": [ "# If you have three string tensors of different lengths, this is OK.\n", "tensor_of_strings = tf.constant([\"Gray wolf\",\n", " \"Quick brown fox\",\n", " \"Lazy dog\"])\n", "# Note that the shape is (3,). The string length is not included.\n", "print(tensor_of_strings)" ] }, { "cell_type": "markdown", "metadata": { "id": "76gQ9qrgSMzS" }, "source": [ "在上面的打印输出中,`b` 前缀表示 `tf.string` dtype 不是 Unicode 字符串,而是字节字符串。有关在 TensorFlow 如何使用 Unicode 文本的详细信息,请参阅 [Unicode 教程](https://tensorflow.google.cn/tutorials/load_data/unicode)。" ] }, { "cell_type": "markdown", "metadata": { "id": "ClSBPK-lZBQp" }, "source": [ "如果传递 Unicode 字符,则会使用 utf-8 编码。" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.131347Z", "iopub.status.busy": "2022-12-14T22:30:05.130887Z", "iopub.status.idle": "2022-12-14T22:30:05.134873Z", "shell.execute_reply": "2022-12-14T22:30:05.134330Z" }, "id": "GTgL53jxSMd9" }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tf.constant(\"🥳👍\")" ] }, { "cell_type": "markdown", "metadata": { "id": "Ir9cY42MMAei" }, "source": [ "在 `tf.strings` 中可以找到用于操作字符串的一些基本函数,包括 `tf.strings.split`。" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.138169Z", "iopub.status.busy": "2022-12-14T22:30:05.137646Z", "iopub.status.idle": "2022-12-14T22:30:05.169676Z", "shell.execute_reply": "2022-12-14T22:30:05.169121Z" }, "id": "8k2K0VTFyj8e" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([b'Gray' b'wolf'], shape=(2,), dtype=string)\n" ] } ], "source": [ "# You can use split to split a string into a set of tensors\n", "print(tf.strings.split(scalar_string_tensor, sep=\" \"))" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.172586Z", "iopub.status.busy": "2022-12-14T22:30:05.172121Z", "iopub.status.idle": "2022-12-14T22:30:05.180597Z", "shell.execute_reply": "2022-12-14T22:30:05.180001Z" }, "id": "zgGAn1dfR-04" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# ...but it turns into a `RaggedTensor` if you split up a tensor of strings,\n", "# as each string might be split into a different number of parts.\n", "print(tf.strings.split(tensor_of_strings))" ] }, { "cell_type": "markdown", "metadata": { "id": "HsAn1kPeO84m" }, "source": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
三个字符串分割,形状:[3, None]
\"Splitting
" ] }, { "cell_type": "markdown", "metadata": { "id": "st9OxrUxWSKY" }, "source": [ "以及 `tf.string.to_number`:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.183780Z", "iopub.status.busy": "2022-12-14T22:30:05.183170Z", "iopub.status.idle": "2022-12-14T22:30:05.194025Z", "shell.execute_reply": "2022-12-14T22:30:05.193474Z" }, "id": "3nRtx3X9WRfN" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor([ 1. 10. 100.], shape=(3,), dtype=float32)\n" ] } ], "source": [ "text = tf.constant(\"1 10 100\")\n", "print(tf.strings.to_number(tf.strings.split(text, \" \")))" ] }, { "cell_type": "markdown", "metadata": { "id": "r2EZtBbJBns4" }, "source": [ "虽然不能使用 `tf.cast` 将字符串张量转换为数值,但是可以先将其转换为字节,然后转换为数值。" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.196821Z", "iopub.status.busy": "2022-12-14T22:30:05.196360Z", "iopub.status.idle": "2022-12-14T22:30:05.208325Z", "shell.execute_reply": "2022-12-14T22:30:05.207696Z" }, "id": "fo8BjmH7gyTj" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Byte strings: tf.Tensor([b'D' b'u' b'c' b'k'], shape=(4,), dtype=string)\n", "Bytes: tf.Tensor([ 68 117 99 107], shape=(4,), dtype=uint8)\n" ] } ], "source": [ "byte_strings = tf.strings.bytes_split(tf.constant(\"Duck\"))\n", "byte_ints = tf.io.decode_raw(tf.constant(\"Duck\"), tf.uint8)\n", "print(\"Byte strings:\", byte_strings)\n", "print(\"Bytes:\", byte_ints)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.211217Z", "iopub.status.busy": "2022-12-14T22:30:05.210747Z", "iopub.status.idle": "2022-12-14T22:30:05.225783Z", "shell.execute_reply": "2022-12-14T22:30:05.225226Z" }, "id": "uSQnZ7d1jCSQ" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Unicode bytes: tf.Tensor(b'\\xe3\\x82\\xa2\\xe3\\x83\\x92\\xe3\\x83\\xab \\xf0\\x9f\\xa6\\x86', shape=(), dtype=string)\n", "\n", "Unicode chars: tf.Tensor([b'\\xe3\\x82\\xa2' b'\\xe3\\x83\\x92' b'\\xe3\\x83\\xab' b' ' b'\\xf0\\x9f\\xa6\\x86'], shape=(5,), dtype=string)\n", "\n", "Unicode values: tf.Tensor([ 12450 12498 12523 32 129414], shape=(5,), dtype=int32)\n" ] } ], "source": [ "# Or split it up as unicode and then decode it\n", "unicode_bytes = tf.constant(\"アヒル 🦆\")\n", "unicode_char_bytes = tf.strings.unicode_split(unicode_bytes, \"UTF-8\")\n", "unicode_values = tf.strings.unicode_decode(unicode_bytes, \"UTF-8\")\n", "\n", "print(\"\\nUnicode bytes:\", unicode_bytes)\n", "print(\"\\nUnicode chars:\", unicode_char_bytes)\n", "print(\"\\nUnicode values:\", unicode_values)" ] }, { "cell_type": "markdown", "metadata": { "id": "fE7nKJ2YW3aY" }, "source": [ "`tf.string` dtype 可用于 TensorFlow 中的所有原始字节数据。`tf.io` 模块包含在数据与字节类型之间进行相互转换的函数,包括解码图像和解析 csv 的函数。" ] }, { "cell_type": "markdown", "metadata": { "id": "ua8BnAzxkRKV" }, "source": [ "## 稀疏张量\n", "\n", "在某些情况下,数据很稀疏,比如说在一个非常宽的嵌入空间中。为了高效存储稀疏数据,TensorFlow 支持 `tf.sparse.SparseTensor` 和相关运算。" ] }, { "cell_type": "markdown", "metadata": { "id": "mS5zgqgUTPRb" }, "source": [ "\n", "\n", " \n", "\n", "\n", " \n", "\n", "
“tf.SparseTensor”,形状:[3, 4]
\"An
" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "execution": { "iopub.execute_input": "2022-12-14T22:30:05.228864Z", "iopub.status.busy": "2022-12-14T22:30:05.228458Z", "iopub.status.idle": "2022-12-14T22:30:05.237259Z", "shell.execute_reply": "2022-12-14T22:30:05.236704Z" }, "id": "B9nbO1E2kSUN" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "SparseTensor(indices=tf.Tensor(\n", "[[0 0]\n", " [1 2]], shape=(2, 2), dtype=int64), values=tf.Tensor([1 2], shape=(2,), dtype=int32), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64)) \n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "tf.Tensor(\n", "[[1 0 0 0]\n", " [0 0 2 0]\n", " [0 0 0 0]], shape=(3, 4), dtype=int32)\n" ] } ], "source": [ "# Sparse tensors store values by index in a memory-efficient manner\n", "sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],\n", " values=[1, 2],\n", " dense_shape=[3, 4])\n", "print(sparse_tensor, \"\\n\")\n", "\n", "# You can convert sparse tensors to dense\n", "print(tf.sparse.to_dense(sparse_tensor))" ] } ], "metadata": { "colab": { "collapsed_sections": [ "Tce3stUlHN0L" ], "name": "tensor.ipynb", "toc_visible": true }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" } }, "nbformat": 4, "nbformat_minor": 0 }