ディープラーニングのフレームワークであるPyTorchをインストールしましたが、最初は右も左もわからない状態だと思います。そんな時はまず公式ページのチュートリアル「What is PyTorch?」で使い方を覚えましょう。
こんにちは。wat(@watlablog)です。PyTorchをインストールしたので、まずは公式の「What is PyTorch?」チュートリアルをなぞってみましょう!
PyTorch公式チュートリアルからはじめよう
チュートリアルをやる意義
PyTorchは数あるディープラーニングのフレームワークの中の1つです。
このページを書いている筆者は機械学習やディープラーニングを学び始めた初心者ですが、初心者の僕がPyTorchを選んだ理由は「ディープラーニング初心者がPyTorchを選んだ3つの理由」に記載しました。
もしこのページをご覧の皆様がまだ初心者でフレームワーク選びを迷っている場合は、少しだけ参考になるかも知れません。
しかし、ディープラーニングを学び始めたばかりの初学者にとって、
PyTorchインストールしたし、早速多層のニューラルネットワーク構築して画像分類でもしてみるか!
とはならないと思います。
なったら既に中級者以上です!
我々初心者は黙ってまず始めにチュートリアルをやりましょう!
公式のチュートリアルを学ぶことで自力で模索するよりも効率良く、正しい手順でフレームワークを使えるようになることが期待できます。
チュートリアル:60-minute blitz
PyTorchの公式チュートリアルは以下の公式チュートリアルの「Tutorials」からアクセス可能です。
PyTorch公式ページ:https://pytorch.org/
公式ページに行くと「60-minute blitzがスタートポイントです」と書いてあるので、まずは「Getting Started」にアクセスします。
60-minute blitzにアクセスすると、まず2分程度の動画説明があります。音声は英語ですが映像がわかりやすいので、英語が苦手でも雰囲気は掴めるのではと思います。
そして60-minute blitzの最初のチュートリアルが「What is PyTorch?」になります。まずはここからやりましょう。
チュートリアルを進めるためにはtorchとtorchvisionというライブラリが必要です。まだインストールしていない人は先ほどの「ディープラーニング初心者がPyTorchを選んだ3つの理由」という記事を参考にしてみて下さい。
挫折せずに進めるか…早速やってみましょう!
PyTorchでテンソルの計算をするコード
numpyのndarryも似たような構造ですが、torchのtensorを使うとGPUを使った高速化を行うことが可能です。
このGPU利用ができることがPyTorchを使う利点の1つです(僕はしばらくはCPUで計算しますが)。
What is PyTorch?ではテンソルの計算方法を習得します。
参考:テンソル(wiki)
初期化していないテンソルを新規に定義する
最初の例題は初期化していない空のテンソルを定義する方法です。
1 2 3 4 5 |
from __future__ import print_function import torch x = torch.empty(5,3) print(x) |
値を決めていないテンソルを定義すると、その時点でメモリにある値が割り当てられるとのこと。まずは無事以下のように結果を得ることができました。
1 2 3 4 5 |
tensor([[9.2755e-39, 1.0561e-38, 9.8265e-39], [1.0102e-38, 8.9082e-39, 5.9694e-39], [1.0286e-38, 8.9081e-39, 8.9082e-39], [6.9796e-39, 9.0919e-39, 9.9184e-39], [7.3470e-39, 1.0194e-38, 1.0469e-38]]) |
初期化されたテンソルを新規に定義する
次は初期化されたテンソルの定義方法です。
チュートリアルでは1つ1つ例題を出していましたが、特に説明が多く必要というわけではなさそうなので、ここではまとめて書いてみます。
(チュートリアル+αの内容もあります)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
from __future__ import print_function import torch # 初期化されたテンソルをそれぞれ定義 rand = torch.rand(5, 3) # 一様乱数 randn = torch.randn(5, 3) # 正規分布 perm = torch.randperm(5) # 1Dランダム整数 zeros = torch.zeros(5, 3, dtype=torch.long) # long型指定0テンソル ones = torch.ones(5, 3, dtype=torch.long) # long型指定1テンソル tensor = torch.tensor([5.5, 3]) # 直接入力 arange = torch.arange(1, 3, 0.5) # 間隔指定の1Dテンソル linspace = torch.linspace(1, 2.5, 4) # 個数指定の1Dテンソル # 結果表示 print('torch.rand= \n', rand) print('torch.randn= \n', randn) print('torch.randperm= \n', perm) print('torch.zeros= \n', zeros) print('torch.ones= \n', ones) print('torch.tensor= \n', tensor) print('torch.arange= \n', arange) print('torch.linspace= \n', linspace) |
randは一様分布で0-1の範囲を、randnは正規分布でランダムな値を定義します。
randpermは指定した数値内で1Dの整数値テンソルを返します。
zerosやonesで0テンソや1テンソルを作れますが、dtypeで型を指定できます。ここではlong型という整数型を指定しています。int型は使わないそうですが、今はあまり深くやりません。
tensorを使うと直接入力でテンソルを定義可能です。
arangeやlinspaceも使え、本当にnumpyライクに使うことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
torch.rand= tensor([[0.0400, 0.9957, 0.0213], [0.7365, 0.1370, 0.2012], [0.8986, 0.9743, 0.2462], [0.7866, 0.4598, 0.4114], [0.6234, 0.6180, 0.4880]]) torch.randn= tensor([[ 0.5146, 0.6025, -2.2834], [-0.4677, -0.8000, -0.0046], [-0.8517, 0.1622, 2.6702], [ 1.9978, 1.0253, 0.5615], [-0.4207, 2.1368, 0.0617]]) torch.randperm= tensor([4, 2, 0, 1, 3]) torch.zeros= tensor([[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]) torch.ones= tensor([[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]) torch.tensor= tensor([5.5000, 3.0000]) torch.arange= tensor([1.0000, 1.5000, 2.0000, 2.5000]) torch.linspace= tensor([1.0000, 1.5000, 2.0000, 2.5000]) |
既存のテンソルから新しいテンソルを定義
既に存在しているテンソルを使って新しいテンソルを作る方法も紹介されています。
1 2 3 4 5 6 7 8 9 10 11 |
from __future__ import print_function import torch x = torch.rand(5, 3) print(x) x = x.new_ones(5, 3) # 既存のテンソルから1テンソルを定義 print(x) x = torch.randn_like(x, dtype=torch.float) # 既存のテンソルのサイズで定義 print(x) |
特に_likeはrandn以外にもrand_like等他の種類のテンソルでも共通で使用可能です。
_likeを使用することで既存テンソルのサイズに合わせた新規テンソルを作成といったことも容易にできそうです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
tensor([[0.2036, 0.4158, 0.5580], [0.0367, 0.0985, 0.0508], [0.2699, 0.3506, 0.6175], [0.4453, 0.2140, 0.8210], [0.5186, 0.5982, 0.5727]]) tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]) tensor([[-1.9160, 2.1421, -1.5401], [ 1.8225, -0.0795, 0.8316], [-1.3870, -0.1979, 2.3541], [-0.5271, -0.4615, -0.2871], [ 0.3452, 0.0986, 1.3375]]) |
テンソルのサイズを取得する
テンソルのサイズは.sizeで取得します。
1 2 3 4 5 |
from __future__ import print_function import torch x = torch.rand(5, 3) print(x.size()) # テンソルサイズを取得 |
取得したサイズtensor.Sizeはタプル形式なので、全てのタプル操作がサポートされています。
1 |
torch.Size([5, 3]) |
テンソルの演算
テンソルの演算にも様々な方法があります。以下のコードはいずれも2つの1テンソルの加算です。
単純に「+」記号で演算する以外にも、add関数や「アンダースコア(_)」を入れたadd_で加算する方法を紹介しています。
add関数を使うことで引数を使って他の変数に値を受け渡すことができます。
また、x.add_とアンダースコアを入れる作業は他にもx.copy_等があり、これは共通してxを変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from __future__ import print_function import torch # テンソルを新規定義 x = torch.ones(5, 3) y = torch.ones(5, 3) # テンソルの加算(色々な方法) print(x + y) # 記号で直接演算 print(torch.add(x, y)) # add関数で演算 # 別のテンソルへ結果を返す result = torch.empty(5, 3) torch.add(x, y, out=result) print(result) # addして置換 y.add_(x) print(y) |
いずれも以下の同一の結果を得ます。演算の方法でメモリの割り当て方が異なるので、計算パフォーマンスに影響すると考えられます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
tensor([[2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.]]) tensor([[2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.]]) tensor([[2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.]]) tensor([[2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.], [2., 2., 2.]]) |
個人的にはできるだけIn-Place系の操作を使った方が良さそうと思うけど、実際どうなんだろう?
テンソルをスライスをする
PyTorchのテンソルはnumpyのようなスライス(indexing)が可能です。
1 2 3 4 5 6 7 8 9 |
from __future__ import print_function import torch # テンソルを新規定義 x = torch.randn(5, 3) print(x) print(x[:, 1]) # 1列スライス print(x[1, :]) # 1行スライス |
上記コードは以下の結果を得ます。numpyと同じですね!
1 2 3 4 5 6 7 |
tensor([[ 2.0010, 0.2166, -1.7440], [-0.6584, -0.0792, -0.4838], [-1.3848, -1.0466, -0.6611], [ 0.3062, -1.2611, -0.3194], [ 0.6795, 0.0870, 1.1469]]) tensor([ 0.2166, -0.0792, -1.0466, -1.2611, 0.0870]) tensor([-0.6584, -0.0792, -0.4838]) |
テンソルのresize/reshape
numpyでいうresizeやreshapeは、PyTorchテンソルの場合以下のように.viewを使います。
1 2 3 4 5 6 7 8 9 10 |
from __future__ import print_function import torch x = torch.randn(4, 4) y = x.view(16) z = x.view(-1, 8) print(x.size(), y.size(), z.size()) print(x) print(y) print(z) |
元々4×4のテンソルだったxに対し、サイズを(16)と指定するとyになり、(-1, 8)と指定するとまず8列が定義されてxの残りから他の次元が推測されzになりました。
1 2 3 4 5 6 7 8 9 |
torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8]) tensor([[-1.4908, -0.0490, 0.7412, 0.1411], [ 1.8461, -1.3220, 1.1647, 0.2138], [ 0.5506, 0.3520, -1.7475, -0.6519], [-0.6411, -1.5663, -0.0807, -0.4007]]) tensor([-1.4908, -0.0490, 0.7412, 0.1411, 1.8461, -1.3220, 1.1647, 0.2138, 0.5506, 0.3520, -1.7475, -0.6519, -0.6411, -1.5663, -0.0807, -0.4007]) tensor([[-1.4908, -0.0490, 0.7412, 0.1411, 1.8461, -1.3220, 1.1647, 0.2138], [ 0.5506, 0.3520, -1.7475, -0.6519, -0.6411, -1.5663, -0.0807, -0.4007]]) |
テンソルから要素を取得
1要素のテンソルの場合、.itemを使ってPythonナンバーを取得できます。
1 2 3 4 5 6 |
from __future__ import print_function import torch x = torch.randn(1) print(x) print(x.item()) |
取得した数値はテンソルではなく、Pythonでそのまま扱える数です。
1 2 |
tensor([-0.1963]) -0.19625703990459442 |
numpyとtensorの相互変換
tensorからnumpyに変換するには.numpy()、numpyからtensorに変換するにはtorch.from_numpy()を使います。
1 2 3 4 5 6 7 8 9 |
from __future__ import print_function import torch a = torch.ones(5) # テンソルを新規定義 b = a.numpy() # aをnumpyに変換 c = torch.from_numpy(b) # bをテンソルに変換 print(a) print(b) print(c) |
相互に変換することができました。もしかしたらこの操作は最もよく使うことになるかも知れません。
1 2 3 |
tensor([1., 1., 1., 1., 1.]) [1. 1. 1. 1. 1.] tensor([1., 1., 1., 1., 1.]) |
GPUではなく、CPU上のtensorはCharTensor以外全てnumpyとの相互変換がサポートされています。
GPU関係はまだまだ理解が足りないので、CUDAチュートリアルは省きますが、What is PyTorch?のチュートリアルは以上です。
ここやチュートリアルに書いていない演算はこちらの公式ドキュメントに記載されています。
まとめ
本ページでは、PyTorchインストール後のはじめの一歩として、「What is PyTorch?」公式チュートリアルをやってみました。
本家ページは全部英語で説明がされていますが、ここでは個人的に理解したことを日本語で書いています。
PyTorchはテンソルの計算が基礎にあるので、ここで習得したテンソル定義、演算、変換はいつでも使えるようにしておきたいですね。
PyTorchインストール直後は本当に何からやってよいかわかりませんでしたが、テンソル計算はなんとか理解することができました!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
コメント