把张量变成int_tensorflow 之 张量与变量

TensorFlow 与 MXNet、PyTorch 很相似,上手速度很快(相比于 TensorFlow1.x)。

TensorFlow 拆开来看,就是 Tensor 与 Flow,即数据流程图,也是有向无环图(DAG)。在 TensorFlow 中以 Tensor(张量)表示数据,即 DAG 的(实线)边,而虚线的边用来表示流程的控制关系。DAG 的节点表示数学操作符(即数学运算)。

1 张量 tf.Tensor

张量是由 tf.Tensor 对象表示的具有统一类型(称为 dtype)的多维数组。您可以在 tf.dtypes.DType 中查看所有支持的 dtypes。就像 Python 数值和字符串一样,所有张量都是不可变的:永远无法更新张量的内容,只能创建新的张量。

编写 TensorFlow 程序时,主要操纵和传递的对象是 tf.Tensor。tf.Tensor 具有以下属性:

单一数据类型 (比如,float32,int32或字符串)

a shape

TensorFlow 支持 eager 执行和 graph 执行。eager 执行时,将立即执行运算。在 graph 中执行时,构造一个计算图为以后运算。TensorFlow 默认 eager 执行。在以下示例中,立即计算矩阵乘法结果。其中 tf.constant 是张量的一种。

# 使用 Tensor 计算一些值

c = tf.constant([[1.0, 2.0], [3.0, 4.0]]) # 常量

d = tf.constant([[1.0, 1.0], [0.0, 1.0]])

e = tf.matmul(c, d) # 矩阵乘法

print(e)

输出:

tf.Tensor(

[[1. 3.]

[3. 7.]], shape=(2, 2), dtype=float32)

请注意,在 eager 执行过程中,您可能会发现您的 Tensors 实际上是类型为“EagerTensor”。这是内部细节,但确实可以给您访问有用的函数 numpy():

在 TensorFlow 中,tf.function 是定义 graph 执行的常用方法。张量的 shape(即张量的 rank 和每个维度的大小)可能并不总是完全已知的。在 tf.function 定义中,shape 可能仅是部分已知的。

如果也可以完全知道其输入的形状,则大多数操作都会生成形状已知的张量,但是在某些情况下,只有在执行时才能找到张量的形状。

有许多专用的张量:参见 tf.constant, tf.sparse.SparseTensor, 和 tf.RaggedTensor。

1.1 常量 tf.constant

def constant(value, dtype=None, shape=None, name="Const"):

从 tensor-like 的对象创建恒定张量,即常量。

注意:所有 eager 的 tf.Tensor 值都是不可变的(与 tf.Variable 相反)。从 tf.constant 返回的值没有特别常数。此功能与 tf.convert_to_tensor 基本上没有区别。名称 tf.constant 来自符号API(例如 tf.data或 tf.keras functional models),其中 value 嵌入在 tf.Graph 的 Const 节点中。tf.constant 可用于断言该值可以通过这种方式嵌入。

我们来创建一些基本张量。

下面是一个“标量”(或称“0 秩”张量)。标量包含单个值,但没有“轴”。

rank_0_tensor = tf.constant(4)

print(rank_0_tensor)

输出:

tf.Tensor(4, shape=(), dtype=int32)

“向量”(或称“1 秩”张量)就像一个值的列表。向量有 1 个轴:

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 个轴:

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)

张量的轴可能更多,下面是一个包含 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]],])

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)

对于包含 2 个以上的轴的张量,您可以通过多种方式将其可视化。

通过使用 np.array 或 tensor.numpy 方法,您可以将张量转换为 NumPy 数组:

张量通常包含浮点型和整型数据,但是还有许多其他数据类型,包括:

复杂的数值

字符串

tf.Tensor 基类要求张量是“矩形”——也就是说,每个轴上的每一个元素大小相同。但是,张量有可以处理不同形状的特殊类型。

上面并没有指定参数 dtype,而从 value 的类型中自动推断出类型。

>>> # Constant 1-D Tensor from a python list.

>>> tf.constant([1, 2, 3, 4, 5, 6])

numpy=array([1, 2, 3, 4, 5, 6], dtype=int32)>

>>> # Or a numpy array

>>> a = np.array([[1, 2, 3], [4, 5, 6]])

>>> tf.constant(a)

array([[1, 2, 3],

[4, 5, 6]])>

如果指定了 dtype,则将结果张量值强制转换为请求的 dtype。

>>> tf.constant([1, 2, 3, 4, 5, 6], dtype=tf.float64)

numpy=array([1., 2., 3., 4., 5., 6.])>

如果设置了 shape,则将 value 调整为匹配的形状。标量被扩展以填充 shape:

>>> tf.constant(0, shape=(2, 3))

array([[0, 0, 0],

[0, 0, 0]], dtype=int32)>

>>> tf.constant([1, 2, 3, 4, 5, 6], shape=[2, 3])

array([[1, 2, 3],

[4, 5, 6]], dtype=int32)>

如果将 eager 张量作为 value 传递,tf.constant 无效,它甚至会传输梯度:

v = tf.Variable([0.0])

with tf.GradientTape() as g:

loss = tf.constant(v + v)

g.gradient(loss, v).numpy()

输出:

array([2.], dtype=float32)

但是,由于 tf.constant 将值嵌入到 tf.Graph 中,因此对于符号张量(symbolic tensors)而言失败:

Related Ops:

tf.convert_to_tensor 与 tf.constant 类似,而不同于:

无 shape 参数

Symbolic tensors 被允许传递

>>> i = tf.keras.layers.Input(shape=[None, None])

>>> t = tf.convert_to_tensor(i)

1.2 张量的简单运算

我们可以对张量执行基本数学运算,包括加法、逐元素乘法和矩阵乘法运算。

a = tf.constant([[1, 2],

[3, 4]])

b = tf.constant([[1, 1],

[1, 1]]) # Could have also said `tf.ones([2,2])`

tf.print(tf.add(a, b), "\n") # 矩阵加法

tf.print(tf.multiply(a, b), "\n") # 逐元素乘法

tf.print(tf.matmul(a, b), "\n") # 矩阵乘法

输出:

[[2 3]

[4 5]]

[[1 2]

[3 4]]

[[3 3]

[7 7]]

其中,tf.print 用于打印信息。

TensorFlow 也重载了运算符:

tf.print(a + b, "\n") # element-wise addition

tf.print(a * b, "\n") # element-wise multiplication

tf.print(a @ b, "\n") # matrix multiplication```

输出:

[[2 3]

[4 5]]

[[1 2]

[3 4]]

[[3 3]

[7 7]]

张量支持其他各种运算 (op) 。

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

# Find the largest value

tf.print(tf.reduce_max(c), '\n')

# Find the index of the largest value

tf.print(tf.argmax(c), '\n')

# Compute the softmax

tf.print(tf.nn.softmax(c), '\n')

输出:

10

[1 0]

[[0.268941432 0.731058598]

[0.999876618 0.00012339458]]

1.3 形状简介

张量有形状。下面是几个相关术语:

形状:张量的每个维度的长度(元素数量)。

秩:张量的维度数量。标量的秩为 0,向量的秩为 1,矩阵的秩为 2。

轴或维度:张量的一个特殊维度。

大小:张量的总项数,即乘积形状向量

注:虽然您可能会看到“二维张量”之类的表述,但 2 秩张量通常并不是用来描述二维空间。

张量和 tf.TensorShape 对象提供了方便的属性来访问:

虽然通常用索引来指代轴,但是您始终要记住每个轴的含义。轴一般按照从全局到局部的顺序进行排序:首先是批次轴,随后是空间维度,最后是每个位置的特征。这样,在内存中,特征向量就会位于连续的区域。

tf.size(x).numpy() 与 len(x) 等效。

1.4 操作形状

通过重构可以改变张量的形状。重构的速度很快,资源消耗很低,因为不需要复制底层数据。

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

reshaped = tf.reshape(x, [1, 3])

print(x.shape)

print(reshaped.shape)

输出:

(3, 1)

(1, 3)

数据在内存中的布局保持不变,同时使用请求的形状创建一个指向同一数据的新张量。TensorFlow 采用 C 样式的“行优先”内存访问顺序,即最右侧的索引值递增对应于内存中的单步位移。

如果您展平张量,则可以看到它在内存中的排列顺序。

一般来说,tf.reshape 唯一合理的用途是用于合并或拆分相邻轴(或添加/移除 1)。

对于 3x2x5 张量,重构为 (3x2)x5 或 3x(2x5) 都合理,因为切片不会混淆:

重构可以处理总元素个数相同的任何新形状,但是如果不遵从轴的顺序,则不会发挥任何作用。

利用 tf.reshape 无法实现轴的交换,要交换轴,您需要使用 tf.transpose。

您可能会遇到非完全指定的形状。要么是形状包含 None 维度(维度的长度未知),要么是形状为 None(张量的秩未知)。

除了 tf.RaggedTensor 外,这种情况只会在 TensorFlow 的符号化计算图构建 API 环境中出现:

1.5 DTypes 详解

从 Python 对象创建 tf.Tensor 时,您可以选择指定数据类型。

如果不指定,TensorFlow 会选择一个可以表示您的数据的数据类型。TensorFlow 将 Python 整数转换为 tf.int32,将 Python 浮点数转换为 tf.float32。另外,当转换为数组时,TensorFlow 会采用与 NumPy 相同的规则。

数据类型可以相互转换。

1.6 广播

广播是从 NumPy 中的等效功能借用的一个概念。简而言之,在一定条件下,对一组张量执行组合运算时,为了适应大张量,会对小张量进行“扩展”。

最简单和最常见的例子是尝试将张量与标量相乘或相加。在这种情况下会对标量进行广播,使其变成与其他参数相同的形状。

同样,可以扩展大小为 1 的维度,使其符合其他参数。在同一个计算中可以同时扩展两个参数。

在本例中,一个 3x1 的矩阵与一个 1x4 进行元素级乘法运算,从而产生一个 3x4 的矩阵。注意前导 1 是可选的:y 的形状是 [4]。

下面是不使用广播的同一运算:

在大多数情况下,广播的时间和空间效率更高,因为广播运算不会在内存中具体化扩展的张量。

与数学运算不同,比方说,broadcast_to 并不会节省内存。在这个例子中,张量已经具体化。

这可能会变得更复杂。Jake VanderPlas 的《Python 数据科学手册》一书中的这一节介绍了更多广播技巧(同样使用 NumPy)。

1.7 tf.convert_to_tensor

大部分运算(如 tf.matmul 和 tf.reshape)会使用 tf.Tensor 类的参数。不过,在上面的示例中,您会发现我们经常传递形状类似于张量的 Python 对象。

大部分(但并非全部)运算会在非张量参数上调用 convert_to_tensor。我们提供了一个转换注册表,大多数对象类(如 NumPy 的 ndarray、TensorShape、Python 列表和 tf.Variable)都可以自动转换。

1.8 不规则张量

如果张量的某个轴上的元素个数可变,则称为“不规则”张量。对于不规则数据,请使用 tf.ragged.RaggedTensor。

例如,下面的例子无法用规则张量表示:

1.9 字符串张量

tf.string 是一种 dtype,也就是说,在张量中,我们可以用字符串(可变长度字节数组)来表示数据。

字符串是原子类型,无法像 Python 字符串一样编制索引。字符串的长度并不是张量的一个维度。有关操作字符串的函数,请参阅 tf.strings。

下面是一个标量字符串张量:

下面是一个字符串向量:

在上面的打印输出中,b 前缀表示 tf.string dtype 不是 Unicode 字符串,而是字节字符串。有关在 TensorFlow 如何使用 Unicode 文本的详细信息,请参阅 Unicode 教程。

如果传递 Unicode 字符,则会使用 utf-8 编码。

以及 tf.string.to_number:

虽然不能使用 tf.cast 将字符串张量转换为数值,但是可以先将其转换为字节,然后转换为数值。

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

1.10 稀疏张量

在某些情况下,数据很稀疏,比如说在一个非常宽的嵌入空间中。为了高效存储稀疏数据,TensorFlow 支持 tf.sparse.SparseTensor 和相关运算。

2 变量

TensorFlow 变量是用于表示程序处理的共享持久状态的推荐方法。本指南介绍在 TensorFlow 中如何创建、更新和管理 tf.Variable 的实例。

变量通过 tf.Variable 类进行创建和跟踪。tf.Variable 表示张量,对它执行运算可以改变其值。利用特定运算可以读取和修改此张量的值。更高级的库(如 tf.keras)使用 tf.Variable 来存储模型参数。

2.1 设置

本笔记本讨论变量布局。如果要查看变量位于哪一个设备上,请取消注释这一行代码。

import tensorflow as tf

# Uncomment to see where your variables get placed (see below)

# tf.debugging.set_log_device_placement(True)

2.2 创建变量

要创建变量,请提供一个初始值。tf.Variable 与初始值的 dtype 相同。

my_tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]])

my_variable = tf.Variable(my_tensor)

# Variables can be all kinds of types, just like tensors

bool_variable = tf.Variable([False, False, False, True])

complex_variable = tf.Variable([5 + 4j, 6 + 1j])

变量与张量的定义方式和操作行为都十分相似,实际上,它们都是 tf.Tensor 支持的一种数据结构。与张量类似,变量也有 dtype 和形状,并且可以导出至 NumPy。

大部分张量运算在变量上也可以按预期运行,不过变量无法重构形状。

如上所述,变量由张量提供支持。您可以使用 tf.Variable.assign 重新分配张量。调用 assign(通常)不会分配新张量,而会重用现有张量的内存。

如果在运算中像使用张量一样使用变量,那么通常会对支持张量执行运算。

从现有变量创建新变量会复制支持张量。两个变量不能共享同一内存空间。

2.3 生命周期、命名和监视

在基于 Python 的 TensorFlow 中,tf.Variable 实例与其他 Python 对象的生命周期相同。如果没有对变量的引用,则会自动将其解除分配。

为了便于跟踪和调试,您还可以为变量命名。两个变量可以使用相同的名称。

保存和加载模型时会保留变量名。默认情况下,模型中的变量会自动获得唯一变量名,所以除非您希望自行命名,否则不必多此一举。

虽然变量对微分很重要,但某些变量不需要进行微分。在创建时,通过将 trainable 设置为 False 可以关闭梯度。例如,训练计步器就是一个不需要梯度的变量。

step_counter = tf.Variable(1, trainable=False)

2.4 放置变量和张量

为了提高性能,TensorFlow 会尝试将张量和变量放在与其 dtype 兼容的最快设备上。这意味着如果有 GPU,那么大部分变量都会放置在 GPU 上。

不过,我们可以重写变量的位置。在以下代码段中,即使存在可用的 GPU,我们也可以将一个浮点张量和一个变量放置在 CPU 上。通过打开设备分配日志记录(参阅设置),可以查看变量的所在位置。

注:虽然可以手动放置变量,但使用分布策略是一种可优化计算的更便捷且可扩展的方式。

如果在有 GPU 和没有 GPU 的不同后端上运行此笔记本,则会看到不同的记录。请注意,必须在会话开始时打开设备布局记录。

您可以将变量或张量的位置设置在一个设备上,然后在另一个设备上执行计算。但这样会产生延迟,因为需要在两个设备之间复制数据。

不过,如果您有多个 GPU 工作进程,但希望变量只有一个副本,则可以这样做。

注:由于 tf.config.set_soft_device_placement 默认处于打开状态,所以,即使在没有 GPU 的设备上运行此代码,它也会运行,只不过乘法步骤在 CPU 上执行。

有关分布式训练的详细信息,请参阅指南。要了解变量的一般使用方法,请参阅关于自动微分的指南。

你可能感兴趣的:(把张量变成int)