



如果要提取3*3鄰域,按照上面代碼的實(shí)現(xiàn)邏輯,則應(yīng)該是x0 = x[:, 0::2, 0::2, :] # B H/2 W/2 Cx1 = x[:, 1::2, 0::2, :] # B H/2 W/2 Cx2 = x[:, 0::2, 1::2, :] # B H/2 W/2 Cx3 = x[:, 1::2, 1::2, :] # B H/2 W/2 Cx = torch.cat([x0, x1, x2, x3], -1) # B H/2 W/2 4*C
x0 = x[:, 0::3, 0::3, :] # B H/3 W/3 Cx1 = x[:, 1::3, 0::3, :] # B H/3 W/3 Cx2 = x[:, 0::3, 1::3, :] # B H/3 W/3 Cx3 = x[:, 1::3, 1::3, :] # B H/3 W/3 C........x7 = x[:, 2::3, 3::3, :]x8 = x[:, 3::3, 2::3, :]x = torch.cat([x0, x1, x2, x3,...,x8], -1) # B H/2 W/2 9*C



x = rearrange(x, 'b h w (p1 p2 c)-> b (h p1) (w p2) c', p1=2, p2=2, c=1) rearrange函數(shù)的輸入包括三部分,x是輸入張量,'b?h?w?(p1?p2?c)->?b?(h?p1)?(w?p2)?c'是張量重排規(guī)則,p1=self.dim_scale,?p2=self.dim_scale,?c=C//self.dim_scale是重排規(guī)則中的相關(guān)變量賦值。這個(gè)格式其實(shí)與之前我們講過(guò)的torch.einsum很相似,詳情見(jiàn)torch.einsum解析,但區(qū)別在于,torch.einsum實(shí)現(xiàn)的是愛(ài)因斯坦求和,是包含加法和乘法的。而rearrange只是張量的重排,并不涉及到加法和乘法。有人會(huì)說(shuō),那torch.einsum是不是都得有兩個(gè)或以上的輸入張量?。窟€真不一定,比如求對(duì)角線平方和就也只需要一個(gè)輸入,因此這不能作為torch.einsum和rearrange的區(qū)別。 diagonal_elements = torch.einsum('ii->i', A) 下面我們重新看rearrange示例的重排規(guī)則部分: 'b h w (p1 p2 c)-> b (h p1) (w p2) c' 輸入為4維張量,分別為b, h, w, 2*2*1。然后將其重排為形狀b, h*2, w*2, 1。我們先一句話總結(jié)其作用:將(h, w)形狀的張量重排成(h*2,w*2),也就是每個(gè)位置擴(kuò)展成2*2的子區(qū)域,該區(qū)域用張量的通道維度填充,也就是這里的第四個(gè)維度2*2*1。 起初我對(duì)這一操作十分不解,核心問(wèn)題是,我可以通過(guò)通過(guò)線性代數(shù)中的子矩陣概念來(lái)理解這一操作。但是我無(wú)法將張量重排操作前后的映射關(guān)系用數(shù)學(xué)公式表示出來(lái)。 例如(1,2,2,4)的張量,我們可以理解為(2,2)個(gè)向量,每個(gè)向量包含4個(gè)元素。將其通道維度展開(kāi)以將原來(lái)的空間維度(2,2)擴(kuò)展成(4,4)可以這樣理解,原來(lái)(2,2)的每一個(gè)位置從(1,1)變成(2,2)形狀,區(qū)域還是那個(gè)區(qū)域。或者反過(guò)來(lái),(4,4)分成4份,每一份就是(2,2)。 用一張純手圖對(duì)上述文字作說(shuō)明(原諒我整了個(gè)手繪就放上來(lái)了) 
元素 |
初始位置 (b, h, w, (p1 * p2 * c)) |
拆分后的 (p1, p2, c) |
新位置(b, h * p1 + p1_index, w * p2 + p2_index, c)? |
1 |
(0, 0, 0, 0) |
(0, 0, 0) |
(0, 0 * 2 + 0, 0 * 2 + 0, 0) |
2 |
(0, 0, 0, 1) |
(0, 1, 0) |
(0, 0 * 2 + 0, 0 * 2 + 1, 0) |
3 |
(0, 0, 0, 2) |
(1, 0, 0) |
(0, 0 * 2 + 1, 0 * 2 + 0, 0) |
4 |
(0, 0, 0, 3) |
(1, 1, 0) |
(0, 0 * 2 + 1, 0 * 2 + 1, 0) |
5 |
(0, 0, 1, 0) |
(0, 0, 0) |
(0, 0 * 2 + 0, 1 * 2 + 0, 0) |
6 |
(0, 0, 1, 1) |
(0, 1, 0) |
(0, 0 * 2 + 0, 1 * 2 + 1, 0) |
7 |
(0, 0, 1, 2) |
(1, 0, 0) |
(0, 0 * 2 + 1, 1 * 2 + 0, 0) |
8 |
(0, 0, 1, 3) |
(1, 1, 0) |
(0, 0 * 2 + 1, 1 * 2 + 1, 0) |
9 |
(0, 1, 0, 0) |
(0, 0, 0) |
(0, 1 * 2 + 0, 0 * 2 + 0, 0) |
10 |
(0, 1, 0, 1) |
(0, 1, 0) |
(0, 1 * 2 + 0, 0 * 2 + 1, 0) |
11 |
(0, 1, 0, 2) |
(1, 0, 0) |
(0, 1 * 2 + 1, 0 * 2 + 0, 0) |
12 |
(0, 1, 0, 3) |
(1, 1, 0) |
(0, 1 * 2 + 1, 0 * 2 + 1, 0) |
13 |
(0, 1, 1, 0) |
(0, 0, 0) |
(0, 1 * 2 + 0, 1 * 2 + 0, 0) |
14 |
(0, 1, 1, 1) |
(0, 1, 0) |
(0, 1 * 2 + 0, 1 * 2 + 1, 0) |
15 |
(0, 1, 1, 2) |
(1, 0, 0) |
(0, 1 * 2 + 1, 1 * 2 + 0, 0) |
16 |
(0, 1, 1, 3) |
(1, 1, 0) |
(0, 1 * 2 + 1, 1 * 2 + 1, 0) |
其實(shí)這里有一個(gè)有趣的地方,如果?'b h w (p1 p2 c)-> b (h p1) (w p2) c'?被改成了?'b h w (p1 p2 c)-> b (h p2) (w p1) c'?會(huì)發(fā)生甚么事情?我們舉個(gè)最簡(jiǎn)單的例子作為結(jié)束。
原來(lái)的結(jié)果如果是?





實(shí)際上,我在和師兄探討這個(gè)映射關(guān)系具體是什么的時(shí)候,師兄的意思是不求甚解,原因是這只是一個(gè)工具,我們知道怎么用即可,不必深究。其實(shí)從科研效率的角度上來(lái)講,師兄說(shuō)得完全正確。人的時(shí)間和精力是有限的,需要投入到最緊要的事情上。但我認(rèn)為在rearrange這個(gè)上花費(fèi)的時(shí)間是有意義的。理由如下: 其一,二維圖像的分塊與重排的確非常重要,例如卷積操作的滑動(dòng)窗口其實(shí)本質(zhì)上就是一種分塊,而由于圖像內(nèi)目標(biāo)的大小、形狀等存在差異,實(shí)際上不同的分塊策略會(huì)對(duì)模型性能有影響,了解張量重排的映射關(guān)系對(duì)于深入理解卷積神經(jīng)網(wǎng)絡(luò)是有益處的。 其二,目前深度學(xué)習(xí)已經(jīng)發(fā)展了很多年,以發(fā)論文為例,審稿人的口味越來(lái)越刁鉆,簡(jiǎn)單的增刪改模塊已經(jīng)難以發(fā)表好論文。我認(rèn)為想要有所收獲,一方面是深度,需要對(duì)原理有更深入的理解,從而有所改良;另一方面是廣度,需要旁征博引,他山之石可以攻玉。
綜上所述,科研本就是需要不斷學(xué)習(xí),你也不知道今天學(xué)的東西能否用上,這個(gè)確實(shí)是玄學(xué)。但是如果有興趣有精力有時(shí)間,還是要深入探討一下,否則以后不管是進(jìn)入業(yè)界做項(xiàng)目還是進(jìn)入高校教書(shū)育人,對(duì)本領(lǐng)域的知識(shí)還是得學(xué)學(xué)許昕,“還是太全面了” 終歸是好詞。

