tensorflow2.0 张量操作

假如想象 提交于 2019-11-30 00:25:04

3 张量操作

3.1 索引

Tensorflow中,支持基本的[i][j]…的标准索引方式,也支持通过逗号分隔索引号的索引方式[i, j, k]。假设如下为图片数据

In [3]: x = tf.random.normal([4, 32, 32, 3])
  • 取第一张图片数据
In [4]: x[0]                                                                    

Out[4]: 

<tf.Tensor: id=15, shape=(32, 32, 3), dtype=float32, numpy=
  • 取第一张图片的第二行
In [5]: x[0][1]                                                                 

Out[5]: 

<tf.Tensor: id=23, shape=(32, 3), dtype=float32, numpy=
  • 取第1张图片,第2行,第3列的像素
In [6]: x[0][1][2]                                                              

Out[6]: <tf.Tensor: id=35, shape=(3,), dtype=float32, numpy=array([-0.11009463,  0.0398486 ,  1.8434385 ], dtype=float32)>
  • 取第三张图片,第2行,第1列元素,第2个通道的颜色强度值
In [7]: x[2][1][0][1]                                                           

Out[7]: <tf.Tensor: id=51, shape=(), dtype=float32, numpy=0.96755>
  • 取第2张图片,第10行,第3列
In [8]: x[1, 9, 2]                                                              

Out[8]: <tf.Tensor: id=55, shape=(3,), dtype=float32, numpy=array([0.7964836, 1.7832114, 0.4268306], dtype=float32)>

3.2 切片

通过 切片方式可以方便地截取一段数据,start为开始读取位置的索引,end为结束读取位置的索引,不包含end,step为读取步长。

读取第2,3张图片

In [9]: x[1:3]

切片方式简写方式:start、end、step3个参数均可以选择行省略,全部省略时即::,表示从最开始读取到最末尾,步长为1。

x[0,::]表示读取第1张图片的所有行,其中::表示在行维度上读取所有行。

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

In [10]: x[:, 0:28:2, 0:28:2, :]  

表示取所有图片,隔行采样,隔列采样,所有通道信息,相当将图片高宽缩放至50%。

切片方式

意义

 

从start开始读取至end,步长为step

 

从start开始读取至end,步长为1

 

从start开始读取晚后续所有元素,步长为1

 

从start开始读取晚后续所有元素,步长为step

 

从0开始读取到end,步长为step

 

从0开始读取到end,步长为1

 

每隔step-1个元素采样所有

 

读取所有元素

 

读取所有元素

特别地,step可以为负数,表示逆序读取。当张量的维度数较多时,不需要采样的维度一般用单毛号:表示采样所有元素。

3.3 维度变换

在神经网络运算中,维度变换时最核心的张量操作,通过维度变换可以将数据任意的切换形式,满足不同场合的运算需求。

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

  • Reshape

tf.reshape(tensor, shape, name=None)

第一个参数为被调整维度的张量,第二个参数为要调整为的形状,返回一个shape形状的新rensor。注意shape里最多有一个维度的值可以为-1,表示自动计算此维度。

In [3]: x = tf.range(24)                                                 

In [4]: x = tf.reshape(x, [2, 4, 3])

在存储数据时,内存并不支持维度层级概念,只能以平铺的形式写入内存,因此这种层级关系需要人为管理,每个张量的存储顺序需要人为跟踪。

  • 增删维度

通过tf.expand_dims(x, axis)可在指定的axis轴前插入一个新的维度。

考虑一张[28, 28]的图片,即shape为[28, 28],在末尾给张量增加一新维度,定义为通道维度数,此时张量shape变为[28, 28, 1]

In [6]: tf.expand_dims(x, axis = 2)                                             

Out[6]: <tf.Tensor: id=15, shape=(28, 28, 1), dtype=int32, numpy=

注意:aixs为正时,表示在当前维度之前插入一个新的维度,为负时,表示在当前维度之后插入一个新的维度。

通过tf.squeeze(x, axis)可以删除长度为1的维度,axis参数为待删除维度的索引号,删除维度只能删除长度为1的维度,也不会改变张量的存储。

In [8]: x = tf.random.uniform([28, 28, 1], maxval = 10, dtype = tf.int32)       

In [9]: tf.squeeze(x, axis = 2)                                                 

Out[9]: <tf.Tensor: id=20, shape=(28, 28), dtype=int32, numpy=

如果不指定维度参数axis,即tf.sequeeze(x),则其会默认删除所有长度为1的维度。

  • 交换维度

交换维度操作式十分常见的,比如在Tensorflow中,图片张量的默认存储格式事通道后行的格式:[b, h, w, c],但是部分库(pytorch)中图片格式是通道先行:[b, c, h, w],因此需要完成[b, h, w, c]到[b, c, h, w]的维度交换。

可以通过tf.transpose(x, perm)函数完成维度交换操作,其中perm表示新维度的顺序List。考虑图片张量shape为[2, 32, 32, 3],图片数量、行、列、通道数的维度索引为[0, 1, 2, 3],将其交换为[b, c, h, w]格式,则新维度的索引号为[0, 3, 1, 2]。

In [14]: x = tf.random.normal([2, 28, 28, 3])                                   

In [15]: tf.transpose(x, perm = [0, 3, 1, 2])                                   

Out[15]: <tf.Tensor: id=41, shape=(2, 3, 28, 28), dtype=float32, numpy=

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

  • 数据复制

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

如下,通过tf.tile(x, multiples=[2, 1])可以在axis = 0维度复制一次,在axis=1维度不复制。

In [17]: tf.tile(x, multiples=[2, 1])                                           

Out[17]: 

<tf.Tensor: id=44, shape=(2, 2), dtype=int32, numpy=

array([[1, 2],

       [1, 2]], dtype=int32)>

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!