====== PyTorch ======
==== 基本 ====
=== ndarrayからTensor ===
tensor = torch.from_numpy(arr.transpose(2,0,1)[np.newaxis,:,:,:])
=== Tensorからndarray ===
arr = tensor.numpy()
==== ModuleList U-Net ====
フィボナッチをワンライナーでやる系のやつを使う
| ''seq'' | Sequential |
| ''mods'' | ModuleList ''[seq,seq,seq,...]'' |
| ''x '' | input tensor |
| ''y'' | output tensors |
y = [(l.append(f(l[-1])),l[-1])[1] for l in [[x]] for f in mods]
==== 変形 ====
=== torch.nn.functional.affine_grid ===
^ input ^^^
| theta | ''(N,2,3)'' | 逆変換行列 |
| size | ''size'' | 出力特徴マップのサイズ |
^ output ^^^
| grid | ''(N,H,W,2_xy)'' | グリッドサンプラー |
座標系におけるアフィン変換の逆変換行列を与えると良い.
base_gridが格子点で生成され,この逆変換行列で座標変換されたものが返されるのだろう.
=== torch.nn.functional.grid_sample ===
入力画像をx[-1,+1],y[-1,+1]のキャンバスに置いて grid で示された座標の値を得る.
この座標系では画像右方向にx軸,下方向にy軸がある.
=== Thin-Plate Splineを自前で実装する場合 ===
Thin-Plate Splineのnn.Moduleを自前で実装するなら,
コンストラクタに変換後コントロールポイント座標と特徴マップのサイズ(H,W)を与え,
インスタンス生成時に
$$
\left(\begin{array}{c|c} {\bf R_{\rm cpt}} & {\bf H_{\rm cpt}}\\ \hline {\bf H_{\rm cpt}}^\top & {\bf O} \end{array}\right)^{-1}
$$
を作成する.
予めベースサンプラーとして
$$\left(\begin{array}{c|c} {\bf R_{\rm gpt}} & {\bf H_{\rm gpt}} \end{array}\right)$$を用意しておく.
ネットワーク中で変換前コントロールポイント座標が与えられたら
$$\left(\begin{array}{c} {\bf P'_{\rm cps}}\\ \hline {\bf O} \end{array}\right)$$を作り,
$$
\left(\begin{array}{c} {\bf W}\\ \hline {\bf A} \end{array}\right)
= \left(\begin{array}{c|c} {\bf R_{\rm cpt}} & {\bf H_{\rm cpt}}\\ \hline {\bf H_{\rm cpt}}^\top & {\bf O} \end{array}\right)^{-1}
\left(\begin{array}{c} {\bf P'_{\rm cps}}\\ \hline {\bf O} \end{array}\right)
$$
で変換後コントロールポイントから変換前コントロールポイントへ変換する変換行列が計算できる.
これによって
$$
\left(\begin{array}{c|c} {\bf R_{\rm gpt}} & {\bf H_{\rm gpt}} \end{array}\right) \left(\begin{array}{c}{\bf W}\\ \hline {\bf A} \end{array}\right) = {\bf P'_{\rm gps}}
$$
でサンプラーが作成出来る.
^ constructor ^^^
| size | | N,H,Wの情報だけあればいい |
| cpt | ''(N,T,2_xy)'' | 目標コントロールポイント座標 |
^ forward input ^^^
| cps | ''(N,T,2_xy)'' | コントロールポイント元座標 |
^ forward output ^^^
| grid | ''(N,H,W,2_xy)'' | グリッド |
| instance public | forward |
| class private | calc_R_mat |
==== align_cornersについて ====
TODO
==== grid について ====
ダサい?
y_map = torch.zeros((1,W,1),device=device) \
+ torch.arange(start=0,end=H,dtype=dtype,device=device).view(H,1,1)
x_map = torch.zeros((H,1,1),device=device) \
+ torch.arange(start=0,end=W,dtype=dtype,device=device).view(1,W,1)
coord_map = torch.cat([x_map,y_map],2)
torch.stack( torch.meshgrid(
torch.arange(W, dtype=dtype, device=device),
torch.arange(H, dtype=dtype, device=device),
indexing='xy'), -1 )
今度、速度比較したい。
==== nn.Module ====
''register_buffer''や''register_parameter''はstate_dict()で呼び出せるようにする.
''register_buffer''はmodel.parameters()で呼び出されないのでoptimizerによる更新がない.
''register_parameter''は呼び出されるので更新がある.
==== print関数の調整 ====
* [[https://pytorch.org/docs/stable/generated/torch.set_printoptions.html]]
* precision : 桁数
* threshold : 省略する個数の閾値
* edgeitems : 真ん中省略するときの最初と最後の個数
* linewidth : 一行の最大文字数
* profile : 'default', 'short', 'full'
* sci_mode : 'True' or 'False'
===== torchvision =====
vgg, inception, resnet などの入力は 3チャンネル、range 0-1
===== backward を自前で定義 =====
==== 既製のものの動作を確認する ====
あるモジュールがあり、''loss = mod(v1,v2,...)'' とする。\\
準備として、全ての始点変数(''v1,v2,..''のこと)を ''.requires_grad()'' しておく。\\
また、途中計算のすべての変数を ''.retain_grad()'' しておく。\\
こうすると、
逆伝播を ''loss.backward(create_graph=True)'' で実行すると、\\
すべての変数に対して ''.grad.data'' で中身が見れるようになる。
=== conv の逆伝播を自前で作る ===
# x (N,iC,H,W)
# w (oC,iC,kH,kW)
# b (oC,)
y = F.conv2d(x,w,b)
dLdy
dLdb = dLdy.sum(dim=(0,2,3)) # (N,oC,H,W) -> (oC,)
dLdx = F.conv_transpose2d( dLdy, w, padding=padding)
dLdw = torch.flip( F.conv2d( dLdy.permute(1,0,2,3),
x.permute(1,0,2,3), padding=padding ), (2,3))
# (oC,N,H,W) conv (iC,N,H,W) -> (oC,iC,kH,kW)
# flip is [:,:,::-1,::-1]
==== 自作関数 ====
''torch.autograd.Function'' を継承したクラスを作り、\\
中に staticmethod として ''forward()'' と ''backward()'' を
持っておくと動く。
''forward()'', ''backward()'' ともに第一引数は ''ctx'' とする。\\
この ''ctx'' は pytorch の特別なオブジェクト。
''backward()'' の戻り値は ''forward()'' の引数に対する勾配。\\
''backward()'' の引数は ''forward()'' の戻り値に対する勾配。
このクラスの ''apply'' というメンバが、ユーザーが実際に使う関数となる。
===== カスタム =====
==== pytorchコードリーディング ====
- pytorch/
- torch/
- csrc/ : C++とかで書かれたコード?
| aten | PyTorch用のテンソル計算ライブラリ |
==== ビルド ====
PyTorch1.5からビルドシステムにちょっと変更が入った?
マルチスレッドな Ninja に対応したことで ''MAX_JOBS=2'' とか付けて ''setup.py'' するか、
''BuildExtension.with_options(use_ninja=False)'' にするかしないと以前のシステムは動かないようになった。
===== 未整理メモ =====
=== nn.Module やそれに所属するメソッドをprintしようとしたときの挙動 ===
クラス内のメソッド (クラスメソッド、インスタンスメソッド両方) を print() すると
以下のように描画される。
インスタンスのクラスなどに ''%%_%%_str_%%_%%'' や ''%%_%%_repr_%%_%%'' が設定されていたらそれが表示されてしまう。
nn.Module は ''%%_%%_str_%%_%%'' と ''_%%_%%repr%%_%%_'' がともに書き換えられているので、
nn.Module またはそれから継承したクラスのメソッドを print() すると
ちなみにクラスに対してあとからメソッドを追加するときは
''hoge.fuga = myfunc'' ではなく ''hoge.%%_%%_class%%_%%_.fuga = myfunc'' とする。
前者は function となり後者は method となる。