自定义基础:张量和操作

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

这是一个介绍性的 TensorFlow 教程,展示了如何

  • 导入所需的包。
  • 创建和使用张量。
  • 使用 GPU 加速。
  • 使用 tf.data.Dataset 构建数据管道。

导入 TensorFlow

要开始,请导入 tensorflow 模块。从 TensorFlow 2 开始,默认情况下会启用急切执行。急切执行为 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 ndarrays 转换为张量。
  • NumPy 操作会自动将张量转换为 NumPy ndarrays。

使用张量的 .numpy() 方法将张量显式转换为 NumPy ndarrays。这些转换通常很便宜,因为数组和 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'), PhysicalDevice(name='/physical_device:GPU:2', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:3', 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: 42.76ms
On GPU:
10 loops: 300.72ms

数据集

本节使用 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()

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 25], shape=(2,), dtype=int32)
tf.Tensor([16 36], 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)