本文是对官方文档 的学习笔记。
介绍
Tensor 的特点:
- 多维
- 一个Tensor 内部数据结构一致, 数据格式见
tf.dtypes.DType
- 不可变(immutable), 就像 Python string, 所有 Tensor 都是常量
基础
这是一个 0 阶 Tensor, 没有“轴”
# This will be an int32 tensor by default; see "dtypes" below.
rank_0_tensor = tf.constant(4)
print(rank_0_tensor)
tf.Tensor(4, shape=(), dtype=int32)
一阶 Tensor 类似一个 List, 有一个“轴”
# Let's make this a float tensor.
rank_1_tensor = tf.constant([2.0, 3.0, 4.0])
print(rank_1_tensor)
tf.Tensor([2. 3. 4.], shape=(3,), dtype=float32)
二阶 Tensor 类似一个 Matrix , 有两个“轴”
# If you want to be specific, you can set the dtype (see below) at creation time
rank_2_tensor = tf.constant([[1, 2],
[3, 4],
[5, 6]], dtype=tf.float16)
print(rank_2_tensor)
tf.Tensor([2. 3. 4.], shape=(3,), dtype=float32)
高阶 Tensor, 这是个 3阶 Tensor , shape 是 [3, 2, 5]
# There can be an arbitrary number of
# axes (sometimes called "dimensions")
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]],])
print(rank_3_tensor)
注意:shape 的规则,最内部的数据个数, 在最后边。 比如上例, 它的shape 是 [3, 2, 5], 意思是最内部的数组(不再包含其他数组)所包含的元素是 5个, 次内部的数组,每个包含2个元素, 以此类推。
A 3-axis tensor, shape: [3, 2, 5]
image.png
Tensor 转化到 numpy
np.array(rank_2_tensor)
rank_2_tensor.numpy()
常见 Tensor 包含的数据格式
- int
- float
- complex (复数)
- string
Tensor 的形状
对于一般的 Tensor 来说 tf.Tensor
(之前我们讨论的) 要求内部数据形状必须是矩形 (所有轴上的数据长度相等), 但也有比较特殊的Tensor , 支持不规则数据形状。
数学运算
Tensor 支持常见的数学运算
a = tf.constant([[1, 2],
[3, 4]])
b = tf.constant([[1, 1],
[1, 1]]) # Could have also said `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") # element-wise addition
print(a * b, "\n") # element-wise multiplication
print(a @ b, "\n") # matrix multiplication
Shape
关于 Tensor 的词汇
- Shape: 各个坐标的长度
- Rank: 坐标的个数, 标量的 Rank 为0
- Axis or Dimension: A particular dimension of a tensor.
- Size: The total number of items in the tensor, the product shape vector.
关于这一段, 原文里面大部分说的很抽象, 没啥指导意义。 倒是这张图, 还有其中的一句话比较有意义。 右边的数值,更加local ,而且在内存上距离更近。 比如上面图所示, 右边的feature 就表示一个sample 的中的feature ,他们之间距离更近。
索引
TensorFlow index 规则:
- indexes 索引从0开始
- 负数代表从后向前
- :用于索引, 格式为: 开始:结束:步长
多数轴索引
print(rank_2_tensor.numpy())
--------------------------------------------
[[1. 2.]
[3. 4.]
[5. 6.]]
=================================
# Pull out a single value from a 2-rank tensor
print(rank_2_tensor[1, 1].numpy())
--------------------------------------------
4.0
=================================
# You can index using any combination of integers and slices:
# Get row and column tensors
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.]]
=================================
print(rank_3_tensor[:, :, 4])
--------------------------------------------
# Here is an example with a 3-axis tensor:
Shape 操作
转换成 Python list
把 [3,1] shape 转换成 Python list : as_list
x = tf.constant([[1], [2], [3]])
print(x.shape)
# You can convert this object into a Python list, too
print(x.shape.as_list())
Reshape
reshape 是转换Tensor shape 的最简单的方式
# You can reshape a tensor to a new shape.
# Note that you're passing in a list
reshaped = tf.reshape(x, [1, 3])
reshape 以后, Tensor 对象会更新, 新的Tensor 还指向相同的数据(The data maintains its layout in memory and a new tensor is created, with the requested shape, pointing to the same data. )
拍平一个Tensor
用: tf.reshape(some_tensor, [-1])
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)
===================================================
# A `-1` passed in the `shape` argument says "Whatever fits".
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)
reshape 正确打开方式
reshape 一般用于增加、减少一个维度。对于上面 3* 2 * 3 Tensor 的例子,减少维度的例子:
print(tf.reshape(rank_3_tensor, [3*2, 5]), "\n")
print(tf.reshape(rank_3_tensor, [3, -1]))
# 上面第二行等于 : print(tf.reshape(rank_3_tensor, [3,2 * 5]))
使用 Shape 的误区
1. 用reshape 来改变轴的顺序
如下, 改变轴的顺序应该用 tf.transpose
# Bad examples: don't do this
# You can't reorder axes with reshape.
print(tf.reshape(rank_3_tensor, [2, 3, 5]), "\n")
# This is a mess
print(tf.reshape(rank_3_tensor, [5, 6]), "\n")
2. 新旧Shape 包含元素总数对不上
# This doesn't work at all
try:
tf.reshape(rank_3_tensor, [7, -1])
except Exception as e:
print(f"{type(e).__name__}: {e}")
位置shape Tensor
有人称为是动态形状 Tensor
改变 Tensor Dtype
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)
# Now, cast to an uint8 and lose the decimal precision
the_u8_tensor = tf.cast(the_f16_tensor, dtype=tf.uint8)
print(the_u8_tensor)
------------------------------------------------------------------------------------------------------
tf.Tensor([2 3 4], shape=(3,), dtype=uint8)
广播
广播是从NumPy中的等效功能中借用的概念。简而言之,在某些情况下,在对它们进行组合操作时,较小的张量会自动“拉伸”以适合较大的张量。
最简单和最常见的情况是尝试将张量乘或加到标量时。在这种情况下,标量被广播为与其他自变量相同的形状。
x = tf.constant([1, 2, 3])
y = tf.constant(2)
z = tf.constant([2, 2, 2])
# All of these are the same computation
print(tf.multiply(x, 2))
print(x * y)
print(x * z)
------------------------------------------------------------------------------------------------------
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
tf.Tensor([2 4 6], shape=(3,), dtype=int32)
在大多数情况下,广播既节省时间又节省空间,因为广播操作永远不会实现内存中扩展的张量。
利用 broadcast_to 在Tensor 内部复制数据
print(tf.broadcast_to(tf.constant([1, 2, 3]), [3, 3]))
------------------------------------------------------------------------------------------------------
tf.Tensor(
[[1 2 3]
[1 2 3]
[1 2 3]], shape=(3, 3), dtype=int32)
注意, 这不和上面广播不一样, broadcast_to 产生的新 Tensor 并不会节约内存。
tf.convert_to_tensor
TF2 中很多函数都会要求参数是 Tensor ,如果参数不是 Tensor 则会调用 convert_to_tensor 来做转换。 有些类型, 比如 ndarray, TensorShape,Python list, tf.Variable 已经“注册”了, 他们可以自动转换成 Tensor。 对于自定义类型, 可以tf.register_tensor_conversion_function
来注册转换函数。
Ragged Tensors
沿某个轴具有可变数量元素的张量称为“Ragged Tensors”。使用 tf.ragged.RaggedTensor处理不整齐的数据。
例如
| A [`tf.RaggedTensor`](https://www.tensorflow.org/api_docs/python/tf/RaggedTensor), shape: `[4,<wbr style="box-sizing: inherit;"> None]` |
image.png
普通 Tensor 处理不了长短不一的情况
ragged_list = [
[0, 1, 2, 3],
[4, 5],
[6, 7, 8],
[9]]
try:
tensor = tf.constant(ragged_list)
except Exception as e:
print(f"{type(e).__name__}: {e}")
---------------------------------------------------------------------
ValueError: Can't convert non-rectangular Python sequence to Tensor.
ragged_tensor = tf.ragged.constant(ragged_list)
print(ragged_tensor)
---------------------------------------------------------------------
<tf.RaggedTensor [[0, 1, 2, 3], [4, 5], [6, 7, 8], [9]]>
print(ragged_tensor.shape)
---------------------------------------------------------------------
(4, None)
String tensors
tf.string是dtype,也就是说您可以将数据表示为张量中的字符串(可变长度字节数组)。
这些字符串是原子的,无法像Python字符串那样被索引。字符串的长度不是张量的轴之一。有关操作它们的功能,请参见tf.strings
。
# Tensors can be strings, too here is a scalar string.
scalar_string_tensor = tf.constant("Gray wolf")
print(scalar_string_tensor)
---------------------------------------------------------------------
tf.Tensor(b'Gray wolf', shape=(), dtype=string)
image.png
# If you have three string tensors of different lengths, this is OK.
tensor_of_strings = tf.constant(["Gray wolf",
"Quick brown fox",
"Lazy dog"])
# Note that the shape is (3,). The string length is not included.
print(tensor_of_strings)
---------------------------------------------------------------------
tf.Tensor([b'Gray wolf' b'Quick brown fox' b'Lazy dog'], shape=(3,), dtype=string)
在上面的打印输出中,b前缀表示tf.string dtype不是unicode字符串,而是字节字符串。有关在TensorFlow中处理Unicode文本的更多信息,请参见Unicode教程。
如果传递unicode字符,则它们是utf-8编码的。
tf.constant("🥳👍")
---------------------------------------------------------------------
<tf.Tensor: shape=(), dtype=string, numpy=b'\xf0\x9f\xa5\xb3\xf0\x9f\x91\x8d'>
可以在tf.strings中找到一些带有字符串的基本功能,包括tf.strings.split。
其他更多关于 String Tensor ,可以参考 string_tensors
Sparse tensors
Sparse tensors 用来存储稀疏矩阵类型的数据。
image.png# Sparse tensors store values by index in a memory-efficient manner
sparse_tensor = tf.sparse.SparseTensor(indices=[[0, 0], [1, 2]],
values=[1, 2],
dense_shape=[3, 4])
print(sparse_tensor, "\n")
# You can convert sparse tensors to dense
print(tf.sparse.to_dense(sparse_tensor))
---------------------------------------------------------------------
SparseTensor(indices=tf.Tensor(
[[0 0]
[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))
tf.Tensor(
[[1 0 0 0]
[0 0 2 0]
[0 0 0 0]], shape=(3, 4), dtype=int32)
网友评论