PyTorch デザインノート : ブロードキャスト・セマンティクス

PyTorch デザインノート : ブロードキャスト・セマンティクス (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 05/23/2018 (0.4.0)

* 本ページは、PyTorch Doc Notes の – Broadcasting semantics を動作確認・翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、適宜、追加改変している場合もあります。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

本文

多くの PyTorch 演算は NumPy ブロードキャスト・セマンティクスをサポートします。

簡潔に言えば、PyTorch 演算がブロードキャストをサポートするのであれば、その Tensor 引数は (データのコピーを行なうことなしに) 同じサイズになるように自動的に expand されます (= 広げられます)。

 

一般的なセマンティクス

次のルールが保持される場合、2 つの tensor は “ブロードキャスト可能 (= broadcastable)” です :

  • 各 tensor は少なくとも 1 次元を持つ。
  • 次元サイズに渡り iterate するとき、末尾次元から初めて、次元サイズが同じか、それらの 1 つが 1 か、それらの 1 つが存在しない。

例えば :

>>> x=torch.empty(5,7,3)
>>> y=torch.empty(5,7,3)
# 同じ shape は常にブロードキャスト可能です (i..e 上のルールが常に保持されます)

>>> x=torch.empty((0,))
>>> y=torch.empty(2,2)
# x と y はブロードキャスト可能ではありません、何故ならば x は少なくとも 1 次元を持たないからです

# can line up trailing dimensions
>>> x=torch.empty(5,3,4,1)
>>> y=torch.empty(  3,1,1)
# x と y はブロードキャスト可能。
# 1st 末尾次元: 両者はサイズ  1 を持つ
# 2nd 末尾次元: y がサイズ 1 を持つ
# 3rd 末尾次元: x サイズ == y サイズ
# 4th 末尾次元: y 次元は存在しない

# しかし:
>>> x=torch.empty(5,2,4,1)
>>> y=torch.empty(  3,1,1)
# x と y はブロードキャスト可能ではありません、何故ならば 3rd 末尾次元で 2 != 3

2 つの tensor x, y が “ブロードキャスト可能” である場合、結果の tensor サイズは次のように計算されます :

  • x と y の次元の数が同じでない場合、それらを同じ長さにするためにより少ない次元を持つ tensor の次元の先頭に 1 を追加します。
  • それから、各次元サイズについて、結果の次元サイズはその次元に沿って x と y のサイズの最大値です。

例えば :

# can line up trailing dimensions to make reading easier
>>> x=torch.empty(5,1,4,1)
>>> y=torch.empty(  3,1,1)
>>> (x+y).size()
torch.Size([5, 3, 4, 1])

# but not necessary:
>>> x=torch.empty(1)
>>> y=torch.empty(3,1,7)
>>> (x+y).size()
torch.Size([3, 1, 7])

>>> x=torch.empty(5,2,4,1)
>>> y=torch.empty(3,1,1)
>>> (x+y).size()
RuntimeError: The size of tensor a (2) must match the size of tensor b (3) at non-singleton dimension 1

 

In-place セマンティクス

ひとつのやっかいな問題は in-place 演算は in-place tensor にブロードキャストの結果として shape を変更することを許さないことです。

例えば :

>>> x=torch.empty(5,3,4,1)
>>> y=torch.empty(3,1,1)
>>> (x.add_(y)).size()
torch.Size([5, 3, 4, 1])

# but:
>>> x=torch.empty(1,3,1)
>>> y=torch.empty(3,1,7)
>>> (x.add_(y)).size()
RuntimeError: The expanded size of the tensor (1) must match the existing size (7) at non-singleton dimension 2.

 

後方互換性

PyTorch の以前のバージョンは、各 tensor の要素数が同じである限りは、特定の pointwise 関数に異なる shape を持つ tensor 上で実行することを可能にしていました。そして pointwise 演算は各 tensor を 1-次元として見ることにより実行されます。今では PyTorch はブロードキャストをサポートして “1-次元” pointwise の挙動は deprecated と考えられます、そして tensor がブロードキャスト可能ではなく、しかし同じ要素数を持つケースでは Python 警告を生成するでしょう。

2 つの tensor が同じ shape を持たずに、しかしブロードキャスト可能で同じ要素数を持つケースではブロードキャストの導入は後方非互換な変更を引き起こせることに注意してください。例えば :

>>> torch.add(torch.ones(4,1), torch.randn(4))

は以前はサイズ : torch.Size([4,1]) の Tensor を生成していましたが、今ではサイズ : torch.Size([4,4]) の Tensor を生成します。貴方のコードでブロードキャストにより導入された後方非互換が存在するかもしれないケースを識別する手助けをするためには、torch.utils.backcompat.broadcast_warning.enabled を True に設定することができます、これはそのような場合に python 警告を生成するでしょう。

例えば :

>>> torch.utils.backcompat.broadcast_warning.enabled=True
>>> torch.add(torch.ones(4,1), torch.ones(4))
__main__:1: UserWarning: self and other do not have the same shape, but are broadcastable, and have the same number of elements.
Changing behavior in a backwards incompatible manner to broadcasting rather than viewing as 1-dimensional.

 

 

以上