TensorFlow:维度变换

基本的维度变换包含了改变视图 reshape,插入新维度 expand_dims,删除维 squeeze,交换维度 transpose,复制数据 tile 等。

一、张量的存储和视图(View)概念

张量的视图就是我们理解张量的方式,比如shape 为[2,4,4,3]的张量A,我们从逻辑上可以理解为2 张图片,每张图片4 行4 列,每个位置有RGB 3 个通道的数据;

张量的存储体现在张量在内存上保存为一段连续的内存区域,对于同样的存储,我们可以有不同的理解方式,比如上述A,我们可以在不改变张量的存储下,将张量A 理解为2 个样本,每个样本的特征为长度48 的向量。

这就是存储与视图的关系。

在存储数据时,内存并不支持这个维度层级概念,只能以平铺方式按序写入内存,因此这种层级关系需要人为管理,也就是说,每个张量的存储顺序需要人为跟踪
为了方便表达,我们把张量shape 中相对靠左侧的维度叫做大维度,shape 中相对靠右侧的维度叫做小维度,比如[2,4,4,3]的张量中,图片数量维度与通道数量相比,图片数量叫做大维度,通道数叫做小维度。
例如:在优先写入小维度的设定下,张量 [2,4,4,3] 的内存布局为
在这里插入图片描述

为了能够正确恢复出数据,必须保证张量的存储顺序与新视图的维度顺序一致
例如根据图片数量-行-列-通道初始视图保存的张量,按照图片数量-行-列-通道(𝑏 − ℎ −w − 𝑐)的顺序可以获得合法数据。

如果按着图片数量-像素-通道(b − h ∗ w − c)的方式恢复视图,也能得到合法的数据。但是如果按着图片数量-通道-像素( − c − h ∗ w)的方式恢复数据,由于内存布局是按着图片数量-行-列-通道的顺序,视图维度与存储维度顺序相悖,提取的数据将是错乱的。

二、Reshape 操作

改变视图是神经网络中非常常见的操作,可以通过串联多个Reshape 操作来实现复杂
逻辑

但是在通过Reshape 改变视图时,必须始终记住张量的存储顺序,新视图的维度顺序不能与存储顺序相悖,否则需要通过交换维度操作将存储顺序同步过来。
举个例子,对于shape 为[4,32,32,3]的图片数据,通过Reshape 操作将shape 调整为[4,1024,3],此时视图的维度顺序为 𝑏 − 𝑝𝑖𝑥𝑒𝑙 − 𝑐,张量的存储顺序为 [𝑏, ℎ, w, 𝑐]。

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

在这里插入图片描述
通过 tf.reshape(x,new_shape),可以将张量的视图任意的合法改变
在这里插入图片描述
当不知道填入什么数字合适时,可以选用 -1 来替代,由python通过其他值进行推算得知具体值
例如将shape为 [b,3,4]的输入数据转为 shape为 [b,3*4] 的数据:
在这里插入图片描述

三、增删维度

1. 增加维度

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

比如:,一张28x28 灰度图片的数据保存为 shape 为[28,28]的张量,在末尾给张量增加一新维度,定义为通道数维度,此时张量的shape 变为[28,28,1]:

通过tf.expand_dims(x, axis)可在指定的axis 轴前可以插入一个新的维度
在这里插入图片描述
可以看到插入一个新维度后,数据的存储顺序并没有改变,仅仅改变了数据的视图。
在这里插入图片描述
需要注意的是,tf.expand_dims 的axis 为正时,表示在当前维度之前插入一个新维度;为负时,表示当前维度之后插入一个新的维度。以[𝑏, ℎ, w, 𝑐]张量为例,不同axis 参数的实际插入位置如图所示:
在这里插入图片描述

2. 删除维度

是增加维度的逆操作,与增加维度一样,删除维度只能删除长度为1 的维度,也不会改变张量的存储。

可以通过tf.squeeze(x, axis)函数,axis 参数为待删除的维度的索引号
在这里插入图片描述
如果不指定维度参数 axis,即 tf.squeeze(x),那么他会默认删除所有长度为1的维度

四、交换维度

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

我们以[𝑏, ℎ, w, 𝑐]转换到[𝑏, 𝑐, ℎ, w]为例,介绍如何使用tf.transpose(x, perm)函数完成维度交换操作,其中 perm 表示新维度的顺序 List。
在这里插入图片描述
通过tf.transpose完成维度交换后,张量的存储顺序已经改变,视图也随之改变,后续的所有操作必须基于新的存续顺序进行

五、数据复制

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

六、Broadcasting(自动扩展)

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

对于所有长度为1 的维度,Broadcasting 的效果和tf.tile 一样,都能在此维度上逻辑复制数据若干份,区别在于tf.tile 会创建一个新的张量,执行复制IO 操作,并保存复制后的张量数据,Broadcasting 并不会立即复制数据,它会逻辑上改变张量的形状,使得视图上变成了复制后的形Broadcasting 会通过深度学习框架的优化手段避免实际复制数据而完成逻辑运算,至于怎么实现的用户不必关系,对于用于来说,Broadcasting 和tf.tile 复制的最终效果是一样的,操作对用户透明,但是Broadcasting 机制节省了大量计算资源,建议在运算过程中尽可能地利用Broadcasting 提高计算效率。

Broadcasting 机制的核心思想是普适性,即同一份数据能普遍适合于其他位置。在验证普适性之前,需要将张量shape 靠右对齐,然后进行普适性判断:对于长度为1 的维度,默认这个数据普遍适合于当前维度的其他位置;对于不存在的维度,则在增加新维度后默认当前数据也是普适性于新维度的,从而可以扩展为更多维度数、其他长度的张量形状。

在这里插入图片描述
在这里插入图片描述
在 c 维度上,张量已经有2 个特征数据,新shape 对应维度长度为c(𝑐 ≠ 2,比如c=3),那么当前维度上的这2 个特征无法普适到其他长度,故不满足普适性原则,无法应用 Broadcasting 机制,将会触发错误

在进行张量运算时,有些运算可以在处理不同shape 的张量时,会隐式自动调用 Broadcasting 机制,如+,-,*,/等运算等,将参与运算的张量Broadcasting 成一个公共shape,再进行
在这里插入图片描述

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南淮北安

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

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

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

打赏作者

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

抵扣说明:

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

余额充值