對(duì)于java起手的程序猿剩瓶,python的計(jì)算多維度數(shù)組的方式真的是有點(diǎn)蛋疼。最近看代碼的時(shí)候需要弄明白tf.slice()的具體操作方法含鳞。去看了看官方的注釋和例子還是一頭霧水影锈,就是看不明白這到底是怎么切的。于是搜了幾個(gè)quora的帖子蝉绷,終于搞懂了鸭廷。下面舉3個(gè)例子??解釋一下切割原理。如果你也跟我一樣不太明白的話就接著往下看吧熔吗。解釋不清楚我吃粑粑辆床。(少在我的簡(jiǎn)書(shū)里騙吃騙喝~)
首先看一眼源代碼注釋是怎么說(shuō)的:
This operation extracts a slice of size `size` from a tensor `input` starting at the location specified by `begin`. The slice `size` is represented as tensor shape, where `size[i]` is the number of elements of the 'i'th dimension of `input` that you want to slice. The starting location (`begin`) for the slice is represented as an offset in each dimension of `input`. In other words, `begin[i]` is the offset into the 'i'th dimension of `input` that you want to slice from.
方程的signature是這樣的:
def slice(input_, begin, size, name=None):
其中“input_”是你輸入的tensor,就是被切的那個(gè)桅狠。
“begin”是每一個(gè)維度的起始位置讼载,這個(gè)下面詳細(xì)說(shuō)。
“size”相當(dāng)于問(wèn)每個(gè)維度拿幾個(gè)元素出來(lái)中跌。
下面看例1:
t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]])
tf.slice(t, [1, 0, 0], [1, 1, 3])
這個(gè)輸出是:
[[[3, 3, 3]]]
首先作為一個(gè)3維數(shù)組t咨堤,你要先明白他的shape是[3,2,3].??
Shape:
這個(gè)shape是怎么來(lái)的呢?咱們把這個(gè)t分解一下看就好理解了漩符。那一大堆有括號(hào)的t一喘,只看它最外面的括號(hào)的話,可以看成是:
t = [A, B, C]? ?#這是第一維度
然后每一個(gè)里面有兩個(gè)東西嗜暴,可以寫(xiě)成:
A = [i, j]津滞, B = [k, l], C = [m, n]? #這是第二維度
最后灼伤,這i, j, k, l, m, n里面分別是:
i = [1, 1, 1],?j = [2, 2, 2],?k = [3, 3 ,3],?l = [4, 4, 4],?m = [5, 5, 5],?n = [6, 6, 6]? # 這是第三維度
所以shape就是中括號(hào) [ ] 的層級(jí)里單位的數(shù)量触徐。
對(duì)于t來(lái)說(shuō),最外面括號(hào)里有3個(gè)東西狐赡,分別是A, B, C撞鹉。這三個(gè)東西每個(gè)里面有兩個(gè)玩意兒, i和j, k和l, m和n。
他們里面每一個(gè)又有3個(gè)數(shù)字。所以t的shape是[3,2,3]鸟雏。這是我的理解方式享郊。
Slice:
在解釋slice之前,有一點(diǎn)要知道的是python的數(shù)組index是從0開(kāi)始的孝鹊。
有了這個(gè)基礎(chǔ)炊琉,我們?cè)賮?lái)看例子:
tf.slice(t, [1, 0, 0], [1, 1, 3])? # begin =?[1, 0, 0]
這里根據(jù)順序我們知道,begin是[1, 0, 0], size是[1, 1, 3].? 他們兩個(gè)數(shù)組的意義是從左至右又活,每一個(gè)數(shù)字代表一個(gè)維度苔咪。上面說(shuō)了begin的意思是起始位置,那么[1, 0, 0]的意思是在3個(gè)維度中柳骄,每個(gè)維度從哪里算起团赏。
第一維度是[A, B, C]。 begin里[1, 0, 0]是1耐薯,也就是從B算起舔清。其次第二維度里B = [k, l](注意啊,我這里只寫(xiě)了B = [k, l]曲初,可不代表只有B有用体谒,如果size里第一個(gè)數(shù)字是2的話,B和C都會(huì)被取的)臼婆,begin里第二個(gè)數(shù)是0抒痒,也就是從k算起。第三維度k = [3, 3 ,3]目锭,begin里第三個(gè)數(shù)是0评汰,就是從第一個(gè)3算起。
到現(xiàn)在都能看懂吧痢虹?知道了這三個(gè)起始點(diǎn)之后被去,再來(lái)看size。
size的意思是每個(gè)維度的大小奖唯,也就是每個(gè)維度取幾個(gè)元素惨缆。size的應(yīng)該是最后輸出的tensor的shape。
例子里面:
tf.slice(t, [1, 0, 0], [1, 1, 3])? # size =?[1, 1, 3]
size里第一個(gè)是1丰捷,意思是在第一個(gè)維度取1個(gè)元素坯墨。t = [A, B, C] begin是起算是B,取一個(gè)那就是B了唄病往。那么第一維度結(jié)果就是[B]
size第二個(gè)也是1捣染,第二維度B = [k, l], begin里起算是k停巷,取一個(gè)是k耍攘。那么第二維度結(jié)果是[[k]]榕栏。
size第三個(gè)是3,第三維度k = [3, 3 ,3],begin里起算是第一個(gè)3蕾各。三個(gè)3取3個(gè)數(shù)扒磁,那就要把三個(gè)3都取了,所以是
[[[3, 3, 3]]]
看懂了嗎式曲?是不是有點(diǎn)像代數(shù)妨托?[B]里把B換成[k], 再把k換成[3, 3 ,3]吝羞。最后注意中括號(hào)的數(shù)量兰伤,和size一樣是[1, 1, 3].
例2:
t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]])
tf.slice(t, [1, 0, 0], [1, 2, 3])
看懂了第一個(gè),再看第二個(gè)就簡(jiǎn)單了脆贵。這里begin還是一樣[1, 0 ,0]医清。 size第一個(gè)維度取一個(gè)起暮,還是[B]卖氨。然后這里不是1了,是2负懦,意思是取兩個(gè)筒捺。還記得B = [k, l]嗎?現(xiàn)在不是只要k了纸厉,是k和l都要系吭。第三維度取3個(gè),也就是說(shuō)不光是k = [3, 3 ,3]颗品,l = [4, 4, 4]也要slice走肯尺。
總結(jié)一下,第一維度取[B]躯枢。第二維度里把B換成[k, l],就變成了[[k, l]]. 第三維度里把k換成[3, 3 ,3]则吟,把l 換成 [4, 4, 4],替換后是最終結(jié)果
[[[3, 3, 3], [4, 4, 4]]]
是不是覺(jué)得看懂了也挺簡(jiǎn)單的锄蹂,只是可能不太習(xí)慣這種思維方式氓仲。
例3:
t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], [6, 6, 6]]])
tf.slice(t, [1, 0, 0], [-1, -1, -1])
對(duì)于這種情況,源代碼注釋中有一句話:
If `size[i]` is -1, all remaining elements in dimension i are included in the slice. In other words, this is equivalent to setting:?`size[i] = input.dim_size(i) - begin[i]`
也就是說(shuō)得糜,如果size輸入值是-1的話敬扛,在那個(gè)維度剩下的數(shù)都會(huì)slice走。上面的例子中朝抖,begin是[1, 0, 0]啥箭。三個(gè)維度都是-1的話,那么結(jié)果: 第一維度是[B,C]治宣;第二維度是[[k, l], [m, n]]; 第三維度是[[[3,3,3], [4,4,4]], [[5,5,5], [6,6,6]]]
ref:
https://www.tensorflow.org/versions/r1.1/api_docs/python/tf/slice
https://www.quora.com/How-does-tf-slice-work-in-TensorFlow