メインコンテンツまでスキップ

PyTorch Quick Note

· 約6分

Tensor

import torch
torch.tensor([0, 1, 2, 3]) # long型
torch.Tensor([0, 1, 2, 3]) # float型
torch.arange(4) # tensor([0, 1, 2, 3])
torch.zeros(4) # tensor([0, 0, 0, 0])
torch.ones(1) # tensor([1, 1, 1, 1])
torch.tensor([[0, 1, 2], [3, 4, 5]]) # 2x3行列
torch.Tensor(2, 3) # ランダムに初期化された2x3行列
torch.arange(6).reshape(2, 3) # 1次元配列をを2x3行列に変換
torch.arange(4) + 2 # tensor([2, 3, 4, 5])
torch.arange(4) * 2 # tensor([0, 2, 4, 6])
torch.arange(4).reshape(2, 2) * 2 # tensor([[0, 2], [4, 6]])
a = torch.arange(4).reshape(2, 2)
b = torch.arange(4).reshape(2, 2)
a + b # tensor([[0, 2], [4, 6]])
a = torch.arange(4).reshape(2, 2)
b = torch.arange(4).reshape(2, 2)
a * b # tensor([[0, 1], [4, 9]])
a = torch.arange(4)
b = torch.arange(4)
torch.dot(a, b) # 内積: tensor([[0, 1, 4, 9]])
a = torch.arange(4).reshape(2, 2)
b = torch.arange(2).reshape(2, 1)
torch.matmul(a, b) # 行列積: tensor([[1], [3]])
torch.arange(24).reshape(-1, 2, 4) # `-1`は余りの次元。この場合, 24 / (2 * 4) = 3 次元
a = torch.arange(4)
a.dtype # torch.int64
torch.tensor([1, 2, 3], dtype=torch.float) # floatのtensorを生成
a = torch.tensor([1, 2, 3])
b = a.numpy() # numpyの配列に変換
torch.from_numpy(b) # numpyの配列をtensorに変換
a = torch.Tensor(2, 3)
b = torch.Tensor(2, 3)
torch.cat([a, b]) # 4x3行列を生成
torch.cat([a, b], dim=1) # 2x6行列を生成
a = torch.Tensor(2, 3)
b = torch.Tensor(2, 3)
c = torch.Tensor(2, 3)
torch.stack([a, b, c]) # 2x3行列を3つ持つバッチ
a = torch.Tensor(2, 3)
a.unsqueeze(0) # torch.stack([a])と同じ
a = torch.Tensor(3, 2, 2)
a.permute(2, 0, 1) # 軸の入れ替え: 元の次元のインデックスを指定する
x1 = torch.tensor([1.], requires_grad=True) # 微分を有効にする
x2 = torch.tensor([2.], requires_grad=True) # 微分を有効にする
x3 = torch.tensor([3.], requires_grad=True) # 微分を有効にする
z = (x1 - 2 * x2 - 1)**2 + (x2 * x3 - 1)**2 - 1
z.backward() # 微分値を計算
x1.grad # dz/dx1の値
x2.grad # dz/dx2の値
x3.grad # dz/dx3の値
# 何回も同じ変数で微分する時は毎回リセットする
x1 = x1.detach() # 微分値をリセット
x1 = x1.requires_grad_(True) # 微分を有効にする

おまじない

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import numpy as np
Pythonメモ

importfrom

import mylib
print(mylib.myfunc)
from mylib import myfunc
print(myfunc)

モデルの定義

class MyModel(nn.Module):
def __init__(self):
super(MyModel, self).__init__()
# 全結合層: 第1層(4 units) -> 第2層(6 units)
self.l1=nn.Linear(4, 6)

# 全結合層: 第2層(6 units) -> 第3層(3 units)
self.l2=nn.Linear(6, 3)

# 順伝播
def forward(self, x):
# 第2層(隠れ層)の値を計算
# 活性化関数: sigmoid
h1 = torch.sigmoid(self.l1(x))

# 出力層の値を計算
h2 = torch.l2(h1)
return h2
Pythonメモ

継承

class MyClass(SuperClass): # 親クラスを継承
def __init__(self, hoge):
# 親クラスのコンストラクタを呼び出す
# super(...)は親クラスのインスタンス
# super(...).`メソッド名`とすることで親クラスのメソッドを呼び出せる
super(MyClass, self).__init__(hoge) # Python2
super().__init__(hoge) # Python3

学習準備

# モデルの生成
model = MyModel()
# 確率的勾配降下法
# lr: 学習率
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 損失関数: 交差エントロピー
criterion = nn.CrossEntropyLoss()
SDG

全ての訓練データに対する損失を使ってパラメータを1回更新する学習をバッチ学習と言う。それに対して、ランラムに選ばれた1つの訓練データに対する損失関数を使ってパラメータを1回更新する学習をSDG(確率的勾配降下法)と言う。

ミニバッチ

1つの訓練データごとにパラメータの更新を行う学習に対して、ある程度の訓練データの集合単位でパラメータを更新する学習もSDGと呼ばれる。このある程度の訓練データの集合をミニバッチと言う。

学習

n = 75 # 訓練データの数
bs = 25 # ミニバッチのサイズ
model.train()
for i in range(1000): # エポック数: 1000
idx = np.random.permutation(n) # 0からn-1まで数をランダムにn個取り出す
for j in range(0, n, bs): # 0, 25, 50
# bs個のデータを抽出
input_batch = input[idx[j:(j+bs) if (j+bs) < n else n]]
target_batch = target[idx[j:(j+bs) if (j+bs) < n else n]]

output = model(input_batch) # モデルの出力を計算
loss = criterion(output, target_batch) # 答えとの誤差を計算
print(i, j, loss.item()) # 誤差を出力
optimizer.zero_grad() # 微分値のリセット
loss.backword() # 微分
optimizer.step() # パラメータの更新(勾配分だけ移動)
逆誤差伝播法

損失関数の微分を効率よく実行する方法。

テスト

model.eval()
with torch.no_grad():
output = model(input)
ans = torch.argmax(output, 1)
print(((target == ans).sum().float() / len(ans)).item())