上一篇里詳細(xì)解釋了tf.slice()
到底是怎么切的,包括shape和怎么思考這種基于數(shù)組的表現(xiàn)方式比較容易理解跳昼。這一篇我打算說tf.concat()
般甲,然后下一篇講tf.stack()
。這兩個(gè)容易混淆庐舟。而且相比之下欣除,tf.concat()
應(yīng)該對(duì)于有計(jì)算機(jī)背景的人更好理解一點(diǎn)。所以咱們本著由淺入深的原則逐個(gè)攻克挪略。
tf.concat()
是相對(duì)比較好理解的函數(shù)历帚,它和python里的numpy.concatenate()
函數(shù)作用是一樣的。都是把多個(gè)array沿著某一個(gè)維度接在一起杠娱。只不過numpy.concatenate()
用來處理numpy array挽牢,tf.concat()
用于處理tensor。他們倆有個(gè)共同點(diǎn)摊求,就是得到的結(jié)果tensor或者numpy array的維度的數(shù)量一定是一樣的禽拔。(如果忘了shape是什么,請(qǐng)先看上一篇)
方程的signature長(zhǎng)這樣:
concat( values, axis, name='concat')
來看例1:
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2], 0)
輸出結(jié)果是:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
shape=[4, 3]
先來分解一下t1和t2室叉。首先t1 = [[1, 2, 3], [4, 5, 6]]
可以看成:
t1 = [A, B]
A = [1,2,3]
B = [4,5,6]
t1的shape是[2,3]睹栖,意思是有2個(gè)元素[A, B], 他們每個(gè)里面有3個(gè)元素。這種類似于代數(shù)的思維方式上一篇也有介紹茧痕。
那么t2 = [[7, 8, 9], [10, 11, 12]]
也照貓畫虎:
t2 = [C, D]
C = [7,8,9]
D = [10,11,12]
t2的shape也是[2,3]
這里[2,3]的維度數(shù)量是2野来,也就是2維的。如果是3維的可能是[2,3,什么]踪旷。知道tf.concat()
不會(huì)改變維度數(shù)量非常重要曼氛。因?yàn)?code>tf.concat()只是對(duì)對(duì)應(yīng)維度元素?cái)?shù)量的疊加。比如tf.concat([t1, t2], 0)
意思是對(duì)t1和t2在第一維度對(duì)接令野。因?yàn)樗麄z的shape都是[2,3]舀患,輸出tensor的shape一定是[4,3],因?yàn)樗麄z的第一維度都是2气破,2+2=4聊浅。再比如如果是tf.concat([t1, t2], 1)
,那么輸出shape一定是[2,6]现使,以此類推低匙。
Concatenation
現(xiàn)在再來看例子:
tf.concat([t1, t2], 0) #后面的0的意思是 axis=0
維度是從0開始算的,也就是沿著第一個(gè)維度接起來朴下。(以此類推努咐,axis=1
就是第二個(gè)維度)
從shape可以看出t1和t2都是只有兩個(gè)維度。既然是沿著第一個(gè)維度對(duì)接殴胧,那根本就不用看第二個(gè)維度渗稍。
那么什么是第一個(gè)維度呢?就可以理解成第一層中括號(hào)团滥。t1的第一層中括號(hào)是t1 = [A, B]竿屹, t2 = [C, D]
(展開A,B,C,D是第二個(gè)維度)
那對(duì)接是什么意思呢?就是把對(duì)應(yīng)的中括號(hào)打開灸姊,把對(duì)應(yīng)的里面一層的元素放在一起拱燃,再用中括號(hào)全擴(kuò)起來。
按步驟是:
- 打開中括號(hào):[A,B],[C,D] -> A,B,C,D
- 放在一起再擴(kuò)起來: A,B,C,D -> [A,B,C,D]
這里已經(jīng)知道了輸出的shape是[4,3]力惯。其中的4代表第一維度有4個(gè)元素碗誉,就是A,B,C,D召嘶。t1 = [A, B], t2 = [C, D]
各只有一個(gè)中括號(hào)哮缺,所以不用考慮對(duì)應(yīng)弄跌,直接放一起就行了。如果t1和t2比如各有2個(gè)中括號(hào)的話尝苇,括回去之后也應(yīng)該有2個(gè)中括號(hào)铛只,下面例2有講到
A,B,C,D都是什么來著?
A = [1,2,3]
B = [4,5,6]
C = [7,8,9]
D = [10,11,12]
每個(gè)里面有3個(gè)元素糠溜,這就是[4,3]的3的含義淳玩。
所以輸出結(jié)果是:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], shape = [4,3]
注意t1和t2是有順序的。如果這行命令是:
tf.concat([t2, t1], 0)
那么結(jié)果應(yīng)該是[[7, 8, 9], [10, 11, 12], [1, 2, 3], [4, 5, 6]]
例2非竿,如果是:
tf.concat([t1, t2], 1) #1是 axis=1蜕着,第二維度的意思
還是按照上面的方法,我們知道了輸出結(jié)果的shape一定是[2,6]汽馋。既然沿著第二維度對(duì)接侮东,那么不用看第一維度。
第一維度是:t1 = [A, B]豹芯, t2 = [C, D]
(不用動(dòng),也就是這一維度的輸出結(jié)果一定是[x1, x2])
第二維度是:A = [1,2,3] B = [4,5,6] C = [7,8,9] D = [10,11,12]
這里A,B屬于t1悄雅,C,D屬于t2,各有2個(gè)中括號(hào)铁蹈。那么按順序宽闲,A對(duì)應(yīng)C,B對(duì)應(yīng)D握牧。
- 打開中括號(hào):[1,2,3],[4,5,6],[7,8,9],[10,11,12] -> 1,2,3, 4,5,6, 7,8,9, 10,11,12
- 對(duì)應(yīng)的A,C放一起:1,2,3,7,8,9 -> [1,2,3,7,8,9]
- 對(duì)應(yīng)的B,D放一起: 4,5,6,10,11,12 -> [4,5,6,10,11,12]
最后在第一維度括起來容诬,結(jié)果是:
[[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12]], shape = [2,6]
直觀方法
我個(gè)人還有一種直觀的方法去理解上面的對(duì)接。
回到例1:
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2], 0)
其實(shí)t1是個(gè)2維數(shù)組沿腰,也就是一個(gè)面览徒。形象一點(diǎn)就是:
t1:
-------
|1|2|3|
|-|-|-|
|4|5|6|
-------
t2:
----------
| 7| 8| 9|
|--|--|--|
|10|11|12|
----------
都是2行3列。
我會(huì)把第一維度看成行颂龙,第二維度看成列习蓬。
如果沿著行對(duì)接,也就是把行數(shù)增加為4行措嵌,列數(shù)還是3列躲叼。那么結(jié)果就是:
----------
| 1| 2| 3|
|--|--|--|
| 4| 5| 6|
----------
| 7| 8| 9|
|--|--|--|
|10|11|12|
----------
這個(gè)矩陣就是:
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
[10, 11, 12]]
再看例2:
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2], 1)
這就是沿著列對(duì)接,也就是變成6列企巢。行還是3行枫慷。也就變成了:
-------------------
| 1| 2| 3| 7| 8| 9|
|--|--|--|--|--|--|
| 4| 5| 6|10|11|12|
-------------------
輸出就是
[[1, 2, 3, 7, 8, 9],
[4, 5, 6, 10, 11, 12]]
如果兩個(gè)tensor都有第三維的話,比如:
t1 = [[[1], [2], [3]], [[4], [5], [6]]]
t2 = [[[7], [8], [9]], [[10], [11], [12]]]
tf.concat([t1, t2], 2)
t1和t2的shape都是[2,3,1],沿著第三維對(duì)接或听。結(jié)果shape一定是[2,3,2]探孝。
那么用這個(gè)直觀的方法就是非常好理解,
就可以理解成把t1的2d矩陣放在t2的2d矩陣的前面神帅,形成一個(gè)3d矩陣再姑,像這樣:
2行:[A, B]
3列:A = [a,b,c], B = [d, e, f]
2層:a = [1,7], b = [2,8], c = [3, 9], d = [4, 10], e = [5, 11], f = [6, 12]
所以結(jié)果是:
[[[1,7], [2,8], [3, 9]], [[4, 10], [5, 11], [6, 12]]], shape = [2,3,2]
這種方法的弊端就是大于3維的數(shù)組就不好想了,畢竟我們生活的是3維世界绍填。