##### Copyright 2018 The TensorFlow Authors.
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

自定义基础知识:张量和运算#

在 TensorFlow.org 查看 在 Google Colab 中运行 在 Github 上查看源代码 下载笔记本

本 TensorFlow 入门教程可帮助您了解如何:

  • 导入所需的软件包。

  • 创建和使用张量。

  • 使用 GPU 加速。

  • 使用 tf.data.Dataset 构建数据流水线。

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'  # 设置日志级别为ERROR,以减少警告信息
# 禁用 Gemini 的底层库(gRPC 和 Abseil)在初始化日志警告
os.environ["GRPC_VERBOSITY"] = "ERROR"
os.environ["GLOG_minloglevel"] = "3"  # 0: INFO, 1: WARNING, 2: ERROR, 3: FATAL
os.environ["GLOG_minloglevel"] = "true"
import logging
import tensorflow as tf
tf.get_logger().setLevel(logging.ERROR)
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
!export TF_FORCE_GPU_ALLOW_GROWTH=true
from pathlib import Path

temp_dir = Path(".temp")
temp_dir.mkdir(parents=True, exist_ok=True)

导入 TensorFlow#

首先,导入 tensorflow 模块。从 TensorFlow 2 开始,会默认打开 Eager Execution。Eager Execution 可以使 TensorFlow 的前端交互性更高,稍后将更详细地探索它。

import tensorflow as tf

张量#

张量是一个多维数组。与 NumPy ndarray 对象类似,tf.Tensor 对象也具有数据类型和形状。此外,tf.Tensor 可以驻留在加速器内存(例如 GPU)中。TensorFlow 提供了丰富的运算库(tf.math.addtf.linalg.matmultf.linalg.inv 等),这些运算使用和生成 tf.Tensor。这些运算会自动转换原生 Python 类型,例如:

print(tf.math.add(1, 2))
print(tf.math.add([1, 2], [3, 4]))
print(tf.math.square(5))
print(tf.math.reduce_sum([1, 2, 3]))

# Operator overloading is also supported
print(tf.math.square(2) + tf.math.square(3))
tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor([4 6], shape=(2,), dtype=int32)
tf.Tensor(25, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(13, shape=(), dtype=int32)

每个 tf.Tensor 都具有形状和数据类型:

x = tf.linalg.matmul([[1]], [[2, 3]])
print(x)
print(x.shape)
print(x.dtype)
tf.Tensor([[2 3]], shape=(1, 2), dtype=int32)
(1, 2)
<dtype: 'int32'>

NumPy 数组与 tf.Tensor 之间最明显的区别是:

  1. 张量可以驻留在加速器内存(例如 GPU、TPU)中。

  2. 张量不可变。

NumPy 兼容性#

在 TensorFlow tf.Tensor 和 NumPy ndarray 之间进行转换非常容易:

  • TensorFlow 运算会自动将 NumPy ndarray 转换为张量。

  • NumPy 运算会自动将张量转换为 NumPy ndarray。

张量可以使用 .numpy() 方法显式转换为 NumPy ndarray。这些转换的开销通常比较小,因为如果可行,数组和 tf.Tensor 将共享底层内存表示。但是,共享底层表示并非始终可行,因为 tf.Tensor 可能托管在 GPU 内存中,而 NumPy 数组则始终驻留在主机内存中,所以转换涉及从 GPU 向主机内存复制的过程。

import numpy as np

ndarray = np.ones([3, 3])

print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.math.multiply(ndarray, 42)
print(tensor)


print("And NumPy operations convert Tensors to NumPy arrays automatically")
print(np.add(tensor, 1))

print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())
TensorFlow operations convert numpy arrays to Tensors automatically
tf.Tensor(
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]], shape=(3, 3), dtype=float64)
And NumPy operations convert Tensors to NumPy arrays automatically
[[43. 43. 43.]
 [43. 43. 43.]
 [43. 43. 43.]]
The .numpy() method explicitly converts a Tensor to a numpy array
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]]

GPU 加速#

许多 TensorFlow 操作都可使用 GPU 来加速计算。无需任何注释,TensorFlow 会自动决定是使用 GPU 还是 CPU 进行操作 - 如有必要,会在 CPU 和 GPU 内存之间复制张量。 由操作生成的张量通常驻留在执行操作的设备的内存中,例如:

x = tf.random.uniform([3, 3])

print("Is there a GPU available: "),
print(tf.config.list_physical_devices("GPU"))

print("Is the Tensor on GPU #0:  "),
print(x.device.endswith('GPU:0'))
Is there a GPU available: 
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU')]
Is the Tensor on GPU #0:  
True

设备名称#

Tensor.device 属性提供存放张量内容的设备的完全限定字符串名称。此名称会编码许多详细信息,例如执行此程序的主机的网络地址标识符以及该主机内设备的标识符。这是分布式执行 TensorFlow 程序所必需的信息。如果将张量放置在主机的第 N 个 GPU 上,则该字符串将以 GPU:<N> 结尾。

显式设备放置#

在 TensorFlow 中,放置指的是各个运算在设备上如何分配(放置)以执行。如上所述,如果没有提供明确的指导,TensorFlow 将自动决定执行运算的设备,并在需要时将张量复制到该设备。

不过,可以使用 tf.device 上下文管理器将 TensorFlow 运算显式放置在特定设备上。例如:

import time

def time_matmul(x):
  start = time.time()
  for loop in range(10):
    tf.linalg.matmul(x, x)

  result = time.time()-start

  print("10 loops: {:0.2f}ms".format(1000*result))

# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
  x = tf.random.uniform([1000, 1000])
  assert x.device.endswith("CPU:0")
  time_matmul(x)

# Force execution on GPU #0 if available
if tf.config.list_physical_devices("GPU"):
  print("On GPU:")
  with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
    x = tf.random.uniform([1000, 1000])
    assert x.device.endswith("GPU:0")
    time_matmul(x)
On CPU:
10 loops: 1095.17ms
On GPU:
10 loops: 363.62ms

数据集#

本部分使用 tf.data.Dataset API 构建为模型提供数据的流水线。tf.data.Dataset 用于从简单、可重用的数据流水线构建高性能、复杂的输入流水线,为模型的训练或评估循环馈送数据。(有关详情,请参阅 tf.data:构建 TensorFlow 输入流水线指南。)

创建源 Dataset#

使用诸如 tf.data.Dataset.from_tensorstf.data.Dataset.from_tensor_slices 等工厂函数之一,或使用从诸如 tf.data.TextLineDatasettf.data.TFRecordDataset 等文件读取的对象创建数据集。有关详情,请参阅 tf.data:构建 TensorFlow 输入流水线指南的读取输入数据部分。

ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])

# Create a CSV file
import tempfile
_, filename = tempfile.mkstemp(dir=temp_dir)

with open(filename, 'w') as f:
  f.write("""Line 1
Line 2
Line 3
  """)

ds_file = tf.data.TextLineDataset(filename)

应用转换#

使用 tf.data.Dataset.maptf.data.Dataset.batchtf.data.Dataset.shuffle 等转换函数对数据集记录应用转换。

ds_tensors = ds_tensors.map(tf.math.square).shuffle(2).batch(2)

ds_file = ds_file.batch(2)

迭代#

tf.data.Dataset 对象支持迭代以循环记录:

print('Elements of ds_tensors:')
for x in ds_tensors:
  print(x)

print('\nElements in ds_file:')
for x in ds_file:
  print(x)
Elements of ds_tensors:
tf.Tensor([4 9], shape=(2,), dtype=int32)
tf.Tensor([ 1 16], shape=(2,), dtype=int32)
tf.Tensor([36 25], shape=(2,), dtype=int32)

Elements in ds_file:
tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)
tf.Tensor([b'Line 3' b'  '], shape=(2,), dtype=string)