⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计3077字,阅读大概需要3分钟
🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号:不懂开发的程序猿
个人网站:https://jerry-jy.co/
TensorFlow进阶二(高阶操作)
- TensorFlow进阶二
- 一、任务需求
- 二、任务目标
- 1、掌握张量的填充与复制
- 2、掌握张量的数据限幅
- 3、掌握张量的高阶操作
- 三、任务环境
- 1、jupyter开发环境
- 2、python3.6
- 3、tensorflow2.4
- 四、任务实施过程
- (四)、高阶操作
- 五、任务小结
TensorFlow进阶二
一、任务需求
对于图片数据的高和宽、序列信号的长度,维度长度可能各不相同。为了方便网络的并行计算,需要将不同长度的数据扩张为相同长度,之前我们介绍了通过复制的方式可以增加数据的长度,但是重复复制数据会破坏原有的数据结构,并不适合于此处。通常的做法是,在需要补充长度的数据开始或结束处填充足够数量的特定数值,这些特定数值一般代表了无效意义,例如 0,使得填充后的长度满足系统要求。那么这种操作就叫作填充(Padding)。本节将要完成张量的填充与复制,数据限幅以及tf.gather、tf.gather_nd、tf.boolean_mark、tf.where、scatter_nd、meshgrid等函数的操作。
二、任务目标
1、掌握张量的填充与复制
2、掌握张量的数据限幅
3、掌握张量的高阶操作
三、任务环境
1、jupyter开发环境
2、python3.6
3、tensorflow2.4
四、任务实施过程
(四)、高阶操作
17、通过 tf.gather_nd 函数,可以通过指定每次采样点的多维坐标来实现采样多个点的目的。回到上面的挑战,我们希望抽查第 2 个班级的第 2 个同学的所有科目,第 3 个班级的第 3 个同学的所有科目,第 4 个班级的第 4 个同学的所有科目。那么这 3 个采样点的索引坐标可以记为:[1,1]、[2,2]、[3,3],我们将这个采样方案合并为一个 List 参数,即
[[1,1],[2,2],[3,3]],通过 tf.gather_nd 函数即可
tf.gather_nd(x,[[1,1],[2,2],[3,3]])
可以看到,结果与串行采样方式的完全一致,实现更加简洁,计算效率大大提升
18、使用 tf.gather_nd 采样多个样本时,例如希望采样𝑖号班级,𝑗个学生,𝑘门科目的成绩,则可以表达为[. . . ,[𝑖,𝑗, 𝑘], . . .],外层的括号长度为采样样本的个数,内层列表包含了每个采样点的索引坐标,如要抽取班级1的学生1的科目、 班级2的学生2的科目、 班级3的学生3的科目的成绩
tf.gather_nd(x,[[1,1,2],[2,2,3],[3,3,4]])
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([73, 4, 99], dtype=int32)>
19、除了可以通过给定索引号的方式采样,还可以通过给定掩码(Mask)的方式进行采样。继续以 shape 为[4,35,8]的成绩册张量为例,这次我们以掩码方式进行数据提取。
考虑在班级维度上进行采样,对这 4 个班级的采样方案的掩码为mask = [True, False, False, True]即采样第 1 和第 4 个班级的数据,通过 tf.boolean_mask(x, mask, axis)可以在 axis 轴上根据
mask 方案进行采样
根据掩码方式采样班级,给出掩码和维度索引
tf.boolean_mask(x,mask=[True, False,False,True],axis=0)
注意掩码的长度必须与对应维度的长度一致,如在班级维度上采样,则必须对这 4 个班级是否采样的掩码全部指定,掩码长度为 4
20、如果对 8 门科目进行掩码采样,设掩码采样方案为mask = [True, False, False, True, True, False, False, True],即采样第 1、4、5、8 门科目
# 根据掩码方式采样科目
tf.boolean_mask(x,mask=[True,False,False,True,True,False,False,True],axis=2)
<tf.Tensor: shape=(4, 35, 4), dtype=int32, numpy=
array([[[54, 15, 81, 19],
[23, 62, 0, 32],
[45, 98, 6, 72],
[18, 99, 76, 51],
[81, 20, 64, 32],
[ 5, 43, 30, 80],
[81, 82, 64, 85],
[10, 63, 55, 97],
[68, 86, 35, 60],
[80, 52, 71, 97],
[99, 35, 20, 56],
[27, 94, 0, 44],
[34, 53, 43, 31],
[35, 46, 66, 71],
[17, 77, 81, 65],
[ 8, 60, 94, 53],
[66, 60, 31, 51],
[26, 57, 71, 31],
[53, 42, 65, 46],
[25, 31, 2, 75],
[60, 40, 24, 68],
[49, 97, 2, 96],
[76, 68, 45, 7],
[87, 18, 95, 67],
...
[70, 7, 64, 15],
[29, 72, 30, 63],
[34, 26, 75, 4],
[83, 22, 68, 99],
[64, 37, 64, 23]]], dtype=int32)>
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
21、通过 tf.where(cond, a, b)操作可以根据 cond 条件的真假从参数𝑨或𝑩中读取数据。当对应位置的cond𝑖为 True,𝑜𝑖从𝑎𝑖中复制数据;当对应位置的cond𝑖为 False,𝑜𝑖从𝑏𝑖中复制数据。考虑从 2 个全 1 和全 0 的
3 × 3大小的张量𝑨和𝑩中提取数据,其中cond𝑖为 True 的位置从𝑨中对应位置提取元素 1,cond𝑖为 False 的位置从𝑩对应位置提取元素 0
a = tf.ones([3,3]) # 构造 a 为全 1 矩阵
b = tf.zeros([3,3]) # 构造 b 为全 0 矩阵
# 构造采样条件
cond =tf.constant([[True,False,False],[False,True,False],[True,True,False]])
tf.where(cond,a,b) #根据条件从a,b中采样
可以看到,返回的张量中为 1 的位置全部来自张量 a,返回的张量中为 0 的位置来自张量b。
22、当参数 a=b=None 时,即 a 和 b 参数不指定,tf.where 会返回 cond 张量中所有 True 的元素的索引坐标
cond # 构造的 cond 张量
<tf.Tensor: shape=(3, 3), dtype=bool, numpy=
array([[ True, False, False],
[False, True, False],
[ True, True, False]])>
其中 True 共出现 4 次,每个 True 元素位置处的索引分别为[0,0]、[1,1]、[2,0]、[2,1],可以直接通过 tf.where(cond)形式来获得这些元素的索引坐标
tf.where(cond) # 获取 cond 中为 True 的元素索引
<tf.Tensor: shape=(4, 2), dtype=int64, numpy=
array([[0, 0],
[1, 1],
[2, 0],
[2, 1]])>
23、我们需要提取张量中所有正数的数据和索引。首先构造张量 a,并通过比较运算得到所有正数的位置掩码
x = tf.random.normal([3,3]) # 构造 a
x
> <tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[ 1.3181536 , 0.7503586 , 1.3323568 ],
[-0.2842348 , -0.11278582, 1.5982385 ],
[ 1.1395993 , -0.6405513 , 0.36168438]], dtype=float32)>
24、通过比较运算,得到所有正数的掩码
mask=x>0 # 比较操作,等同于 tf.math.greater()
mask
<tf.Tensor: shape=(4, 28, 28, 1), dtype=bool, numpy=
array([[[[False],
[False],
[ True],
...,
[ True],
[ True],
[ True]],
[[ True],
[ True],
[ True],
...,
[ True],
[False],
[False]],
[[False],
[False],
[ True],
...,
[False],
[False],
[False]],
...
[ True],
...,
[ True],
[ True],
[False]]]])>
Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...
25、通过 tf.where 提取此掩码处 True 元素的索引坐标
indices=tf.where(mask) # 提取所有大于 0 的元素索引
indices
<tf.Tensor: shape=(1597, 4), dtype=int64, numpy=
array([[ 0, 0, 2, 0],
[ 0, 0, 3, 0],
[ 0, 0, 4, 0],
...,
[ 3, 27, 22, 0],
[ 3, 27, 25, 0],
[ 3, 27, 26, 0]])>
26、拿到索引后,通过 tf.gather_nd 即可恢复出所有正数的元素
tf.gather_nd(x,indices) # 提取正数的元素值
<tf.Tensor: shape=(3,), dtype=float32, numpy=array([1.9939046 , 0.2653219 , 0.12416901], dtype=float32)>
27、通过 tf.scatter_nd(indices, updates, shape)函数可以高效地刷新张量的部分数据,但是这个函数只能在全0的白板张量上面执行刷新操作。
我们将实现一个向量的刷新实例如下
# 构造需要刷新数据的位置参数,即为 4、3、1 和 7 号位置
indices = tf.constant([[4], [3], [1], [7]])
# 构造需要写入的数据,4 号位写入 4.4,3 号位写入 3.3,以此类推
updates = tf.constant([4.4, 3.3, 1.1, 7.7])
# 在长度为 8 的全 0 向量上根据 indices 写入 updates 数据
tf.scatter_nd(indices, updates, [8])
可以看到,在长度为 8 的白板上,写入了对应位置的数据,4 个位置的数据被刷新
28、考虑 3 维张量的刷新例子,白板张量的 shape 为[4,4,4],共有 4 个通道的特征图,每个通道大小为4 × 4,现有 2 个通道的新数据 updates:[2,4,4],需要写入索
引为[1,3]的通道上
# 构造写入位置,即 2 个位置
indices = tf.constant([[1],[3]])
updates = tf.constant([# 构造写入数据,即 2 个矩阵
[[5,5,5,5],[6,6,6,6],[7,7,7,7],[8,8,8,8]],
[[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4]]
])
# 在 shape 为[4,4,4]白板上根据 indices 写入 updates
tf.scatter_nd(indices,updates,[4,4,4])
可以看到,数据被刷新到第 2 和第 4 个通道特征图上。
29、通过 tf.meshgrid 函数可以方便地生成二维网格的采样点坐标。通过在 x 轴上进行采样 100 个数据点,y 轴上采样 100 个数据点,然后利用
tf.meshgrid(x, y)即可返回这 10000 个数据点的张量数据,保存在 shape 为[100,100,2]的张量中。为了方便计算,tf.meshgrid 会返回在 axis=2 维度切割后的 2 个张量𝑨和𝑩,其中张量𝑨包含了所有点的 x 坐标,𝑩包含了所有点的 y 坐标,shape 都为[100,100]
x = tf.linspace(-8.,8,100) # 设置 x 轴的采样点
y = tf.linspace(-8.,8,100) # 设置 y 轴的采样点
x,y = tf.meshgrid(x,y) # 生成网格点,并内部拆分后返回
x.shape,y.shape # 打印拆分后的所有点的 x,y 坐标张量 shape
30、利用生成的网格点坐标张量𝑨和𝑩,Sinc 函数在 TensorFlow 中实现如下
z = tf.sqrt(x**2+y**2)
z = tf.sin(z)/z # sinc 函数实现
31、通过 matplotlib 库即可绘制出函数在𝑥 ∈ [−8,8],𝑦 ∈ [−8,8]区间的 3D 曲面
import matplotlib
from matplotlib import pyplot as plt
# 导入 3D 坐标轴支持
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = Axes3D(fig) # 设置 3D 坐标轴
# 根据网格点绘制 sinc 函数 3D 曲面
ax.contour3D(x.numpy(), y.numpy(), z.numpy(), 50)
plt.show()
五、任务小结
本节我们完成了填充、复制,tf.tile()函数实现长度为 1 的维度复制的功能。tf.tile 函数除了可以对长度为 1 的维度进行复制若干份,还可以对任意长度的维度进行复制若干份,进行复制时会根据原来的数据次序重复复制。紧接着介绍了数据的下限幅、上下边界限幅。最后展示了高阶操作如tf.gather、tf.gather_nd、tf.boolean_mask、tf.where等一系列操作。通过本节任务需要掌握以下知识:
- 掌握张量的填充与复制
- 掌握张量的数据限幅
- 掌握张量的高阶操作
–end–