PyTorch 0.4.0 リリースノート

PyTorch 0.4.0 リリースノート (翻訳)

翻訳 : (株)クラスキャット セールスインフォメーション
日時 : 04/27/2018

* 本ページは github PyTorch の releases の PyTorch 0.4.0 リリースノートに相当する、
“Trade-off memory for compute, Windows support, 24 distributions with cdf, variance etc., dtypes, zero-dimensional Tensors, Tensor-Variable merge, , faster distributed, perf and bug fixes, CuDNN 7.1” を翻訳したものです:

 

重要なコアの変更

ユーザが日々使う最も重要な中心的な特徴への更新の要約がここにあります。

重要な変更と潜在的に互換性を損なう変更 :

  • Tensor と Variable がマージされました。
  • 幾つかの演算は今では 0-次元 (スカラー) Tensor を返します。
  • volatile フラグの deprecation。

改良:

  • dtypes, devices, そして Numpy-スタイル Tensor 作成関数が追加されました。
  • デバイス不可知論者 (= agnostic) コードを書くためのサポート。

マイグレーション・ガイド を書きました、これは貴方のコードを新しい API とスタイルに移行することを手助けするはずです。マイグレートしたい PyTorch の以前のバージョンでのコードを持つ場合にはそれを読んでください。

このセクション (重要なコアの変更) の内容はマイグレーション・ガイドに含まれています。

 

Tensor と Variable クラスのマージ

torch.autograd.Variable と torch.Tensor は今では同じクラスです。より正確には、torch.Tensor は history を追跡することが可能で古い Variable のように振る舞います ; Variable ラッピングは以前のように動作し続けますが torch.Tensor のオブジェクト型を返します。これは、貴方のコードの至るところで Variable ラッパーがもう必要ないことを意味します。

Tensor の type() の変更

Tensor の type() はもはやデータ型を反映しないことにもまた注意してください。代わりに isinstance() か x.type() を使用してください :

>>> x = torch.DoubleTensor([1, 1, 1])
>>> print(type(x)) # was torch.DoubleTensor
<class 'torch.autograd.variable.Variable'>
>>> print(x.type())  # OK: 'torch.DoubleTensor'
'torch.DoubleTensor'
>>> print(isinstance(x, torch.DoubleTensor))  # OK: True
True

今では autograd はいつ history の追跡を開始しますか?

requires_grad, autograd のための中心的なフラグ, は今では Tensor の属性です。

この変更がコードでどのように現れるかを見てみましょう。

autograd は Variable のために以前に使われた同じルールを使用します。それは演算の任意の入力 Tensor が requires_grad=True を持つときに history の追跡を開始します。例えば、

>>> x = torch.ones(1)  # create a tensor with requires_grad=False (default)
>>> x.requires_grad
False
>>> y = torch.ones(1)  # another tensor with requires_grad=False
>>> z = x + y
>>> # both inputs have requires_grad=False. so does the output
>>> z.requires_grad
False
>>> # then autograd won't track this computation. let's verify!
>>> z.backward()
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
>>>
>>> # now create a tensor with requires_grad=True
>>> w = torch.ones(1, requires_grad=True)
>>> w.requires_grad
True
>>> # add to the previous result that has require_grad=False
>>> total = w + z
>>> # the total sum now requires grad!
>>> total.requires_grad
True
>>> # autograd can compute the gradients as well
>>> total.backward()
>>> w.grad
tensor([ 1.])
>>> # and no computation is wasted to compute gradients for x, y and z, which don't require grad
>>> z.grad == x.grad == y.grad == None
True
requires_grad フラグを操作する

属性を直截的に設定する他に、my_tensor.requires_grad_(requires_grad=True) を使用してこのフラグを in-place に変更できます、あるいは上のサンプル内で、作成時に引数 (デフォルトは False) をそれに渡すことによっても (設定可能です), e.g.,

>>> existing_tensor.requires_grad_()
>>> existing_tensor.requires_grad
True
>>> my_tensor = torch.zeros(3, 4, requires_grad=True)
>>> my_tensor.requires_grad
True

.data についてはどうでしょう?

.data は Variable から基礎的な Tensor を得るための主要な方法でした。このマージ後、y = x.data の呼び出しは依然として同様のセマンティクスを持ちます。従って y は x と同じデータを共有する Tensor で、x の計算 history とは関係なく、requires_grad=False を持ちます。

けれども、幾つかのケースでは安全ではないかもしれません。x.data 上の任意の変更は autograd により追跡されません、そして x が backward パスで必要とされるのであれば計算された勾配は正しくないでしょう。より安全な代替は x.detach() を使用することです、これはまた requires_grad=False を持つデータを共有する Tensor を返しますが、x が backward で必要とされる場合には autograd により報告されたその in-place 変更を持ちます。

 

幾つかの演算は今では 0-次元 (スカラー) Tensor を返します

以前は、Tensor ベクトル (1-次元 tensor) へのインデキシングは Python 数値を与えていましたが、Variable ベクトルへのインデキシングはサイズ (1,) のベクトルを与えていました (矛盾です!) ! 同様の挙動は reduction 関数でも存在します、i.e. tensor.sum() は Python 数値を返しますが、variable.sum() はサイズ (1,) のベクトルを返します。

幸い、このリリースは PyTorch で正しいスカラー (0-次元 tensor) サポートを導入します! スカラーは新しい torch.tensor 関数を使用して作成できます (これは後でより詳細に説明されます ; 今のところはそれを numpy.array の PyTorch 同値として単に考えてください)。今ではこのようなことができます :

>>> torch.tensor(3.1416)         # create a scalar directly
tensor(3.1416)
>>> torch.tensor(3.1416).size()  # scalar is 0-dimensional
torch.Size([])
>>> torch.tensor([3]).size()     # compare to a vector of size 1
torch.Size([1])
>>>
>>> vector = torch.arange(2, 6)  # this is a vector
>>> vector
tensor([ 2.,  3.,  4.,  5.])
>>> vector.size()
torch.Size([4])
>>> vector[3]                    # indexing into a vector gives a scalar
tensor(5.)
>>> vector[3].item()             # .item() gives the value as a Python number
5.0
>>> sum = torch.tensor([2, 3]).sum()
>>> sum
tensor(5)
>>> sum.size()
torch.Size([])

損失の累積

0.4.0 以前の広く使用されるパターン total_loss += loss.data[0] を考えます。loss は size(1,) の tensor をラッピングする Variable でしたが、0.4.0 では loss は今ではスカラーであり 0 次元を持ちます。スカラーへのインデキシングは意味を持ちません (それは今は警告を与えますが、0.5.0 ではハード・エラーになります) : スカラーから Python 数値を得るためには loss.item() を使用します。

損失を累積するとき Python 数値に変換しない場合には、貴方のプログラムでメモリ消費の増加を見るかもしれないことに注意してください。これは Python float として使用される上の式の右辺が、その一方でそれは今では 0-次元 Tensor であるからです。合計損失はこうして Tensor とそれらの勾配 history を蓄積します、これは必要とされるよりも遥かに長い間およそ巨大な autograd グラフを保持するかもしれません。

 

volatile フラグの deprecation

volatile フラグは今では deprecated で効果は持ちません。以前は、volatile=True を持つ Variable を伴うどのような計算も autograd により追跡されませんでした。これは、torch.no_grad(), torch.set_grad_enabled(grad_mode), そしてその他を含む、より柔軟な コンテキスト・マネージャのセット で置き換えられました。

>>> x = torch.zeros(1, requires_grad=True)
>>> with torch.no_grad():
...     y = x * 2
>>> y.requires_grad
False
>>>
>>> is_train = False
>>> with torch.set_grad_enabled(is_train):
...     y = x * 2
>>> y.requires_grad
False
>>> torch.set_grad_enabled(True)  # this can also be used as a function
>>> y = x * 2
>>> y.requires_grad
True
>>> torch.set_grad_enabled(False)
>>> y = x * 2
>>> y.requires_grad
False

 

dtypes, devices そして NumPy-スタイルの作成関数

PyTorch の以前のバージョンでは、data type (e.g. float vs double), device type (cpu vs cuda) そして layout (dense vs sparse) を一緒に “tensor 型” として良く指定しました。例えば、torch.cuda.sparse.DoubleTensor は double data type、CUDA デバイス上に存在し、 そして COO sparse tensor layout を持つことを表わす Tensor type です。

このリリースでは、NumPy-スタイルの作成関数を通してこれらのプロパティのより良い管理を可能にするために torch.dtype, torch.device そして torch.layout クラスを導入します。

torch.dtype

以下は利用可能な torch.dtypes (data types) とそれらに対応する tensor type の完全なリストです。

データ型 torch.dtype Tensor 型
32-bit 浮動小数点 torch.float32 または torch.float torch.*.FloatTensor
64-bit 浮動小数点 torch.float64 または torch.double torch.*.DoubleTensor
16-bit 浮動小数点 torch.float16 または torch.half torch.*.HalfTensor
8-bit 整数 (unsigned) torch.uint8 torch.*.ByteTensor
8-bit 整数 (signed) torch.int8 torch.*.CharTensor
16-bit 整数 (signed) torch.int16 または torch.short torch.*.ShortTensor
32-bit 整数 (signed) torch.int32 または torch.int torch.*.IntTensor
64-bit 整数 (signed) torch.int64 または torch.long torch.*.LongTensor

浮動小数点 tensor のためのデフォルト dtype を操作するためには torch.set_default_dtypetorch.get_default_dtype を使用してください。

torch.device

torch.device はデバイス型 (‘cpu’ か ‘cuda’) と (デバイス型のための) オプションのデバイス ordinal (id) を含みます。それは torch.device(‘{device_type}’) または torch.device(‘{device_type}:{device_ordinal}’) で初期化できます。

もしデバイス ordinal が存在しない場合には、これはデバイス型のための現在のデバイスを表します ; e.g., torch.device(‘cuda’) は torch.device(‘cuda:X’) と同値です、ここで X は torch.cuda.current_device() の結果です。

torch.layout

torch.layout は Tensor のデータ・レイアウトを表します。Currentlytorch.strided (dense tensor) と torch.sparse_coo (COO フォーマットを持つ sparse tensor) がサポートされます。

 

Tensor を作成する

Tensor を作成するメソッド は今では返される Tensor 上の望まれる属性を指定するために dtype, device, layout, そして requires_grad オプションを取ります。例えば、

>>> device = torch.device("cuda:1")
>>> x = torch.randn(3, 3, dtype=torch.float64, device=device)
tensor([[-0.6344,  0.8562, -1.2758],
        [ 0.8414,  1.7962,  1.0589],
        [-0.1369, -1.0462, -0.4373]], dtype=torch.float64, device='cuda:1')
>>> x.requires_grad  # default is False
False
>>> x = torch.zeros(3, requires_grad=True)
>>> x.requires_grad
True

torch.tensor

torch.tensor は新たに追加された tensor 作成メソッド の一つです。総ての種類の array like なデータを取り含まれる値を新しい Tensor にコピーします。以前に言及したように torch.tensor はNumPy の numpy.array コンストラクタの PyTorch の同値です。torch.*Tensor とは違い、0-次元 Tensor (aka スカラー) もまたこのように作成できます (単一の python 数値は torch.*Tensor メソッドの Size として扱われます)。更に、もし dtype 引数が与えられない場合には、それはデータが与えられたとして適合する dtype を推論します。それは Python リストのような既存のデータから tensor を作成するための推奨される方法です。例えば、

>>> cuda = torch.device("cuda")
>>> torch.tensor([[1], [2], [3]], dtype=torch.half, device=cuda)
tensor([[ 1],
        [ 2],
        [ 3]], device='cuda:0')
>>> torch.tensor(1)               # scalar
tensor(1)
>>> torch.tensor([1, 2.3]).dtype  # type inferece
torch.float32
>>> torch.tensor([1, 2]).dtype    # type inferece
torch.int64

私達はまた更に tensor 作成メソッドを追加しました。それらの幾つかは torch.*_like and/or tensor.new_* の変形を持ちます。

  1. torch.*_like は shape の代わりに入力 Tensor を取ります。それは (指定されない限りは) デフォルトでは入力 Tensor と同じ属性を持つ Tensor を返します :
    >>> x = torch.randn(3, dtype=torch.float64)
    >>> torch.zeros_like(x)
    tensor([ 0.,  0.,  0.], dtype=torch.float64)
    >>> torch.zeros_like(x, dtype=torch.int)
    tensor([ 0,  0,  0], dtype=torch.int32)
    
  2. tensor.new_* もまた tensor と同じ属性を持つ Tensor を作成できますが、それは常に shape 引数を取ります :
    >>> x = torch.randn(3, dtype=torch.float64)
    >>> x.new_ones(2)
    tensor([ 1.,  1.], dtype=torch.float64)
    >>> x.new_ones(4, dtype=torch.int)
    tensor([ 1,  1,  1,  1], dtype=torch.int32)
    

望まれる shape を指定するには、多くの場合タプル (e.g., torch.zeros((2, 3))) か variable 引数を使用できます。

名前 返される Tensor torch.*_like variant tensor.new_* variant
torch.empty 非初期化メモリ ✔ ✔
torch.zeros all zeros ✔ ✔
torch.ones 総て 1 ✔ ✔
torch.full 与えられた値で満たされます ✔ ✔
torch.rand i.i.d. 連続一様[0, 1) ✔
torch.randn i.i.d. 正規(0, 1) ✔
torch.randint i.i.d. 与えられた範囲の離散一様 ✔
torch.randperm {0, 1, …, n – 1} のランダム順列
torch.tensor 既存のデータ (リスト, NumPy ndarray, etc.) からコピー ✔
torch.from_numpy* NumPy ndarray から (コピーなしでストレージ共有)
torch.arange,
torch.range, そして
torch.linspace
与えられた範囲で uniformly spaced values
torch.logspace 与えられた範囲tで logarithmically spaced values
torch.eye 恒等行列

*: torch.from_numpy はその入力引数として NumPy ndarray を取るだけです。

 

デバイス不可知論 (= device-agnostic) なコードを書く

PyTorch の以前のバージョンはデバイス不可知論なコード (i.e. それは変更なしに CUDA-enabled と CPU-only マシンの両者上で実行可能) を書くことを困難にしていました。

PyTorch 0.4.0 はこれを2つの方法でより簡単にします :

  • Tensor の device 属性が総ての Tensor に torch.device を与えます (get_device は CUDA tensor のために動作するだけです)
  • オブジェクトを異なるデバイスに簡単に移動するために Tensor と Module の to メソッドが使用できます (コンテキストに基づいて cpu() か cuda() を呼び出さなければならない代わりに)

次のパターンを推奨します :

# at beginning of the script
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

...

# then whenever you get a new Tensor or Module
# this won't copy if they are already on the desired device
input = data.to(device)
model = MyModule(...).to(device)

 

Tensor

進んだインデキシングの完全なサポート

PyTorch は、numpy の進んだインデキシング・ルールに追随して今では進んだ (= advanced) インデキシングのための完全なサポートを持ちます。次のサンプルが今では可能です :

a = torch.rand(10, 10, 10, 10)

# the indexing elements can have other shapes than 1
b = a[[[3, 2]], :, [[1, 3]]]

# broadcasting also supported in the indices, as well as lists,
# negative indices, slices, elipses, numbers
c = a[[1, -2], 2:4, :, [1]]

# can also support tensors as indices
index = torch.tensor([2, 4])
d = a[index]

# and the indices can be on the GPU
# or CPU
e = a[index.cuda()]
f = a.cuda()[index]


mask = torch.rand(10) > 0.5
# we can now index with a mask that has fewer
# dimensions than the indexing tensor
c = a[mask, :5]

高速フーリエ変換

  • 新しい FFT メソッドを追加します。 #5856
  • torch.stft (短時間フーリエ変換) と hann/hamming/bartlett 窓関数を追加します。 #4095
  • *FFT のバッチ次元の任意の数をサポートします。 #6528

新しいそして更新された Torch 演算子

  • torch.log2 と torch.log10 を追加しました。 #6272
  • torch.isnan を追加しました。#5273
  • torch.reshape を追加します、これは numpy.reshape に似ています。これは tensor.contiguous().view() におおよそ同値ですが、あるケースではコピーを回避します。 #5575
  • torch.unique の CPU 実装を追加します、これは Tensor の unique な要素を出力します。 #5503
  • torch.det, torch.logdet と torch.slogdet を追加します、正方 2D tensor の (log-) 行列式 を計算するためです。負の行列式のためには、torch.logdet は nan を返します、一方で torch.slogdet は log-行列式の符号と行列式の絶対値の log を返します。 #3816#5393
  • nn.functional.gumbel_softmax を追加します、これは離散変数のための reparametrization trick を使用することを可能にします。 #3341
  • torch.take と Tensor.put_ を追加します。それらの関数は numpy.take と numpy.put に同値で、PyTorch の進んだインデキシングの完全なサポートのための基礎です。 #3263
  • torch.randint を追加します、これは numpy.random.randint に類似しています。 #6136
  • torch.diagonal と torch.diagflat を追加します、これらは numpy.diagonal と numpy.diagflat に類似しています。それらは torch.diag の置き換えとして意図されています、これは対角 tensor の構築と行列の対角 (成分) の抽出の両者のケースを扱っていました。 #5622
  • torch.einsum を追加します、これは numpy.einsum に同値です。einsum は Einstein の記法を使用して演算を遂行することを可能にします。 #5503
    a = torch.arange(0, 9).reshape(3, 3)
    # the following transposes a
    b = torch.einsum('ij->ji', (a,))
    
  • torch.expm1 を追加します、小さい x に対して数値的安定な exp(x)-1 です。 #4350
  • torch.split で個々の split サイズを指定することを可能にします。 #3837
  • torch.where(condition, tensor1, tensor2) を追加します、これは条件に基づき tensor1 または tensor2 から選択された要素の tensor を返します。 #4259
  • 疎 tensor のために Tensor.norm(dim) を追加します。 #4882
  • 総ての型のために torch.neg を実装します。#4075
  • torch.trtrs のための勾配計算を実装します。 #3972
  • 不適当 (= out-of-place) な Tensor.resize と Tensor.resize_as を deprecate します。これらは奇妙なセマンティクスを持ち正しく使うことが困難です。それらの適切な変形 Tensor.resize_ と Tensor.resize_as_ を使用してください。 #4886

.cuda() の async 引数を non_blocking に名前変更します

conversion 呼び出しの async キーワード引数は今では PyTorch で deprecated です、そしてそれは non_blocking で置き換えられました。これが必要なのは async が Python 3.7 でキーワードとなるからです。

 

ニューラルネットワーク

新しい autograd コンテナはメモリのために計算をトレードすることを可能にします

新しい checkpoint コンテナは backpropagation に必要な出力のサブセットだけをストアすることを可能にします。(メモリをセーブするために) 出力が欠落している場合には checkpoint コンテナは中間出力を再計算するでしょう、その結果 (計算時間の増加と共に) メモリ消費量は削減できます 。ここにサンプルがあります :

# input
input = torch.rand(1, 10)
# suppose we have a very deep model
layers = [nn.Linear(10, 10) for _ in range(1000)]
model = nn.Sequential(*layers)
output = model(input)

上のモデルは多くのメモリを使用します、何故ならばそれは backpropagation のための総ての演算の中間値を保持する必要があるからです。checkpoint はメモリ要求を削減させます :

# create the input tensors and set the requires_grad=True
# NOTE: the requires_grad=True for the input is a current
# limitation of checkpointing. At least one of the 
# model inputs should have requires_grad=True. 
# If you don't do it, you might have empty gradients.
input = torch.rand(1, 10, requires_grad=True)
layers = [nn.Linear(10, 10) for _ in range(1000)]

# define function that will define where
# we will checkpoint and store
# intermediate gradients. In this case,
# we will only store one intermediate
# gradient, in the middle of the
# model

def run_first_half(*args):
    x = args[0]
    for layer in layers[:500]:
        x = layer(x)
    return x

def run_second_half(*args):
    x = args[0]
    for layer in layers[500:-1]:
        x = layer(x)
    return x

# now uses the new checkpoint functionality
from torch.utils.checkpoint import checkpoint

x = checkpoint(run_first_half, input)
x = checkpoint(run_second_half, x)
# last output need to be run without checkpoint
x = layers[-1](x)
x.sum.backward()  # works!

sequential モジュール (これは任意のブロックを内部に持つことができます) のために、ヘルパー関数 checkpoint_sequential が提供されます、これは最も一般的なユースケースをケアします :

input = torch.rand(1, 10, requires_grad=True)
layers = [nn.Linear(10, 10) for _ in range(1000)]
model = nn.Sequential(*layers)

from torch.utils.checkpoint import checkpoint_sequential

# split in two blocks
num_segments = 2
x = checkpoint_sequential(model, num_segments, input)
x.sum().backward()  # works!

 

bottleneck – 貴方のコードのホットスポットを確認します

torch.utils.bottleneck (#5216, #6425) は貴方のプログラムのボトルネックをデバッグするための初期ステップとして使用できるツールです。それは Python profiler と PyTorch の autograd profiler を持つ貴方のスクリプトの実行を要約します。より詳細のためには bottleneck docs を見てください。

reduce=False 損失

このリリースの時点で、総ての損失関数は reduce キーワードをサポートします。reduce=False の指定は単一の reduced 損失の代わりに損失のユニットあたりの Tensor を与えます。

#4924, #5346, #5646, #4231, #4705, #5680

 

新しいモジュールとモジュール改良

  • DistributedDataParallelCPU を追加します。これは DistributedDataParallel に類似していますが、(GPU を対象とする DistributedDataParallel とは反対に) CPU 上で動作するモデルのための特定のサポートを持ち、mpi, gloo と tcp backends をサポートします。 #5919
  • Group 正規化 (nn.GroupNorm) を追加します、バッチ正規化の代替で小さいバッチサイズのための BatchNorm のような同じ問題を受けません。
  • Layer 正規化 (nn.LayerNorm) を追加します、NLP タスクでしばしば使用されるバッチ正規化のための代替です。 #4922
  • Local Response 正規化 (nn.LocalResponseNorm) を追加します。 #4922
  • MaxPool3d は今では double backwards をサポートします。MaxPool3d と MaxUnpool3d は今では残りのプーリング層と一貫するインデックスを使用します。 #5328
  • 総ての損失関数は今では損失のバッチを返す reduce 引数をサポートします。 #264
  • torch.nn.utils.clip_grad の勾配値をクリップして torch.nn.init の He 初期化スキームへの param を追加するための util を追加します。 #6173
  • torch.nn.init.* メソッドを最後にアンダースコアを持つように名前変更します、それらが in-place で動作するからです、そして古いバージョンは depreate します。 #6093
  • DataParallel で辞書を返すためのサポートを追加しました。 #6113
  • torch.nn.Bilinear で N-D tensor のためのサポートを追加しました。 #5764
  • Embedding.from_pretrained ファクトリを追加します。これは Embedding 層をその重みの初期ランダム初期化をバイパスして、既存の tensor で初期化することを可能にします。
  • nn.Sequential, nn.ModuleList, と nn.ParameterList を今ではスライスできます。 #4491
  • 登録された nn.Module 整数パラメータとバッファは今では module.float(), module.double() module.half() 呼び出しの影響を受けません。 #3820

 

torch.distributions

torch.distributions は 24 の 基本的な確率分布 を含むように拡充されました : Bernoulli, Beta, Binomial, Categorical, Cauchy, Chi2, Dirichlet, Exponential, FisherSnedecor, Gamma, Geometric, Gumbel, Laplace, LogNormal, Multinomial, MultivariateNormal, Normal, OneHotCategorical, Pareto, Poisson, RelaxedBernoulli, RelaxedOneHotCategorical, StudentT, そして Uniform.

Distribution インターフェイスは .cdf(), .icdf(), .mean(), .variance(), .entropy(), そして .perplexity() を含む多くのメソッドを含むように拡充されました。Distributions は今では tensor 次元を sample_shape+batch_shape+event_shape に分割します。殆どの連続分布は今では pathwise derivative aka reparameterization trick を計算するために微分可能な .rsample() メソッドもまた実装します (利用可能性のためには .has_rsample を確認してください) :

>>> loc = torch.tensor(0., requires_grad=True)
>>> scale = torch.tensor(1., requires_grad=True)
>>> samples = Normal(loc, scale).rsample(sample_shape=(1000,))
>>> loss = (samples - 0.5).pow(4).mean()  # average over 1000 monte carlo samples
>>> grad(loss, [loc, scale])
(tensor(-7.5092), tensor(15.2704))

殆どの離散分布は総ての可能なサンプル値に渡り総計することを容易にするために .enumerate_support() メソッドを実装します (利用可能性のためには .has_enumerate_support を確認してください)。

kl_divergence は分布の多くのペアのために定義されています, e.g.

>>> x = torch.tensor(1.0, requires_grad=True)
>>> kl = kl_divergence(Uniform(-x, x), Normal(0., 1.))
>>> grad(kl, [x])[0]
tensor(-0.6667)

 

Distribution Transform

新しい分布は TransformedDistribution を (以下を含む) torch.distributions.transforms ライブラリからの任意の数の Transform オブジェクトと組み合わせることにより作成できます : ExpTransform, PowerTransform, SigmoidTransform, AbsTransform, AffineTransform, SoftmaxTransform, StickBreakingTransform, LowerCholeskyTransform, そして .inv プロパティを通したそれらの逆関数 (= inverses)。

 

Distribution 制約

Distribution はそれらの .support の制約とそれらの引数 (.arg_constraints) についてのメタデータを提供します。これらの Constraint オブジェクトは transform_to() と biject_to() を使用して transform で登録されます。constraint と transform は一緒に新しい分布を一般的な方法で指定することを容易にします。

>>> scale = torch.tensor(1., requires_grad=True)
>>> p = Normal(0., scale)
>>> assert p.arg_constraints['scale'] == constraints.positive
>>> prior = TransformedDistribution(Normal(0., 1.),
...                                 transform_to(constraints.positive))

torch.distributions.constraints ライブラリの Constraints は以下を含みます : boolean, greater_than(lower_bound), integer_interval(lower_bound, upper_bound), interval(lower_bound, upper_bound), lower_cholesky, lower_triangular, nonnegative_integer, positive, positive_definite, positive_integer, real, real_vector, simplex, そして unit_interval.

分散

分散訓練ジョブを launch するためのヘルパー・ユティリティ

分散セットアップ上でジョブを launch することを助けるためのユティリティ関数を追加しました。シングル・ノードかマルチ・ノード上で DistributedDataParallel を活用するスクリプトを launch するために、次のように torch.distributed.launch を利用できます。

python -m torch.distributed.launch my_script.py --arg1 --arg2 --arg3

スクリプトは分散パッケージの日々のユーザビリティを単純化します。

その利用方法についてはここで読むことができます : http://pytorch.org/docs/stable/distributed.html#launch-utility

NCCL 2.0 ベースの新しい分散バックエンド

PyTorch は今では新しい分散バックエンドを持ちます、これは最大限の速度のために NCCL 2.0 を活用します。それはまたマルチ GPU 上の集合的演算のための新しい API も提供します。
次を通して新しいバックエンドを有効にできます。

torch.distributed.init_process_group("nccl")

その他の分散改良

  • パフォーマンスを改善するために多くの小さなブロードキャストをまとめます。 #4978
  • 分散訓練のための混合精度サポートを追加します。 #4891
  • NCCL 分散バックエンドをリリースします。以前はそれは実験的とマークされていました。 #4921
  • 自動 IB デバイス検知を持つ Gloo データチャネルのためのインフィニバンド・サポートを有効にします。 #4795

C++ 拡張

以前は、カスタム・モジュールのための C または CUDA を使用して拡張を書く公式な方法は cffi 拡張を通すことでした。この方法の欠点は、それは CUDA カーネルをコンパイルするために別のステップを必要としたことで、これは少しやっかいだったかもしれません。

PyTorch は今では貴方自身の C++ / CUDA 拡張 を書くためのより良いシステムを提供します。この新しい拡張サポートを使用するサンプル実装は pytorch/cpp_extensions レポジトリで見つかります。

2つの compilation モードを提供します :

  • ahead of time compilation: setuptools.Extension モジュールの拡張である、新しい CppExtension か CUDAExtension を使用して setup.py スクリプトを書きます ;
  • just-in-time compilation: コンパイルすることを望む C++ / CUDA ファイルのリストを torch.utils.cpp_extension.load に渡して、それは貴方のために実行中に (= on the fly) コンパイルしてライブラリをキャッシュします。ここに拡張を実装することがどれほど簡単かを示すサンプルがあります :

In C++

// my_implementation.cpp
#include <torch/torch.h>
#include <unordered_set>

// can use templates as well. But let's keep it
// simple
using scalar_t = float;

at::Tensor unique_float(at::Tensor input_) {
  // only works for floats
  AT_ASSERT(input_.type().scalarType() == at::ScalarType::Float, "input must be a float tensor");
  // and CPU tensors
  AT_ASSERT(!input_.type().is_cuda(), "input must be a CPU tensor");
  
  // make the input contiguous, to simplify the implementation
  at::Tensor input = input_.contiguous();
  
  // get the pointer that holds the data
  scalar_t* input_data = input.data<scalar_t>();
  // let's use a function from the std library to implement
  // the unique function
  std::unordered_set<scalar_t> set(input_data, input_data + input.numel());
  
  // create the output tensor, with size set.size()
  at::Tensor output = input.type().tensor({static_cast<int64_t>(set.size())});
  scalar_t* output_data = output.data<scalar_t>();
  // copy the content of the set to the output tensor
  std::copy(set.begin(), set.end(), output_data);
  
  return output;
}

// this defines the functions exposed to Python
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  m.def("unique_float", &unique_float, "Unique for float tensors");
}

そしてそれから in Python

import torch
from torch.utils.cpp_extension import load as load_ext
# pass the source files, they will be compiled on the fly 
# and will return a python module
_C = load_ext('my_unique_lib', sources=['my_implementation.cpp'])

# now can use the functions implemented in C++
unique = _C.unique_float

a = torch.tensor([1.0, 2.0, 1.0])
print(unique(a))
# tensor([ 2.,  1.])

 

Windows サポート

PyTorch は今では公式に Windows をサポートします。事前コンパイルされた Conda バイナリと Python 3.5 と 3.6 のための pip wheel を提供します。PyTorch on Windows は分散訓練をサポートしませんし Linux / OSX よりもほんの少しだけ遅いかもしれません、これは Visual Studio が OpenMP のより古いバージョンをサポートするからです。

いつものように、Windows 上に PyTorch をインストールするために http://pytorch.org のコマンドを使用できます。
Windows まわりで持つであろう殆どの質問に答える FAQ をここで持ちます : http://pytorch.org/docs/stable/notes/windows.html

ONNX 改良

新しい ONNX 演算子

  • torch.max(input, dim) and torch.min(input, dim) の export をサポートします。 #6220
  • ONNX に export するサポートのため ReLU のシンボリックを追加します。 #5759
  • sum, prod, sqrt を追加して log_softmax を改良します。 #4579
  • InstanceNorm のための ONNX サポートを追加します。 #4626
  • Elu のための ONNX シンボリックを追加します。 #3453
  • UpsamplingNearest2d のための ONNX シンボリックを追加します。 #3450

改良

  • ONNX export が node について失敗するときソース位置をプリントします。 #5652
  • onnx protobuf バインディングを python に export します。 #6651
  • ConvTranspose で output_padding をサポートします。 #4583

より良い RNN サポート

  • PyTorch は今では RNN のサブセットを ONNX に export できます。 #4409
  • Elman RNN の ONNX への export を追加します。 #4613
  • パッドされた sequence の ONNX export で batch-first をサポートします。 #5360
  • Bidirectional Elman RNN の ONNX へのサポート。 #5120
  • RNN を ONNX へ export するとき sequence の長さを正しく処理します。 #4695
  • GRU の ONNX への export をサポートします。 #4390

バグ修正

  • 3d average pooling の ONNX シンボリックのバグを修正します。 #6101
  • replication/reflection pad の onnx export を修正します。 #4263

 

多方面の改良

  • Tensor のために __dir__ を実装します、その結果 editor は自動的に auto-complete して Tensor の可能なフィールドを問い合わせることができます。
  • numpy() と from_numpy() を HalfTensor に追加します。
  • TensorDataset が任意の数の入力 tensor を持つことを可能にします。
  • torch.nn.utils.rnn.pad_sequence に padding_value を追加します。
  • pack_padded_sequence に total_length を追加します、これは DataParallel を使用するとき有用です、というのは同じ長さの sequence を持つことを保証できるからです。
  • numpy.arange と一貫するように、torch.arange の数値精度を改良します。
  • torch.load() と torch.save() は任意のファイル-like オブジェクトをサポートします。
  • torch.nn.functional.grid_sample は今では 2D (spatial) と 3D (volumetric) 入力をサポートします。
  • 実験の再現性を改良するために、DataLoader ワーカーで python ランダム・シードを設定します。
  • nn.Sequential に __delitem__ を追加します。今では nn.Sequential の任意の要素を delete できます。
    例えば :
    model = nn.Sequential(nn.Linear(2, 2), nn.ReLU(), nn.Linear(2, 2))
    del model[1]  # deletes nn.ReLU
    
  • ReduceLROnPlateau は今ではシリアライズ可能です。 #5300
  • CPU 上の非正規数字をフラッシュするためのオプションを追加します。 #5294
  • PyTorch は今では入力と重みに関する conv1d, conv2d と conv3d の勾配を expose します。 #5408
  • リストか Tensor を持つ pack_padded_sequence を呼び出すためのサポートを追加します。 #5133
  • nn.Embedding の padding_idx のための負のインデキシングをサポートします。 #4496
  • pack_padded_sequence のための backward パスを実装します。 #4512
  • 0 を持つ可変長 Tensor のリストを pad して可変長 Tenosr のリストをパックするために nn.utils.rnn.pad_sequence と nn.utils.rnn.pack_sequence を追加します。
  • CUDA メモリ消費量をチェックするために torch.cuda.memory_cached, torch.cuda.max_memory_cached, torch.cuda.memory_allocated と torch.cuda.max_memory_allocated メソッドを追加します。 #4511
  • 新しい view size が tensor の元の size と stride と互換である場合は非連続 tensor 上の view を可能にします。 #4062
  • NLLLoss と CrossEntropyLoss は今では 2 次元以上をサポートします。 #4654
  • model_zoo ダウンロード進捗バーを表示しないようなオプションを追加します。 #4135
  • 今ではモジュールを nn.Sequential のインデックスに割り当てることができます。 #4931
  • numpy np.longlong 配列で tensor を作成することができます。 #4367
  • 良い heuristics を使用するために autograd 実行順序を変更します。これは巨大なモデルのためのメモリ使用量を大きく改良します。 #4746
  • AMSgrad モードを Adam と SparseAdam optmizer に追加します。 #4034
  • cudaEvent API を使用して CUDA profiling のためのより良い torch.autograd.profiler サポート。 #3734
  • torch.set_num_threads はまたそれぞれの MKL オプションを設定しますのでそれを制御するために環境変数を使用する必要はないでしょう。 #4949

 

パフォーマンス改良

  • CPU nn.EmbeddingBag を高速化します、これは訓練を全体を 30% より速くします。 #5433
  • nn.MarginRankingLoss, nn.CosineEmbeddingLoss, nn.HingeEmbeddingLoss, と nn.TripletMarginLoss を Python から私達の ATen バックエンドに移動します、幾つかのケースでは 3x パフォーマンス獲得上昇の結果になります。 #5346, #5646, #5080, #5680
  • pin_memory() を NativeFunction として実装します。 #4094
  • メモリをセーブするために、backward 計算のために self の代わりに self.numel() をセーブします。 #5747
  • 一つのケースでは 10x までのより良いパフォーマンスのために pointwise 演算のために次元を再配置します。 #4174
  • 小さい場合に 5-6x 高速化のために normal_ をベクトル化します。 #4312
  • Broadcast 演算のために PyTorch 内で GPU Direct の使用を可能にします。 #4183
  • 3D 入力ケースのために nn.Linear を高速化します。 #5279
  • vol2col と col2vol の並列化により CPU 上の Conv3D を高速化します。 #4824
  • sigmoid 関数のために AVX2 実装を追加します、およそ 10x の高速化を示します。 #5010
  • カーネル内の division ops を回避するために fast integer division アルゴリズムを使用します。 #5054
  • CUDA ランダム数生成のための専有を改良します。 #5710
  • 一般的な norm のために norm への最適化を追加します。 #5722
  • 高速 fused GLU backward を追加します。 #5782
  • std::set の代わりに std::vector+sort を使用することにより unique ソーティングを最適化します、これは 5x までの高速化を与えます。 #5913
  • 次元に渡る sum を高速化します。 #6026
  • MKLDNN convolution forward と backward を有効にします。 #6062
  • OpenMP を伴う不連続 point-wise 演算を並列化します。 #2764
  • Volta (訳注: GPU) のために RNN に cudnn Tensor Core ops を追加します。 #3409
  • exp, log, sin, cos のベクトル化。 #6078
  • 複数の backwards grad_inputs に渡る中間結果を再利用します。 #3526

分散

  • DistributedDataParallel: 混合精度サポートと共に NCCL backend perf の 10% 改良。 #5064
  • DistributedDataParallel (シングル-GPU バインディング) マルチプロセス分散訓練パフォーマンスを少し改良しました。 #4870

 

バグ修正

torch 演算子

  • torch.digamma の改良。 #6517
  • 負の入力上の Tensor.random_ の不正な挙動を修正します。 #6463
  • 負の次元を持つ tensor.permute(dims) のための backward パスにおける未定義の挙動を修正します。 #5945
  • torch.remainder 演算子における整数オーバーフローを修正します (それは 2**48 以上の除数で壊れるでしょう)。 #5906
  • torch.bmm におけるメモリリークを修正します。 #5744
  • scatter_ と一貫した scatter_add_ の次元チェッカーを作成します。 #5659
  • 不連続確率 tensor 入力を持つ CPU torch.multinomial を修正します (以前は、それは入力データを上書きするでしょう)。 #5093
  • 不正な stride を使用して zero-probability イベントを選択できる CUDA torch.multinomial を修正します。 #5774, #5238
  • index_select のために空のインデックス tensor をサポートします。 #3429
  • CUDA Tensor.put_ における空のインデックス tensor をサポートします。 #4486
  • 空の tensor を持つ torch.cat の安定性を改良します。 #3602, #5971, #5819
  • 任意の入力次元が整列されていないケースでの torch.fft を修正します。 #6118
  • CUDA btrifact エラー・メッセージを改良します。 #5644
  • torch.symeig でリクエストされていないとき固有ベクトル tensor のためにゼロを返します。 #3411
  • tensor 上の torch.btrifact を修正します。 #4318
  • tensor 上の torch.pstrf を修正します。 #4883
  • torch.median のメモリリークを修正します。 #6889
  • some=False のとき非正方行列上の SVD backward を修正します。 #6870

core

  • _C 共有ライブラリの最初期化を検出します、それはしばしば exit 上の segfault の結果になります。 #6232
  • 総て zero の ByteTensor を持つインデキシングを修正します。 #3926
  • デフォルトの tensor 型として dense 浮動小数点型のみを許します。 #5674
  • クラッシュを回避するために CUDA tensor 型をデフォルトとして設定する前に CUDA を初期化します。 #4788
  • CUDA が初期化されていない場合に from_dlpack が失敗するバグを修正します。 #4182
  • numpy 配列を持つ CUDA tensor を作成する際のクラッシュを修正します。 #5850
  • 幾つかの OS 上のマルチプロセッシングで空の tensor の壊れた共有を修正します。 #6229

autograd

  • allow_unused 機能の復旧: 微分された入力が未使用か非到達であるときにエラーを投げます。 #6553
  • 正しくインクリメントされない output_nr を修正します。これはある入力上で requires_grad しない演算の backward パスでクラッシュを引き起こしました。 #4812
  • torch.autograd.profiler における nvprof 解析を修正します。 #5840

nn 層

  • adaptive pooling のためにある次元で size だけの指定をサポートします。 #3127
  • 不正なメモリアクセスを引き起こさないように reflection padding 境界チェックを修正します。 #6438
  • NLLLoss に対するエラーメッセージを改良します。 #5299, #6072
  • CUDA 上の kl_div backward を修正します。以前は gradInput を計算するとき gradOutput を尊重しませんでした。 #5814
  • Linear に対する不正な bias size assert を修正します。 #5992
  • 不正な nn.functional.convNd と nn.functional.conv_transposeNd エラーメッセージを修正します。 #5701
  • 幾つかの損失関数に対して要素の数の代わりに入力とターゲットの shape が適合するかをチェックします。 #5085
  • 非正方入力で正方勾配を返す torch.diag backward を修正します。 #4538
  • convolution 型ミスマッチのエラーメッセージを修正します。 #5815
  • 線形補間 upsampling に align_corners オプションを追加してデフォルトの upsampling 挙動を他のフレームワークとより一貫させます。 #5927
  • log_input=False のとき poisson_nll_loss を伴う数値問題を回避します。 #3336

CUDA

  • CUDA ConvTranspose double backward を修正するために convolution 重みが連続することを確かなものにします。 #4543
  • CUDA double backwards を修正します。 #4460

sparse

  • sparse=True を持つ embedding を修正します。 #4686
  • 入力が padding_idx のみを含むとき sparse embedding backward を修正します。 #6211
  • 空の sparse tensors to/from CPU, GPU を処理します。 #5361

dataloader

  • torch.utils.data.Sampler クラスに引数チェックを追加し、DataLoader が非整数 batch_size 上で dataset 全体をロードしようとするバグを修正します。 #6249
  • batch_sampler が与えられたとき dataloader.batch_size = None を設定します、DataLoader が batch_size を 1 と報告するバグを修正します。 #6108
  • DataLoader におけるシグナル処理を改良します。 #4643
  • シャッティングダウンのとき FileNotFoundError を無視します。 #5380
  • preprocessing deterministic を作成します。 #4640

optim

  • ユーザビリティを改良するために optimizer 状態辞書をロードするときに tensor をキャストします。 #3658
  • load_state_dict() の安定性を改良するためにモデル・パラメータを deterministic 順序でリストします。 #6031
  • 総ての optimizer に対してパラメータ範囲チェックを追加します。 #6000
  • SparseAdam のために AMSGrad モードを修正します。 #4314

分散と multi-gpu

  • detach in place エラーにより引き起こされる多くの分散訓練エラーを修正します。 #5829
  • DataParallel を no_grad モードで実行するとき requires_grad を変更しません。 #5880
  • Distributed Data Parallel 安定性のための broadcast_coalesce のための GPU guard を追加します。 #5655
 

以上