说明:这两个维度变换操作,对于张量的处理是非常重要的!但是二者其实有本质上的不同!一定不能混用。本文将详细说明两者对张量变换的区别。
写在前面1:Tensorflow与Numpy其实从出发点来讲是一致的!都是“高维数组”的科学计算库,只不过TF把高维数组又起了一个名字叫“张量”而已。因此:高维数组与张量没有本质区别!只不过张量多了一个属性叫“张量的阶”(其实就是这个高维数组一共有几维而已)。因此:本文所阐明的Tensorflow中的tf.reshape与tf.transpose的不同,同理可用来区别Numpy中np.reshape与np.transpose。
写在前面2:transpose就是“转置”的意思!当数据/张量为2维时,不论是reshape还是transpose都非常好理解。而本文讲解的“高维数组”下的情况:举一个3维数组的例子,理解之后即可理解更高维的情况。
写在前面3:在深度学习中,tf.reshape改变的是“view(视图)”;tf.transpose改变的是“content(原图)”。其实二者都会改变原始图像的样貌,但个人认为:tf.transpose对原图的改变程度更大!—— 因为它改变的是轴的顺序
本文举例中所用的数据:
import numpy as np
import tensorflow as tf
c1 = [0, 1, 2, 3]
c2 = [4, 5, 6, 7]
c3 = [8, 9, 10, 11]
c4 = [12, 13, 14, 15]
c5 = [16, 17, 18, 19]
c6 = [20, 21, 22, 23]
c = np.array( [ [c1,c2], [c3,c4], [c5,c6] ] )
c = tf.convert_to_tensor(c)
# 所用数据为:
<tf.Tensor: id=12, shape=(3, 2, 4), 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]]])>
一、tf.reshape( c, [] )
使用方式:c1 = tf.reshape(c, [新的尺寸])
参数1:c是原始图像;
参数2:[新的尺寸] —— 给一个“符合逻辑(乘积和原数据点数相同)”的新尺寸。既然可以自定义尺寸,那么理论上就会有非常多种view视图;
函数内部处理流程:
- 把c所有数据点:按页一行一行展平;—— 一定且无法改变
- 把展平的数据按新的尺寸组合起来。—— 自定义
随便自定义一种view视图:
c2 = tf.reshape(c, [2, 6, 2])
c2
# 结果:
<tf.Tensor: id=22, shape=(2, 6, 2), 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]]])>
说明(很重要):如上面说明的函数内部处理流程,其中第一步“数据展平”操作一定会进行且展平规则不会被改变。—— 也就是说:只要原始数据不变,那么展平操作就不变,展平的效果就不变,即:各个“数据点之间的前后顺序”不会改变!—— 所以,不管在哪种view视图下,只要再次reshape到原图的的视图(3,2,4),就能回到原图!!!
在c2视图的基础上,按照原图的视图(3,2,4)回到原图:
c3 = tf.reshape(c2, [3,2,4]) # 在c2视图的基础上,回到原图的视图
c3
# 结果:
<tf.Tensor: id=24, shape=(3, 2, 4), 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]]])>
总结:不管怎么reshape原图,只要原图不变,那么任何新的view视图只要通过“原图的view视图方式”,就一定能回到原图。 —— 即:reshape没有改变原图,因为它没有改变“展平后”的数据点前后、先后顺序!!! —— 即:reshape,仅仅是对原图“看法”的改变,原图还是原图。
二、tf.transpose( c, perm = [新的轴顺序] )
使用方式1:c1 = tf.transpose( c, perm = [新的轴顺序] )
使用方式2:c1 = tf.tf.transpose( c, [新的轴顺序] ) # perm可以不写
参数1:c还是原图数据;
参数2:[新的轴顺序] —— 里面的数值是“索引值”。不需要给定义,举个例子就能明白:比如这里是[1, 0, 2],那么就表示:原来索引号为1的轴(原第二个),现在放第一位;原来索引号为0的轴(原第一个),现在放第二位;原来索引号为2的轴(原第三个),现在放第三位。 —— 即:原图尺寸是(3,2,4),现在按索引号重新调整后变为:(2,3,4)。
它的效果可能不好直观理解,毕竟是“轴交换”。那么下面用是一个示意图来说明。看了示意图,会发现transpose的操作其实很好理解:
图1:transpose之前看的角度永远是“顺着0轴正方向看”:可以看到3个2x4 —— (3,2,4)
[0 1 2 3
4 5 6 7]
[8 9 10 11
12 13 14 15]
[16 17 18 19
20 21 22 23]
当perm = [1, 0, 2]时:0轴和1轴交换
图2:transpose之后:0轴和1轴交换
仍然是“顺着0轴正方向看”:现在是“从纸内向纸外”(不方便画箭头,就省略了)。那么现在看到就是2个3x4 —— (2, 3, 4)
[0 1 2 3
8 9 10 11
16 17 18 19]
[4 5 6 7
12 13 14 15
20 21 22 23]
验证一下这种理解方法是否正确:
c1 = tf.transpose(c, perm = [1, 0, 2])
c1
# 结果:
<tf.Tensor: id=26, shape=(2, 3, 4), dtype=int32, numpy=
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11],
[16, 17, 18, 19]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15],
[20, 21, 22, 23]]])> # 果然,理解没错!
说明(很重要):tf.transpose改变是轴的顺序,也就是从不同的轴向来看待原数据!—— 这种轴的变换,虽然原数据点之间的相互顺序没用变,但换了一个轴的来看、来划分这些数据,其结果就是完全新的数据!—— 这些新的数据,不管怎么reshape是肯定回不到原图像的(因为reshape所根据的是“新数据”,由由上面关于reshape的说明可知:reshape不会改变所基于数据的数据点的相互排序顺序,因此不可能通过reshape把新数据恢复到原数据)。—— 因此:要想把tf.transpose创造的新数据,再转变回原数据,只能还利用tf.transpose按“相反的轴变换”再变回去。
例如,把上面的c1再利用tf.transpose变回原图:在新图上再把0轴和1轴交换
c11 = tf.transpose(c1, [1, 0, 2])
c11
# 结果:
<tf.Tensor: id=20, shape=(3, 2, 4), 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]]])>
总结:以0轴的正方向来看,再每一个面上:先2轴正方向,再1轴正方向。
总之:tf.transpose对于高维数组/张量的变换,是轴的交换,从得带来的是“观察方位”的改变。
网友评论