Tensorflow2.0四维张量的索引和切片问题

索引

在 TensorFlow 中,支持基本的[𝑖][𝑗] …标准索引方式,也支持通过逗号分隔索引号的索引方式。考虑输入X 为4 张32x32 大小的彩色图片,shape 为[4,32,32,3],首先创建张量:
x = tf.random.normal([4,32,32,3])
接下来我们使用索引方式读取张量的部分数据。

❑ 取第 1 张图片的数据:

In [51]: x[0]
Out[51]:<tf.Tensor: id=379, shape=(32, 32, 3), dtype=float32, numpy=
array([[[ 1.3005302 , 1.5301839 , -0.32005513],
[-1.3020388 , 1.7837263 , -1.0747638 ], ...
[-1.1092019 , -1.045254 , -0.4980363 ],
[-0.9099222 , 0.3947732 , -0.10433522]]], dtype=float32)>

❑ 取第 1 张图片的第2 行:

In [52]: x[0][1]
Out[52]:
<tf.Tensor: id=388, shape=(32, 3), dtype=float32, numpy=
array([[ 4.2904025e-01, 1.0574218e+00, 3.1540772e-01],
[ 1.5800388e+00, -8.1637271e-02, 6.3147342e-01], ...,
[ 2.8893018e-01, 5.8003378e-01, -1.1444757e+00],
[ 9.6100050e-01, -1.0985689e+00, 1.0827581e+00]], dtype=float32)>

❑ 取第 1 张图片,第2 行,第3 列的像素:

In [53]: x[0][1][2]
Out[53]:
<tf.Tensor: id=401, shape=(3,), dtype=float32, numpy=array([-0.55954427,
0.14497331, 0.46424514], dtype=float32)>

❑ 取第 3 张图片,第2 行,第1 列的像素,B 通道(第2 个通道)颜色强度值:

In [54]: x[2][1][0][1]
Out[54]:
<tf.Tensor: id=418, shape=(), dtype=float32, numpy=-0.84922135>

当张量的维度数较高时,使用[𝑖][𝑗]. . . [𝑘]的方式书写不方便,可以采用[𝑖, 𝑗, … , 𝑘]的方式索引,它们是等价的。

❑ 取第 2 张图片,第10 行,第3 列:

In [55]: x[1,9,2]
Out[55]:
4.6 索引与切片[在此处键入] 17
<tf.Tensor: id=436, shape=(3,), dtype=float32, numpy=array([ 1.7487534 , -
0.41491988, -0.2944692 ], dtype=float32)>

切片

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

❑ 读取第 2,3 张图片:

In [56]: x[1:3]
Out[56]:
<tf.Tensor: id=441, shape=(2, 32, 32, 3), dtype=float32, numpy=
array([[[[ 0.6920027 , 0.18658352, 0.0568333 ],
[ 0.31422952, 0.75933754, 0.26853144],
[ 2.7898 , -0.4284912 , -0.26247284],...

start: end: step切片方式有很多简写方式,其中start、end、step 3 个参数可以根据需要选择性地省略,全部省略时即::,表示从最开始读取到最末尾,步长为1,即不跳过任何元
素。如x[0,::]表示读取第1 张图片的所有行,其中::表示在行维度上读取所有行,它等于
x[0]的写法:

In [57]: x[0,::]
Out[57]:
<tf.Tensor: id=446, shape=(32, 32, 3), dtype=float32, numpy=
array([[[ 1.3005302 , 1.5301839 , -0.32005513],
[-1.3020388 , 1.7837263 , -1.0747638 ],
[-1.1230233 , -0.35004002, 0.01514002],
...

为了更加简洁,::可以简写为单个冒号:,如

In [58]: x[:,0:28:2,0:28:2,:]
Out[58]:
<tf.Tensor: id=451, shape=(4, 14, 14, 3), dtype=float32, numpy=
array([[[[ 1.3005302 , 1.5301839 , -0.32005513],
[-1.1230233 , -0.35004002, 0.01514002],
[ 1.3474811 , 0.639334 , -1.0826371 ],
...

表示取所有图片,隔行采样,隔列采样,所有通道信息,相当于在图片的高宽各缩放至原来的50%。

我们来总结start: end: step切片的简写方式,其中从第一个元素读取时start 可以省略,
即start=0 是可以省略,取到最后一个元素时end 可以省略,步长为1 时step 可以省略

切片的方式意义
start: end:step从 start 开始读取到end(不包含end),步长为step
start: end从 start 开始读取到end(不包含end),步长为1
start:从 start 开始读取完后续所有元素,步长为1
start::step从 start 开始读取完后续所有元素,步长为step
: end:step从 0 开始读取到end(不包含end),步长为step
:end从 0 开始读取到end(不包含end),步长为1
::step每隔 step-1 个元素采样所有
::读取所有元素
:读取所有元素

特别地,step 可以为负数,考虑最特殊的一种例子,step = −1时,start: end: −1表示从start 开始,逆序读取至end 结束(不包含end),索引号𝑒𝑛𝑑 ≤ 𝑠𝑡𝑎𝑟𝑡。考虑一0~9 简单序列,逆序取到第1 号元素,不包含第1 号:

In [59]: x = tf.range(9)
x[8:0:-1]
Out[59]:
<tf.Tensor: id=466, shape=(8,), dtype=int32, numpy=array([8, 7, 6, 5, 4, 3,
2, 1])>

逆序取全部元素:

In [60]: x[::-1]
Out[60]:
<tf.Tensor: id=471, shape=(9,), dtype=int32, numpy=array([8, 7, 6, 5, 4, 3,
2, 1, 0])>

逆序间隔采样:

In [61]: x[::-2]
Out[61]:
<tf.Tensor: id=476, shape=(5,), dtype=int32, numpy=array([8, 6, 4, 2, 0])>

读取每张图片的所有通道,其中行按着逆序隔行采样,列按着逆序隔行采样:

In [62]: x = tf.random.normal([4,32,32,3])
x[0,::-2,::-2]
Out[62]:
<tf.Tensor: id=487, shape=(16, 16, 3), dtype=float32, numpy=
array([[[ 0.63320625, 0.0655185 , 0.19056146],
[-1.0078577 , -0.61400175, 0.61183935],
[ 0.9230892 , -0.6860094 , -0.01580668],
…

当张量的维度数量较多时,不需要采样的维度一般用单冒号:表示采样所有元素,此时有可能出现大量的:出现。继续考虑[4,32,32,3]的图片张量,当需要读取G 通道上的数据时,前面所有维度全部提取,此时需要写为:

In [63]: x[:,:,:,1]
Out[63]:
<tf.Tensor: id=492, shape=(4, 32, 32), dtype=float32, numpy=
array([[[ 0.575703 , 0.11028383, -0.9950867 , ..., 0.38083118,
-0.11705163, -0.13746642],
...

为了避免出现像𝑥[: , : , : ,1]这样出现过多冒号的情况,可以使用⋯符号表示取多个维度上所有的数据,其中维度的数量需根据规则自动推断:当切片方式出现⋯符号时,⋯符号左边的维度将自动对齐到最左边,⋯符号右边的维度将自动对齐到最右边,此时系统再自动推断⋯符号代表的维度数量,它的切片
表格 4.2 …切片方式小结

切片的方式意义
a,⋯,ba 维度对齐到最左边,b 维度对齐到最右边,中间的维度全部读取,其他维度按a/b 的方式读取
a,⋯ a维度对齐到最左边,a 维度后的所有维度全部读取,a 维度按a 方式读取。这种情况等同于a 索引/切片方式
⋯,bb 维度对齐到最右边,b 之前的所有维度全部读取,b 维度按b 方式读取
读取张量所有数据

考虑如下例子:

❑ 读取第 1-2 张图片的G/B 通道数据:

In [64]: x[0:2,...,1:]
Out[64]:
<tf.Tensor: id=497, shape=(2, 32, 32, 2), dtype=float32, numpy=
array([[[[ 0.575703 , 0.8872789 ],
[ 0.11028383, -0.27128693],
[-0.9950867 , -1.7737272 ],
...

❑ 读取最后2 张图片:

In [65]: x[2:,...]
Out[65]:
<tf.Tensor: id=502, shape=(2, 32, 32, 3), dtype=float32, numpy=
array([[[[-8.10753584e-01, 1.10984087e+00, 2.71821529e-01],
[-6.10031188e-01, -6.47952318e-01, -4.07003373e-01],
[ 4.62206364e-01, -1.03655539e-01, -1.18086267e+00],
...

❑ 读取 R/G 通道数据:

In [66]: x[...,:2]
Out[66]:
<tf.Tensor: id=507, shape=(4, 32, 32, 2), dtype=float32, numpy=
array([[[[-1.26881 , 0.575703 ],
[ 0.98697686, 0.11028383],
[-0.66420585, -0.9950867 ],
...

张量的索引与切片方式多种多样,尤其是切片操作,初学者容易犯迷糊。但其实本质上切片操作只有𝑠𝑡𝑎𝑟𝑡: 𝑒𝑛𝑑: 𝑠𝑡𝑒𝑝这一种基本形式,通过这种基本形式有目的地省略掉默认参数,从而衍生出多种简写方法,这也是很好理解的。它衍生的简写形式熟练后一看就能推测出省略掉的信息,书写起来也更方便快捷。由于深度学习一般处理的维度数在4 维以内,⋯操作符完全可以用:符号代替,因此理解了这些就会发现张量切片操作并不复杂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值