《TensorFlow 2.0深度学习算法实战教材》学习笔记(三、TensorFlow 基础)

本文深入解析TensorFlow中的数据类型,包括标量、向量、矩阵及张量的基本概念,探讨了数值、字符串和布尔类型张量的创建方法,以及张量的常见操作如索引、切片和维度变换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

数据类型

TensorFlow 中的基本数据类型,它包含了数值型、字符串型和布尔型。

数值类型

数值类型的张量是TensorFlow 的主要数据载体,分为:

  • 标量(Scalar) 单个的实数,如1.2, 3.4 等,维度数(Dimension,也叫秩)为0,shape 为[]
  • 向量(Vector) n 个实数的有序集合,通过中括号包裹,如[1.2],[1.2, 3.4]等,维度数为1,长度不定,shape 为[𝑛]
  • 矩阵(Matrix) n 行m 列实数的有序集合,维度数为2,每个维度上的长度不定,shape 为[𝑛, 𝑚]
  • 张量(Tensor) 所有维度数dim > 2的数组统称为张量。张量的每个维度也做轴(Axis),一般维度代表了具体的物理含义

在 TensorFlow 中间,为了表达方便,一般把标量、向量、矩阵也统称为张量,不作区分,需要根据张量的维度数和形状自行判断。首先来看标量在TensorFlow 是如何创建的:

a = tf.constant(1.2) # 创建标量
a = tf.constant([1.2]) # 创建向量
a = tf.constant([[1,2],[3,4]]) # 创建矩阵
a = tf.constant([[[1,2],[3,4]],[[5,6],[7,8]]])  # 创建三维张量

字符串类型

通过传入字符串对象即可创建字符串类型的张量

a = tf.constant('Hello, Deep Learning.')

布尔类型

TensorFlow 还支持布尔类型(Boolean, bool)的张量。布尔类型的张量只需要传入Python 语言的布尔类型数据,转换成TensorFlow 内部布尔型即可:

a = tf.constant(True)
a = tf.constant([True, False])

数值精度

常用的精度类型有tf.int16, tf.int32, tf.int64,tf.float16,tf.float32,tf.float64,其中tf.float64 即为tf.double

tf.constant(123456789, dtype=tf.int16)
tf.constant(123456789, dtype=tf.int32)

读取精度

通过访问张量的dtype 成员属性可以判断张量的保存精度:

print('before:',a.dtype)

类型转换

通过tf.cast 函数进行转换

a = tf.constant(np.pi, dtype=tf.float16)
tf.cast(a, tf.double)

进行类型转换时,需要保证转换操作的合法性,例如将高精度的张量转换为低精度的张量时,可能发生数据溢出隐患

待优化张量

为了区分需要计算梯度信息的张量与不需要计算梯度信息的张量,TensorFlow 增加了一种专门的数据类型来支持梯度信息的记录:tf.Variable。tf.Variable 类型在普通的张量类型基础上添加了name,trainable 等属性来支持计算图的构建。由于梯度运算会消耗大量的计算资源,而且会自动更新相关参数,对于不需要的优化的张量,如神经网络的输入X,不需要通过tf.Variable 封装;相反,对于需要计算梯度并优化的张量,如神经网络层的W和𝒃,需要通过tf.Variable 包裹以便TensorFlow 跟踪相关梯度信息。

通过 tf.Variable()函数可以将普通张量转换为待优化张量:

a = tf.constant([-1, 0, 1, 2])
aa = tf.Variable(a)
aa.name, aa.trainable
Out[20]:
('Variable:0', True)

其中张量的name 和trainable 属性是Variable 特有的属性,name属性用于命名计算图中的变量,这套命名体系是TensorFlow内部维护的,一般不需要用户关注name 属性;trainable
表征当前张量是否需要被优化,创建Variable 对象是默认启用优化标志,可以设置trainable=False 来设置张量不需要优化。

除了通过普通张量方式创建Variable,也可以直接创建:

a = tf.Variable([[1,2],[3,4]])

创建张量

从 Numpy, List 对象创建

Numpy Array 数组和Python List 是Python 程序中间非常重要的数据载体容器,很多数据都是通过Python 语言将数据加载至Array 或者List 容器,再转换到Tensor 类型,通过TensorFlow 运算处理后导出到Array 或者List 容器,方便其他模块调用。

通过 tf.convert_to_tensor 可以创建新Tensor,并将保存在Python List 对象或者Numpy Array 对象中的数据导入到新Tensor 中:

tf.convert_to_tensor(np.array([[1,2.],[3,4]]))

Numpy 中浮点数数组默认使用64-Bit 精度保存数据,转换到Tensor 类型时精度为tf.float64,可以在需要的时候转换为tf.float32 类型。

实际上,tf.constant()和tf.convert_to_tensor()都能够自动的把Numpy 数组或者PythonList 数据类型转化为Tensor 类型.

创建全0,全1 张量

将张量创建为全0 或者全1 数据是非常常见的张量初始化手段。
通过tf.zeros()和tf.ones()即可创建任意形状全0 或全1 的张量。

创建为0 和为1 的标量张量:

tf.zeros([]),tf.ones([])

创建全0 和全1 的向量:

tf.zeros([1]),tf.ones([1])

创建全0 的矩阵:

tf.zeros([2,2])

创建全1 的矩阵:

tf.ones([2,2])

通过tf.zeros_like, tf.ones_like 可以方便地新建与某个张量shape 一致,内容全0 或全1的张量。

a = tf.ones([2,3])
tf.zeros_like(a)
tf.ones_like(a)

创建自定义数值张量

通过 tf.fill(shape, value)可以创建全为自定义数值value 的张量。

创建元素为-1的标量:

tf.fill([], -1)

创建所有元素为99 的矩阵:

tf.fill([2,2], 99)

创建已知分布的张量

正态分布(Normal Distribution,或Gaussian Distribution)和均匀分布(UniformDistribution)是最常见的分布之一,创建采样自这2 种分布的张量非常有用,比如在卷积神经网络中,卷积核张量W 初始化为正态分布有利于网络的训练;在对抗生成网络中,隐藏变量z 一般采样自均匀分布。

通过 tf.random.normal(shape, mean=0.0, stddev=1.0)可以创建形状为shape,均值为mean,标准差为stddev 的正态分布𝒩(𝑚𝑒𝑎𝑛, 𝑠𝑡𝑑𝑑𝑒𝑣2)。例如,创建均值为0,标准差为1的正太分布:

tf.random.normal([2,2])

创建均值为1,标准差为2 的正太分布:

In [34]: tf.random.normal([2,2], mean=1,stddev=2)

通过tf.random.uniform(shape, minval=0, maxval=None, dtype=tf.float32)可以创建采样自[𝑚𝑖𝑛𝑣𝑎𝑙, 𝑚𝑎𝑥𝑣𝑎𝑙]区间的均匀分布的张量。例如创建采样自区间[0,10],shape 为[2,2]的矩阵:

In [36]: tf.random.uniform([2,2],maxval=10)
Out[36]:
<tf.Tensor: id=166, shape=(2, 2), dtype=float32, numpy=
array([[4.541913 , 0.26521802],
[2.578913 , 5.126876 ]], dtype=float32)>

创建序列

在循环计算或者对张量进行索引时,经常需要创建一段连续的整形序列,可以通过tf.range()函数实现。tf.range(limit, delta=1)可以创建[0, 𝑙𝑖𝑚𝑖𝑡)之间,步长为delta 的整形序列,不包含limit 本身。

通过tf.range(start, limit, delta=1)可以创建[𝑠𝑡𝑎𝑟𝑡, 𝑙𝑖𝑚𝑖𝑡),步长为delta 的序列,不包含limit本身:

In [40]: tf.range(1,10,delta=2)
Out[40]:
<tf.Tensor: id=190, shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9])>

张量的典型应用

标量

在 TensorFlow 中,标量最容易理解,它就是一个简单的数字,维度数为0,shape 为[]。标量的典型用途之一是误差值的表示、各种测量指标的表示,比如准确度(Accuracy,acc),精度(Precision)和召回率(Recall)等。

向量

向量是一种非常常见的数据载体,如在全连接层和卷积神经网络层中,偏置张量𝒃就使用向量来表示。

矩阵

矩阵也是非常常见的张量类型,比如全连接层的批量输入𝑋 = [𝑏, 𝑑𝑖𝑛 ],其中𝑏表示输入样本的个数,即batch size,𝑑𝑖𝑛表示输入特征的长度。

三维张量

三维的张量一个典型应用是表示序列信号,它的格式是

𝑋 = [𝑏, 𝑠𝑒𝑞𝑢𝑒𝑛𝑐𝑒 𝑙𝑒𝑛, 𝑓𝑒𝑎𝑡𝑢𝑟𝑒 𝑙𝑒𝑛]

其中𝑏表示序列信号的数量,sequence len 表示序列信号在时间维度上的采样点数,feature len 表示每个点的特征长度。

4 维张量

我们这里只讨论3/4 维张量,大于4 维的张量一般应用的比较少,如在元学习(metalearning)中会采用5 维的张量表示方法,理解方法与3/4 维张量类似。

4 维张量在卷积神经网络中应用的非常广泛,它用于保存特征图(Feature maps)数据,格式一般定义为

[𝑏, ℎ, , 𝑐]

其中𝑏表示输入的数量,h/w分布表示特征图的高宽,𝑐表示特征图的通道数,

索引

在 TensorFlow 中,支持基本的[𝑖][𝑗] …标准索引方式,也支持通过逗号分隔索引号的索引方式。

x = tf.random.normal([4,32,32,3])
In [51]: x[0]

切片

通过𝑠𝑡𝑎𝑟𝑡: 𝑒𝑛𝑑: 𝑠𝑡𝑒𝑝切片方式可以方便地提取一段数据,其中start 为开始读取位置的索引,end 为结束读取位置的索引(不包含end 位),step 为读取步长。

以 shape 为[4,32,32,3]的图片张量为例,读取第 2,3 张图片:

In [56]: x[1:3]

start: end: step切片方式有很多简写方式,其中start、end、step 3 个参数可以根据需要选择性地省略,全部省略时即::,表示从最开始读取到最末尾,步长为1,即不跳过任何元素。

在这里插入图片描述
特别地,step 可以为负数,考虑最特殊的一种例子,step = −1时,start: end: −1表示从start 开始,逆序读取至end 结束(不包含end),索引号𝑒𝑛𝑑 ≤ 𝑠𝑡𝑎𝑟𝑡.

在这里插入图片描述

维度变换

Reshape

改变张量的视图仅仅是改变了张量的理解方式,并不会改变张量的存储顺序.

为了能够正确恢复出数据,必须保证张量的存储顺序与新视图的维度顺序一致.

在 TensorFlow 中,可以通过张量的ndim 和shape 成员属性获得张量的维度数和形状:

In [68]: x.ndim,x.shape
Out[68]:(4, TensorShape([2, 4, 4, 3]))

通过tf.reshape(x, new_shape),可以将张量的视图任意的合法改变:

In [69]: tf.reshape(x,[2,-1])
Out[69]:<tf.Tensor: id=520, shape=(2, 48), 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, 30, 31,…
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95]])>

其中的参数-1 表示当前轴上长度需要根据视图总元素不变的法则自动推导,从而方便用户书写.

增删维度

增加维度 增加一个长度为1 的维度相当于给原有的数据增加一个新维度的概念,维度长度为1,故数据并不需要改变,仅仅是改变数据的理解方式,因此它其实可以理解为改变视图的一种特殊方式。

通过tf.expand_dims(x, axis)可在指定的axis 轴前可以插入一个新的维度.tf.expand_dims 的axis 为正时,表示在当前维度之前插入一个新维度;为负时,表示当前维度之后插入一个新的维度。以[𝑏, ℎ, , 𝑐]张量为例,不同axis 参数的实际插入位置如下图 4.6 所示:
在这里插入图片描述
删除维度 是增加维度的逆操作,与增加维度一样,删除维度只能删除长度为1 的维度,也不会改变张量的存储。继续考虑增加维度后shape 为[1,28,28,1]的例子,如果希望将图片数量维度删除,可以通过tf.squeeze(x, axis)函数,axis 参数为待删除的维度的索引号,图片数量的维度轴axis=0:

In [75]: x = tf.squeeze(x, axis=0)
Out[75]:
<tf.Tensor: id=586, shape=(28, 28, 1), dtype=int32, numpy=
array([[[8],
[2],
[2],
[0],…

如果不指定维度参数axis,即tf.squeeze(x),那么他会默认删除所有长度为1 的维度.

交换维度

改变视图、增删维度都不会影响张量的存储。在实现算法逻辑时,在保持维度顺序不变的条件下,仅仅改变张量的理解方式是不够的,有时需要直接调整的存储顺序,即交换维度(Transpose)。通过交换维度,改变了张量的存储顺序,同时也改变了张量的视图。

交换维度操作是非常常见的,比如在TensorFlow 中,图片张量的默认存储格式是通道后行格式:[𝑏, ℎ, , 𝑐],但是部分库的图片格式是通道先行:[𝑏, 𝑐, ℎ, ],因此需要完成[𝑏, ℎ, , 𝑐]到[𝑏, 𝑐, ℎ, ]维度交换运算。我们以[𝑏, ℎ, , 𝑐]转换到[𝑏, 𝑐, ℎ, ]为例,介绍如何使用tf.transpose(x, perm)函数完成维度交换操作,其中perm 表示新维度的顺序List。考虑图片张量shape 为[2,32,32,3],图片数量、行、列、通道数的维度索引分别为0,1,2,3,如果需要交换为[𝑏, 𝑐, ℎ, ]格式,则新维度的排序为图片数量、通道数、行、列,对应的索引号为[0,3,1,2],实现如下:

In [78]: x = tf.random.normal([2,32,32,3])
tf.transpose(x,perm=[0,3,1,2])

如果希望将[𝑏, ℎ, , 𝑐]交换为[𝑏, , ℎ, 𝑐],即将行列维度互换,则新维度索引为[0,2,1,3]:

x = tf.random.normal([2,32,32,3])
tf.transpose(x,perm=[0,2,1,3])

通过tf.transpose 完成维度交换后,张量的存储顺序已经改变,视图也随之
改变,后续的所有操作必须基于新的存续顺序进行。

数据复制

可以通过tf.tile(x, multiples)函数完成数据在指定维度上的复制操作,multiples 分别指定了每个维度上面的复制倍数,对应位置为1 表明不复制,为2 表明新长度为原来的长度的2 倍,即数据复制一份,以此类推。

b = tf.constant([1,2])
b = tf.expand_dims(b, axis=0)
b = tf.tile(b, multiples=[2,1])

Broadcasting

Broadcasting 也叫广播机制(自动扩展也许更合适),它是一种轻量级张量复制的手段,在逻辑上扩展张量数据的形状,但是只要在需要时才会执行实际存储复制操作。对于大部分场景,Broadcasting 机制都能通过优化手段避免实际复制数据而完成逻辑运算,从而相对于tf.tile 函数,减少了大量计算代价。

Broadcasting 机制的核心思想是普适性,即同一份数据能普遍适合于其他位置。

通过 tf.broadcast_to(x, new_shape)可以显式将现有shape 扩张为new_shape:

In [87]:
A = tf.random.normal([32,1])
tf.broadcast_to(A, [2,32,32,3])
Out[87]:
<tf.Tensor: id=13, shape=(2, 32, 32, 3), dtype=float32, numpy=
array([[[[-1.7571245 , -1.7571245 , -1.7571245 ],
[ 1.580159 , 1.580159 , 1.580159 ],
[-1.5324328 , -1.5324328 , -1.5324328 ],...

数学运算

加减乘除

加减乘除是最基本的数学运算,分别通过tf.add, tf.subtract, tf.multiply, tf.divide 函数实现,TensorFlow 已经重载了+ −∗/运算符,一般推荐直接使用运算符来完成加减乘除运算。

整除和余除也是常见的运算之一,分别通过//和%运算符实现。

乘方

通过 tf.pow(x, a)可以方便地完成𝑦 = 𝑥𝑎乘方运算,也可以通过运算符**实现𝑥 ∗∗ 𝑎运
算.

对于常见的平方和平方根运算,可以使用tf.square(x)和tf.sqrt(x)实现。

指数、对数

通过 tf.pow(a, x)或者**运算符可以方便实现指数运算𝑎𝑥.
在 TensorFlow 中,自然对数l g𝑒 𝑥可以通过tf.math.log(x)实现

矩阵相乘

神经网络中间包含了大量的矩阵相乘运算,前面我们已经介绍了通过@运算符可以方
便的实现矩阵相乘,还可以通过tf.matmul(a, b)实现。需要注意的是,TensorFlow 中的矩阵相乘可以使用批量方式,也就是张量a,b 的维度数可以大于2。当张量a,b 维度数大于2时,TensorFlow 会选择a,b 的最后两个维度进行矩阵相乘,前面所有的维度都视作Batch 维度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汀桦坞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值