文章目录
- Basics
- About shapes
- Indexing
- Single-axis indexing
- Multi-axis indexing
- Manipulating Shapes
- More on dtypes
- References
import tensorflow as tf
import numpy as np
Basics
张量是具有统一类型(dtype
)的多维数组。它和 NumPy 中的 np.arrays
是非常类似的。如 Python 的数值和字符串类型一样,张量是不可变的(immutable):张量内容无法更新,只能创建新的张量。
包含单个数值的标量我们可以叫做 0-秩张量(rank-0),它没有轴:
rank_0_tensor = tf.constant(22)
rank_0_tensor
"""
<tf.Tensor: shape=(), dtype=int32, numpy=22>
"""
包含一个值列表的向量可以叫做 1-秩张量,它有一个轴:
rank_1_tensor = tf.constant([2.0, 3.0, 5.0])
rank_1_tensor
"""
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([2., 3., 5.], dtype=float32)>
"""
矩阵可以叫做 2-秩张量,它有两个轴:
rank_2_tensor = tf.constant([[1, 2],
[3, 4],
[5, 6]], dtype=tf.float16)
rank_2_tensor
"""
<tf.Tensor: shape=(3, 2), dtype=float16, numpy=
array([[1., 2.],
[3., 4.],
[5., 6.]], dtype=float16)>
"""
张量也可以包含更多的轴,如 3 个或者 4 个,这也是我们在处理计算机视觉问题时最常遇到的轴维度,下面是一个 3-秩张量:
rank_3_tensor = tf.constant([
[[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]
])
rank_3_tensor
"""
<tf.Tensor: shape=(3, 2, 5), dtype=int32, numpy=
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]], dtype=int32)>
"""
我们可以使用 np.array
函数或者 .numpy
方法来将一个张量转换成 NumPy 数组:
np.array(rank_2_tensor)
"""
array([[1., 2.],
[3., 4.],
[5., 6.]], dtype=float16)
"""
rank_3_tensor.numpy()
"""
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9]],
[[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]],
[[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]], dtype=int32)
"""
我们可以对张量做一些基本的数学运算,如加法、逐元素乘法和矩阵乘法:
a = tf.constant([[1, 2],
[3, 4]])
b = tf.constant([[1, 1],
[1, 1]]) # 也可写为 b = tf.ones([2, 2])
print(tf.add(a, b), "\n")
print(tf.multiply(a, b), "\n")
print(tf.matmul(a, b), "\n")
"""
tf.Tensor(
[[2 3]
[4 5]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[1 2]
[3 4]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[3 3]
[7 7]], shape=(2, 2), dtype=int32)
"""
另外一种写法:
print(a + b, "\n")
print(a * b, "\n")
print(a @ b, "\n")
"""
tf.Tensor(
[[2 3]
[4 5]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[1 2]
[3 4]], shape=(2, 2), dtype=int32)
tf.Tensor(
[[3 3]
[7 7]], shape=(2, 2), dtype=int32)
"""
About shapes
张量形状的几个相关术语:
- 形状(shape):张量的每个轴的长度(即元素数量)
- 秩(rank):张量的轴数
- 轴或维度(axis or dimension):张量的某个维度
- 大小(size):张量的总项数,即形状向量的乘积
下面我们来看如何来访问这些属性:
rank_4_tensor = tf.zeros([3, 2, 4, 5])
print("Type of every element:", rank_4_tensor.dtype)
print("Number of dimensions:", rank_4_tensor.ndim)
print("Shape of tensor:", rank_4_tensor.shape)
print("Elements along axis 0 of tensor", rank_4_tensor.shape[0])
print("Total number of elements (3*2*4*5):", tf.size(rank_4_tensor).numpy())
"""
Type of every element: <dtype: 'float32'>
Number of dimensions: 4
Shape of tensor: (3, 2, 4, 5)
Elements along axis 0 of tensor 3
Total number of elements (3*2*4*5): 120
"""
.ndim
和.shape
方法返回的不是张量对象,如果想要返回张量,则需使用tf.rank
和tf.shape
函数。
虽然通常用索引来指代轴,但在我们的实际问题中,每个轴是有实际含义的,如下图所示:
在计算机视觉任务中,即对于图片数据集来说,最后一个轴表示的其实为通道数。
Indexing
Single-axis indexing
单轴索引和 Python 中的列表以及 NumPy 索引类似。
标量索引:
rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
print("First:", rank_1_tensor[0].numpy())
print("Second:", rank_1_tensor[1].numpy())
print("Last:", rank_1_tensor[-1].numpy())
"""
First: 0
Second: 1
Last: 34
"""
使用冒号的切片索引:
print("Everything:", rank_1_tensor[:].numpy())
print("Before 4:", rank_1_tensor[:4].numpy())
print("From 4 to the end:", rank_1_tensor[4:].numpy())
print("From 2, before 7:", rank_1_tensor[2:7].numpy())
print("Every other item:", rank_1_tensor[::2].numpy()) # start:stop:step
print("Reversed:", rank_1_tensor[::-1].numpy())
"""
Everything: [ 0 1 1 2 3 5 8 13 21 34]
Before 4: [0 1 1 2]
From 4 to the end: [ 3 5 8 13 21 34]
From 2, before 7: [1 2 3 5 8]
Every other item: [ 0 1 3 8 21]
Reversed: [34 21 13 8 5 3 2 1 1 0]
"""
Multi-axis indexing
对于高秩张量的每个单独的轴,遵循与单轴情形完全相同的规则。
为每个索引轴传递一个整数,结果是对应位置的标量:
print(rank_2_tensor)
rank_2_tensor[1, 1].numpy()
"""
tf.Tensor(
[[1. 2.]
[3. 4.]
[5. 6.]], shape=(3, 2), dtype=float16)
4.0
"""
索引任何行、列:
print("Second row:", rank_2_tensor[1, :].numpy())
print("Second column:", rank_2_tensor[:, 1].numpy())
print("Last row:", rank_2_tensor[-1, :].numpy())
print("First item in last column:", rank_2_tensor[0, -1].numpy())
print("Skip the first row:")
print(rank_2_tensor[1:, :].numpy(), "\n")
"""
Second row: [3. 4.]
Second column: [2. 4. 6.]
Last row: [5. 6.]
First item in last column: 2.0
Skip the first row:
[[3. 4.]
[5. 6.]]
"""
对于我们上面定义的 3-秩张量,我们想选择每个批次中每个示例的所有位置的最后一个特征:
rank_3_tensor[:, :, 4]
"""
tf.Tensor(
[[ 4 9]
[14 19]
[24 29]], shape=(3, 2), dtype=int32)
"""
我们会得到一个二维张量,画出图来就是这样的:
稍微做些改动:
rank_3_tensor[:, :, 4:]
"""
tf.Tensor(
[[[ 4]
[ 9]]
[[14]
[19]]
[[24]
[29]]], shape=(3, 2, 1), dtype=int32)
"""
我们会发现得到的是一个三维张量。所以一定要注意冒号的使用。
Manipulating Shapes
x = tf.constant([[1], [2], [3]])
print(x.shape)
"""
(3, 1)
"""
可以将返回的 TensorShape
对象转换为列表:
print(x.shape.as_list())
"""
[3, 1]
"""
使用 .reshape
方法改变张量的形状,该方法速度很快,资源消耗很低,因为不需要复制底层数据。
reshaped = tf.reshape(var_x, [1, 3])
注意我们传入的形状为列表类型。
print(var_x.shape)
print(reshaped.shape)
"""
(3, 1)
(1, 3)
"""
TensorFlow 使用“行优先”的内存访问顺序。把一个张量展平,我们可以看到它在内存中的排列顺序:
print(rank_3_tensor)
"""
tf.Tensor(
[[[ 0 1 2 3 4]
[ 5 6 7 8 9]]
[[10 11 12 13 14]
[15 16 17 18 19]]
[[20 21 22 23 24]
[25 26 27 28 29]]], shape=(3, 2, 5), dtype=int32)
"""
print(tf.reshape(rank_3_tensor, [-1]))
"""
tf.Tensor(
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29], shape=(30,), dtype=int32)
"""
利用 tf.reshape
无法实现轴的交换,要交换轴,我们需要使用 tf.transpose
。
tf.transpose(rank_3_tensor, (1, 0, 2))
"""
<tf.Tensor: shape=(2, 3, 5), dtype=int32, numpy=
array([[[ 0, 1, 2, 3, 4],
[10, 11, 12, 13, 14],
[20, 21, 22, 23, 24]],
[[ 5, 6, 7, 8, 9],
[15, 16, 17, 18, 19],
[25, 26, 27, 28, 29]]], dtype=int32)>
"""
More on dtypes
如果创建张量时没有指定数据类型,TensorFlow 会将 Python 整数转换为 tf.int32
,将 Python 浮点数转换为 tf.float32
。另外,当转换为数组时,TensorFlow 会采用与 NumPy 相同的规则。
我们可以使用 tf.cast
函数来转换张量的数据类型:
the_f64_tensor = tf.constant([2.2, 3.3, 4.4], dtype=tf.float64)
the_f16_tensor = tf.cast(the_f64_tensor, dtype=tf.float16)
the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)
print(the_u8_tensor)
"""
tf.Tensor([2 3 4], shape=(3,), dtype=uint8)
"""
References
TensorFlow 官方文档 (https://tensorflow.google.cn/guide/tensor)