# 张量简介

``````import tensorflow as tf
import numpy as np
``````

## 基础知识

``````# 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)
```

“向量”（或称“1 秩”张量）就像一个值列表。向量有 1 个轴：

``````# 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)
```

“矩阵”（或称“2 秩”张量）有 2 个轴：

``````# If we want to be specific, we 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(
[[1. 2.]
[3. 4.]
[5. 6.]], shape=(3, 2), dtype=float16)
```

``````# 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)
``````
```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)
```

3 轴张量，形状：`[3, 2, 5]`

``````np.array(rank_2_tensor)
``````
```array([[1., 2.],
[3., 4.],
[5., 6.]], dtype=float16)
```
``````rank_2_tensor.numpy()
``````
```array([[1., 2.],
[3., 4.],
[5., 6.]], dtype=float16)
```

• 复杂的数值
• 字符串

`tf.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.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
``````
```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)
```

``````c = tf.constant([[4.0, 5.0], [10.0, 1.0]])

# Find the largest value
print(tf.reduce_max(c))
# Find the index of the largest value
print(tf.argmax(c))
# Compute the softmax
print(tf.nn.softmax(c))
``````
```tf.Tensor(10.0, shape=(), dtype=float32)
tf.Tensor([1 0], shape=(2,), dtype=int64)
tf.Tensor(
[[2.6894143e-01 7.3105854e-01]
[9.9987662e-01 1.2339458e-04]], shape=(2, 2), dtype=float32)
```

## 形状简介

• 形状：张量的每个轴的长度（元素数量）。
• ：张量轴数。标量的秩为 0，向量的秩为 1，矩阵的秩为 2。
• 维度：张量的一个特殊维度。
• 大小：张量的总项数，即乘积形状向量

``````rank_4_tensor = tf.zeros([3, 2, 4, 5])
``````
4 秩张量，形状：`[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("Elements along the last axis of tensor:", rank_4_tensor.shape[-1])
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
Elements along the last axis of tensor: 5
Total number of elements (3*2*4*5):  120
```

## 索引

### 单轴索引

TensorFlow 遵循标准 Python 索引规则（类似于在 Python 中为列表或字符串编制索引）以及 NumPy 索引的基本规则。

• 索引从 `0` 开始编制
• 负索引表示按倒序编制索引
• 冒号 `:` 用于切片 `start:stop:step`
``````rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
print(rank_1_tensor.numpy())
``````
```[ 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())
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]
```

### 多轴索引

``````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
```

``````# 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])
``````
```tf.Tensor(
[[ 4  9]
[14 19]
[24 29]], shape=(3, 2), dtype=int32)
```

## 操作形状

Reshaping a tensor is of great utility.

``````# Shape returns a `TensorShape` object that shows the size on each dimension
var_x = tf.Variable(tf.constant([[1], [2], [3]]))
print(var_x.shape)
``````
```(3, 1)
```
``````# You can convert this object into a Python list, too
print(var_x.shape.as_list())
``````
```[3, 1]
```

``````# We can reshape a tensor to a new shape.
# Note that we're passing in a list
reshaped = tf.reshape(var_x, [1, 3])
``````
``````print(var_x.shape)
print(reshaped.shape)
``````
```(3, 1)
(1, 3)
```

``````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)
```

``````print(tf.reshape(rank_3_tensor, [3*2, 5]), "\n")
print(tf.reshape(rank_3_tensor, [3, -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=(6, 5), dtype=int32)

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, 10), dtype=int32)
```

``````# 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")

# This doesn't work at all
try:
tf.reshape(rank_3_tensor, [7, -1])
except Exception as e:
print(f"{type(e).__name__}: {e}")
``````
```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=(2, 3, 5), dtype=int32)

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=(5, 6), dtype=int32)

InvalidArgumentError: Input to reshape is a tensor with 30 values, but the requested shape requires a multiple of 7 [Op:Reshape]
```

## `DTypes` 详解

``````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, let's 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)
```

## 广播

``````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)
```

``````# These are the same computations
x = tf.reshape(x,[3,1])
y = tf.range(1, 5)
print(x, "\n")
print(y, "\n")
print(tf.multiply(x, y))
``````
```tf.Tensor(
[[1]
[2]
[3]], shape=(3, 1), dtype=int32)

tf.Tensor([1 2 3 4], shape=(4,), dtype=int32)

tf.Tensor(
[[ 1  2  3  4]
[ 2  4  6  8]
[ 3  6  9 12]], shape=(3, 4), dtype=int32)
```

``````x_stretch = tf.constant([[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]])

y_stretch = tf.constant([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]])

``````
```tf.Tensor(
[[ 1  2  3  4]
[ 2  4  6  8]
[ 3  6  9 12]], shape=(3, 4), dtype=int32)
```

``````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)
```

## 不规则张量

“tf.RaggedTensor”，形状：`[4, None]`
``````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]]>
```

`tf.RaggedTensor` 的形状将包含一些具有未知长度的轴：

``````print(ragged_tensor.shape)
``````
```(4, None)
```

## 字符串张量

`tf.string` 是一种 `dtype`，也就是说，在张量中，您可以用字符串（可变长度字节数组）来表示数据。

``````# 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)
```

``````# If we 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)
```

``````tf.constant("🥳👍")
``````
```<tf.Tensor: shape=(), dtype=string, numpy=b'\xf0\x9f\xa5\xb3\xf0\x9f\x91\x8d'>
```

`tf.strings` 中可以找到用于操作字符串的一些基本函数，包括 `tf.strings.split`

``````# We can use split to split a string into a set of tensors
print(tf.strings.split(scalar_string_tensor, sep=" "))
``````
```tf.Tensor([b'Gray' b'wolf'], shape=(2,), dtype=string)
```
``````# ...but it turns into a `RaggedTensor` if we split up a tensor of strings,
# as each string might be split into a different number of parts.
print(tf.strings.split(tensor_of_strings))
``````
```<tf.RaggedTensor [[b'Gray', b'wolf'], [b'Quick', b'brown', b'fox'], [b'Lazy', b'dog']]>
```

``````text = tf.constant("1 10 100")
print(tf.strings.to_number(tf.strings.split(text, " ")))
``````
```tf.Tensor([  1.  10. 100.], shape=(3,), dtype=float32)
```

``````byte_strings = tf.strings.bytes_split(tf.constant("Duck"))
byte_ints = tf.io.decode_raw(tf.constant("Duck"), tf.uint8)
print("Byte strings:", byte_strings)
print("Bytes:", byte_ints)
``````
```Byte strings: tf.Tensor([b'D' b'u' b'c' b'k'], shape=(4,), dtype=string)
Bytes: tf.Tensor([ 68 117  99 107], shape=(4,), dtype=uint8)
```
``````# Or split it up as unicode and then decode it
unicode_bytes = tf.constant("アヒル 🦆")
unicode_char_bytes = tf.strings.unicode_split(unicode_bytes, "UTF-8")
unicode_values = tf.strings.unicode_decode(unicode_bytes, "UTF-8")

print("\nUnicode bytes:", unicode_bytes)
print("\nUnicode chars:", unicode_char_bytes)
print("\nUnicode values:", unicode_values)
``````
```Unicode bytes: tf.Tensor(b'\xe3\x82\xa2\xe3\x83\x92\xe3\x83\xab \xf0\x9f\xa6\x86', shape=(), dtype=string)

Unicode chars: tf.Tensor([b'\xe3\x82\xa2' b'\xe3\x83\x92' b'\xe3\x83\xab' b' ' b'\xf0\x9f\xa6\x86'], shape=(5,), dtype=string)

Unicode values: tf.Tensor([ 12450  12498  12523     32 129414], shape=(5,), dtype=int32)
```

`tf.string` dtype 可用于 TensorFlow 中的所有原始字节数据。`tf.io` 模块包含在数据与字节类型之间进行相互转换的函数，包括解码图像和解析 csv 的函数。

## 稀疏张量

“tf.SparseTensor”，形状：`[3, 4]`
``````# 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")

# We 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)
```
[]
[]