einops 張量操作

語言: CN / TW / HK

 

pip install einops

 

from einops import rearrange, reduce, repeat # 按給出的模式重組張量

output_tensor = rearrange(input_tensor, 't b c -> b c t') # 結合重組(rearrange)和reduction操作

output_tensor = reduce(input_tensor, 'b c (h h2) (w w2) -> b h w c', 'mean', h2=2, w2=2) # 沿著某一維複製

output_tensor = repeat(input_tensor, 'h w -> h w c', c=3)

 

重新考慮和上面相同的例子:

y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
y = rearrange(x, 'b c h w -> b (c h w)')
  •  

第二行檢查了輸入資料擁有四個維度(當然你也可以指定其他數字)
這和僅僅寫註釋標明資料維度是很不一樣的,畢竟據我們所知,註釋不能執行也無法阻止錯誤發生

y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
y = rearrange(x, 'b c h w -> b (c h w)', c=256, h=19, w=19)

 

更多的檢查

重新考慮和上面相同的例子:

y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
y = rearrange(x, 'b c h w -> b (c h w)')
  • 1
  • 2

第二行檢查了輸入資料擁有四個維度(當然你也可以指定其他數字)
這和僅僅寫註釋標明資料維度是很不一樣的,畢竟據我們所知,註釋不能執行也無法阻止錯誤發生

y = x.view(x.shape[0], -1) # x: (batch, 256, 19, 19)
y = rearrange(x, 'b c h w -> b (c h w)', c=256, h=19, w=19)
  • 1
  • 2

對輸出的嚴格定義

下面有兩種將張量深度轉換為廣度(depth-to-space)的方式

# depth-to-space
rearrange(x, 'b c (h h2) (w w2) -> b (c h2 w2) h w', h2=2, w2=2)
rearrange(x, 'b c (h h2) (w w2) -> b (h2 w2 c) h w', h2=2, w2=2)
  • 1
  • 2
  • 3

並且我們至少還有其他的四種方式來進行這種“深度-廣度”的轉換。哪一種是被框架使用的呢?

這些細節往往會被忽略,因為一般情況下,這些做法不會有什麼區別。
但是有時這些細節能有很大的影響(例如使用分組卷積的時候)。
所以你會希望可以在自己程式碼裡講清楚這個操作。

一致性

reduce(x, 'b c (x dx) -> b c x', 'max', dx=2)
reduce(x, 'b c (x dx) (y dy) -> b c x y', 'max', dx=2, dy=3)
reduce(x, 'b c (x dx) (y dy) (z dz)-> b c x y z', 'max', dx=2, dy=3, dz=4)
  • 1
  • 2
  • 3

上面這些例子展示了無論是幾維的張量池化,我們都使用一致的操作,而不會因為張量維度的改變而有不同介面。

廣度-深度 或者 深度-廣度 的轉化在許多框架中都有定義,那 寬度-高度 呢?

rearrange(x, 'b c h (w w2) -> b c (h w2) w', w2=2)
  • 1

與具體框架無關的行為表現

即使是很簡單的函式在不同的框架裡也往往有不同的寫法。

y = x.flatten() # 或者 flatten(x)
  • 1

假設張量x的形狀(shape)是(3,4,5),那麼y的形狀可能是:

  • 在numpy, cupy, chainer, pytorch中: (60,)
  • 在keras, tensorflow.layers, mxnet 和 gluon中: (3, 20)

與框架使用的具體術語無關

舉個栗子:tailrepeat常常會令人困擾。當你要沿著寬度複製圖片時,你要:

np.tile(image, (1, 2))    # 在numpy中
image.repeat(1, 2)        # pytorch的repeat ≈ numpy的tile
  • 1
  • 2

而使用einops的話,你甚至不需要研究要哪個維度的資料被複制了:

 

分享到: