数组转置以及time_major和batch_major的区别

1)数组转置和轴对换

转置(transpose)是重塑的一种特殊形式,它返回的是源数据的视图(不会进行任何复制操作),不仅有transpose方法,还有一个特殊的T属性

In [1]:
import numpy as np
arr=np.arange(15)
arr
Out[1]:
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
In [2]:
arr=arr.reshape((3,5))
arr
Out[2]:
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

二维数组转置后,原来的行变成列,原来arr是3行5列的数组,现在变成了5行3列,转置只是返回的是视图,不改变原来的数组

In [3]:
arr.T
Out[3]:
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])
In [4]:
arr.transpose()
Out[4]:
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])
In [5]:
arr.T.shape
Out[5]:
(5, 3)
In [6]:
arr.transpose().shape
Out[6]:
(5, 3)

对于高维数组,transpose需要一个轴编号组成的元组才能对这些轴进行转置,那轴编号是什么呢?按照定义,轴编号是数组shape的索引编号。对于二维数组Axis 0是第一维(也就是行rows),Axis 1是第二维(也就是列columns),对于高维数组行和列没那么直观,需要从数组shape的索引来考虑。如果操作 .sum(axis=n),则第n维就会折叠和删除,而新矩阵的值等于对应折叠列求和。

In [7]:
arr=np.arange(24).reshape((2,3,4))
arr
Out[7]:
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]]])

现在arr的shape为(2,3,4),Axis 0对应2,Axis 1对应3,Axis 2对应4

In [8]:
arr.shape
Out[8]:
(2, 3, 4)

把arr变为shape为(3,2,4)的数组,交换Axis0和Axis1的位置即可

In [9]:
a=arr.transpose((1,0,2))
a
Out[9]:
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])
In [10]:
a.shape
Out[10]:
(3, 2, 4)

把arr变shape为(4,3,2)的数组,则重新编排下Axis的顺序即可

In [11]:
b=arr.transpose((2,1,0))
b
Out[11]:
array([[[ 0, 12],
        [ 4, 16],
        [ 8, 20]],

       [[ 1, 13],
        [ 5, 17],
        [ 9, 21]],

       [[ 2, 14],
        [ 6, 18],
        [10, 22]],

       [[ 3, 15],
        [ 7, 19],
        [11, 23]]])
In [12]:
b.shape
Out[12]:
(4, 3, 2)

有时候我们仅仅想交换两个Axis而已,不想写出全部的Axis,那么就使用swapaxes方法,函数接口为swapaxes(axis1,axis2), 例如把arr数组变成shape为(3,2,4),效果和arr.transpose((1,0,2))一样

In [13]:
arr.swapaxes(0,1)
Out[13]:
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])
In [14]:
c=arr.swapaxes(1,0)
c
Out[14]:
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])
In [15]:
c.shape
Out[15]:
(3, 2, 4)

现在想把c数组变成shape成(3,2),并且值是最后一维是求和

In [16]:
d=c.sum(axis=2)
d
Out[16]:
array([[ 6, 54],
       [22, 70],
       [38, 86]])
In [17]:
d.shape
Out[17]:
(3, 2)

2)tensorflow也有对应的操作,分别是tf.shape(input,name=None,out_type=tf.int32)tf.transpose(a,perm=None,name='tranpose',conjugate=False)

In [18]:
import tensorflow as tf
sess=tf.Session()
t=tf.constant(np.arange(24).reshape((2,3,4)))
sess.run(t)
Out[18]:
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]]])
In [19]:
sess.run(tf.shape(t))
Out[19]:
array([2, 3, 4], dtype=int32)

把t变成shape为(4,3,2)的tensor

In [20]:
t1=tf.transpose(t,perm=[2,1,0])
sess.run(t1)
Out[20]:
array([[[ 0, 12],
        [ 4, 16],
        [ 8, 20]],

       [[ 1, 13],
        [ 5, 17],
        [ 9, 21]],

       [[ 2, 14],
        [ 6, 18],
        [10, 22]],

       [[ 3, 15],
        [ 7, 19],
        [11, 23]]])
In [21]:
sess.run(tf.shape(t1))
Out[21]:
array([4, 3, 2], dtype=int32)

3)time_major和batch_major的区别

想象你有如下的数据,shape为(batch_size,features),batch_size=100,features=4,其中每行为一个训练数据的输入,每列是不同的数据特征。

In [22]:
arr=np.arange(200).reshape((50,4))
arr
Out[22]:
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],
       [ 24,  25,  26,  27],
       [ 28,  29,  30,  31],
       [ 32,  33,  34,  35],
       [ 36,  37,  38,  39],
       [ 40,  41,  42,  43],
       [ 44,  45,  46,  47],
       [ 48,  49,  50,  51],
       [ 52,  53,  54,  55],
       [ 56,  57,  58,  59],
       [ 60,  61,  62,  63],
       [ 64,  65,  66,  67],
       [ 68,  69,  70,  71],
       [ 72,  73,  74,  75],
       [ 76,  77,  78,  79],
       [ 80,  81,  82,  83],
       [ 84,  85,  86,  87],
       [ 88,  89,  90,  91],
       [ 92,  93,  94,  95],
       [ 96,  97,  98,  99],
       [100, 101, 102, 103],
       [104, 105, 106, 107],
       [108, 109, 110, 111],
       [112, 113, 114, 115],
       [116, 117, 118, 119],
       [120, 121, 122, 123],
       [124, 125, 126, 127],
       [128, 129, 130, 131],
       [132, 133, 134, 135],
       [136, 137, 138, 139],
       [140, 141, 142, 143],
       [144, 145, 146, 147],
       [148, 149, 150, 151],
       [152, 153, 154, 155],
       [156, 157, 158, 159],
       [160, 161, 162, 163],
       [164, 165, 166, 167],
       [168, 169, 170, 171],
       [172, 173, 174, 175],
       [176, 177, 178, 179],
       [180, 181, 182, 183],
       [184, 185, 186, 187],
       [188, 189, 190, 191],
       [192, 193, 194, 195],
       [196, 197, 198, 199]])
In [23]:
arr.shape
Out[23]:
(50, 4)

arr的转置矩阵如下,也就是矩阵变成了(features,batch_size)

In [24]:
a=arr.transpose((1,0))
a
Out[24]:
array([[  0,   4,   8,  12,  16,  20,  24,  28,  32,  36,  40,  44,  48,
         52,  56,  60,  64,  68,  72,  76,  80,  84,  88,  92,  96, 100,
        104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152,
        156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196],
       [  1,   5,   9,  13,  17,  21,  25,  29,  33,  37,  41,  45,  49,
         53,  57,  61,  65,  69,  73,  77,  81,  85,  89,  93,  97, 101,
        105, 109, 113, 117, 121, 125, 129, 133, 137, 141, 145, 149, 153,
        157, 161, 165, 169, 173, 177, 181, 185, 189, 193, 197],
       [  2,   6,  10,  14,  18,  22,  26,  30,  34,  38,  42,  46,  50,
         54,  58,  62,  66,  70,  74,  78,  82,  86,  90,  94,  98, 102,
        106, 110, 114, 118, 122, 126, 130, 134, 138, 142, 146, 150, 154,
        158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198],
       [  3,   7,  11,  15,  19,  23,  27,  31,  35,  39,  43,  47,  51,
         55,  59,  63,  67,  71,  75,  79,  83,  87,  91,  95,  99, 103,
        107, 111, 115, 119, 123, 127, 131, 135, 139, 143, 147, 151, 155,
        159, 163, 167, 171, 175, 179, 183, 187, 191, 195, 199]])
In [25]:
a.shape
Out[25]:
(4, 50)

对于RNN的输入张量通常是3维数组以上,如果输入的是(batch_size,sequence_num,features),则叫做batch major,因为Axis 0是batch_size;如果输入的是(sequence_num,batch_size,features),则叫做time major,因为Axis 0是sequence_num。特征features总是最后的一维。到底是batch major还是time major取决于函数的API,按照API格式输入即可

参考资料

《python for data analysis》

What's the difference between data time major and batch major?

how is axis indexed in numpy's array?

《tensorflow官方文档》

In [ ]: