もう先週になりますがpytorch0.4が出ました。
自分がpytorchを使い始めたのは0.3以降なので初めてのメジャー(?)バージョンアップになります。
1.0以下のバージョンアップはやはり安定しないもので、大きな変更がいくつかありますね。
主な変更点
- TensorとVariableの統合
- ゼロ次元テンソル
- dtypesとtesnorsの導入
- advanced indexingの完全サポート
- FFT
- 計算グラフのチェックポイント機能
- ボトルネック分析機能
- 確率分布の拡充
- ONNXでRNNのサポート
- winodes対応
TensorとVariableの統合
0.4以降は何回もVariable(x)
なんて書く必要がなくなりました!
Tensor
に計算グラフを保持する機能が追加され、backwardすることが出来ます。
>>> x = torch.DoubleTensor([1,2,3])
>>> x
tensor([ 1., 2., 3.], dtype=torch.float64)
>>> x.requires_grad
False
デフォルトだとrequires_grad=False
となっており計算グラフを保持してくれないので、有効にするためにはmy_tensor.requires_grad_(requires_grad=True)
を呼び出すか、有効な状態で作成する必要があります。
>>> x.requires_grad_()
tensor([ 1., 2., 3.], dtype=torch.float64)
>>> x.requires_grad
True
>>> y = torch.ones(1, requires_grad=True)
>>> y.requires_grad
True
いままでVariable
からTensor
を取り出すために.data
を使っていたと思いますが、0.4では.data
はrequires_grad=False
となったTensor
を返すようになります。
>>> yd = y.data
>>> yd.requires_grad
False
ただ、.data
で計算グラフの途中のノードを参照して変更を行った場合逆伝播時に問題が起きるらしく、葉ノードを生成する.detach()
の使用が推奨されているようです。(ここらへん良く理解できいなので後で調べます。)
ゼロ次元テンソル
いままではスカラーを表すテンソルは存在せず、長さ1のベクトルを代用していました。
なのでスカラ値を示すテンソルが出来ました。以上。
>>> a = torch.tensor(1)
>>> a
tensor(1)
>>> a.size()
torch.Size([])
これに伴いいくつかの関数の返り値が変わります。
>>> b = torch.arange(1,5)
>>> b
tensor([ 1., 2., 3., 4.])
>>> b.sum()
tensor(10.)
ゼロ次元テンソルからpythonの値を取り出す場合、.item()
を使います。
loss.data[0]
と書く必要がなくなりました。
というより、ゼロ次元なのでindexingすると警告が出ます。0.5でエラーになるようです。
>>> loss.item()
1
>>> loss.data[0]
__main__:1: UserWarning: invalid index of a 0-dim tensor. This will be an error in PyTorch 0.5. Use tensor.item() to convert a 0-dim tensor to a Python number
tensor(1)
dtypes等の導入
Numpyに似たテンソルの作成方法が出来るようになりました。
いままでFloatTensor
などテンソルの作成にはクラスごとに使い分けていたのが、tensor
の引数を変えることで出来るようになります。
>>> device = torch.device('cpu')
>>> torch.tensor([1,2,3], dtype=torch.float32, device=device)
tensor([ 1., 2., 3.])
>>> torch.randn(3, dtype=torch.float32, device=device)
tensor([ 1.6814, -0.6660, 0.7717])
dtype
、device
、layout
をそれぞれ指定出来ます。
- dtypeは型を表します
-
torch.float32
やtorch.int32
など
-
- deviceは作成する場所を表します
-
cpu
やcuda:0
などで指定します。cuda
と指定した場合デフォルトのGPUを使用します
-
- layoutはテンソルのレイアウト(?)を表します
- 現状密なテンソル(torch.strided)と疎なテンソル(torch.sparse_coo)が存在します
また.cuda
の代わりに.to(device)
というのが導入されました。
CPUとGPUの両方で使えるコードを以下のように作れます。
# いままで
model = Model()
if use_cuda:
model = model.cuda()
# 0.4以降
device = torch.device('cuda:0') # or 'cpu'
model = model.to(device)
deviceを共有することで、条件分岐などを無くスッキリ書けます。
advanced indexing
Numpyのadvanced indexingが使えるようになりました。
ブロードキャストなどです。
numpy芸は出来ないので、なにが出来るようになったのか実感がないですが、便利なのでしょう。
計算グラフのチェックポイント
ニューラルネットワークの計算時には逆伝播のために計算結果をすべて保持する必要がありメモリを大変食います。
そこで、一度計算結果を捨てて逆伝播の時に必要となったら再計算することで使用メモリを減らすチェックポイントを作れるようになりました。
再計算するため訓練速度は落ちますが、重いのは大抵逆伝播の処理なので訓練時間が数倍になったりはしないと思います。
プロファイリングのためのツールの追加
ボトルネックを見つけるためのtorch.utils.bottleneck
が追加されたようです。
0.3の時点でGPU usageを見るものはあった気がしますがどう変更されたのか気になりますね。
bottleneck docs
その他細かい変更
einsumの導入
tensorflowで使えたenisumが使えるようになりました。
>>> w = torch.tensor([[1,2], [2,3]])
>>> v = torch.tensor([3,4])
>>> torch.einsum('ik,k->i', (w, v))
tensor([ 11, 18])
速度的にどうなのか分かりませんが、複雑な演算をしたい時に便利です。