TensorFlow 基础(一)张量


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.ranktf.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

猜你喜欢

转载自blog.csdn.net/myDarling_/article/details/128579151