MIT License
元ネタ: jcjohnson/pytorch-examples
PyTorch: Tensors
# Program 1 素朴なMLPの実装
import torch
dtype = torch.FloatTensor # CPU上の32-bit floating point
# dtype = torch.cuda.FloatTensor # GPU上の32-bit floating point
# D_in x H x D_outの三層ニューラルネットを構成する.
N, D_in, H, D_out = 64, 1000, 100, 10
# データセットの作成
x = torch.randn(N, D_in).type(dtype)
y = torch.randn(N, D_out).type(dtype)
# 重み行列の作成
w1 = torch.randn(D_in, H).type(dtype)
w2 = torch.randn(H, D_out).type(dtype)
# Gradient Descentによる最適化
learning_rate = 1e-6
for t in range(500):
h = x.mm(w1) # matrix multiplication
h_relu = h.clamp(min=0) # Clamp all elements in input into the range [min, max] and return a resulting Tensor.
y_pred = h_relu.mm(w2)
# compute and print loss
loss = (y_pred - y).pow(2).sum()
if t % 50 == 0:
print(t, loss)
# backpropagation
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.t().mm(grad_y_pred) # a.t() : transpose
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h<0] = 0
grad_w1 = x.t().mm(grad_h)
# gradient descent
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
0 33983926.96143705
50 11801.846684516087
100 357.2751016973617
150 17.174204719908438
200 1.006447628455322
250 0.06717062689924691
300 0.005198379904488515
350 0.0006403423317780793
400 0.0001579846401805196
450 6.24626183654553e-05
PyTorch: Variables and autograd
Program 1では手動でbackpropagationを行って勾配を計算したが,PyTorchでは変数をVariable
型でラップすることで,その変数に対する写像の勾配を簡単に計算できる.
# Program 2 自動微分を使った三層MLPの実装
import torch
from torch.autograd import Variable
dtype = torch.FloatTensor # CPU上の32-bit floating point
# dtype = torch.cuda.FloatTensor # GPU上の32-bit floating point
# D_in x H x D_outの三層ニューラルネットを構成する.
N, D_in, H, D_out = 64, 1000, 100, 10
# データセットの作成
# データセットについての勾配は不要なので,requires_grad=Falseとする.
x = Variable(torch.randn(N, D_in).type(dtype), requires_grad=False)
y = Variable(torch.randn(N, D_out).type(dtype), requires_grad=False)
# 重み行列の作成
# 重み行列でloss functionを最適化するため,重み行列による勾配が必要. requires_grad=True
w1 = Variable(torch.randn(D_in, H).type(dtype), requires_grad=True)
w2 = Variable(torch.randn(H, D_out).type(dtype), requires_grad=True)
# GDによる最適化
learning_rate = 1e-6
for t in range(500):
# backpropagationを手動ではしないので,中間の計算結果は保存しない.
y_pred = x.mm(w1).clamp(min=0).mm(w2)
loss = (y_pred - y).pow(2).sum() # lossはVariableに対する演算の結果なのでVariable
# VariableはTensorであり,実数は(1,)のTensorとして格納され,
# v.data[0]によってただの実数として取り出せる.
if t % 50 == 0:
print(loss.data[0])
# backward passの前に手動で勾配を0にする (前のループでの勾配を初期化するということ?)
# もとの例ではt=0の場合にも初期化を行っていたが,最新のPyTorchだとエラーになる.
if t:
w1.grad.data.zero_()
w2.grad.data.zero_()
# loss.backward()によって,lossに至るまでの全ての変数に対する勾配を計算する.
# w1.grad, w2.gradで計算した勾配を読める.
loss.backward()
w1.data -= learning_rate * w1.grad.data
w2.data -= learning_rate * w2.grad.data
33022228.0
13424.4697265625
475.697021484375
26.867782592773438
1.9564745426177979
0.1696002036333084
0.016552181914448738
0.0019943274091929197
0.0004035909951198846
0.00013585695705842227
PyTorch: nn
autogradよりも抽象的で,大規模なnetworkの記述に向いたツールにnn パッケージが有る. neural networkはいくつものlayerが重なって構成されており,層ごとにlearnable parametersをもつことがある. nn
にはModuleの集合が定義されていて,それぞれがlayerの抽象化と考えることが出来る. ModuleはVariable
のインスタンス(たち)を与えられてVariable
のインスタンス(たち)を返し,かつlearnable parametersを含む内部状態をVariable
のインスタンスとして持つ. また,nn
は有用なloss functionを予め定義している. Program 3はnn
による3層のneural networkの例である.
# Program 3
import torch
from torch.autograd import Variable
N, D_in, H, D_out = 64, 1000, 100, 10
x = Variable(torch.randn(N, D_in))
y = Variable(torch.randn(N, D_out), requires_grad=False)
# torch.nn.Sequential() の引数にlayerたちを記述し,その順番にlayerを繋げたnetworkがモデルとなる.
# layerたちのもつパラメータmodelに保存されていて,あとで勾配を計算できる.
# 引数にmoduleを入れてネストした構造を作ることも出来る.
# moduleを組み合わせてmodelすなわちnetworkを構成する.
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
)
# torch.nnは代表的なloss functionを予め定義している. ここではMSEを使う.
loss_fn = torch.nn.MSELoss(size_average=False)
learning_rate = 1e-4
for t in range(500):
# Forward pass
# modelは関数であるかのように呼べて,ここではxを引数とする.
y_pred = model(x)
# lossを計算する. y_predにmodelの情報(networkの全てのパラメータ)が保存されているから
# あとでloss.backward()をするだけでnetworkのパラメータによるlossの勾配が計算される.
# loss_fn()の返り値はまたVariableのインスタンス.
loss = loss_fn(y_pred, y)
if t % 50 == 0:
print(t, loss.data[0])
# gradientの初期化
if t:
model.zero_grad()
loss.backward() # これによってgradientが計算される.
# gradient descentの更新.
# model.parameters()がモデルの全てのパラメータである.
# modelのパラメータはVariableだから,以下のように更新する.
for param in model.parameters():
param.data -= learning_rate * param.grad.data
0 697.54541015625
50 30.74203872680664
100 2.117093086242676
150 0.22655823826789856
200 0.03121182695031166
250 0.005095028784126043
300 0.0009658429189585149
350 0.0002087247121380642
400 4.9990881962003186e-05
450 1.284706377191469e-05
PyTorch:optim
これまではGradient Descentによって最適化を行ってきたが,より洗練された最適化手法は多くあるが,いちいち実装していては大変なので,optim
packageは有用な最適化手法を定義している. Program 4はAdam methodによる最適化をoptim
によって実現している.
# Program 4
import torch
from torch.autograd import Variable
N, D_in, H, D_out = 64, 1000, 100, 10
x = Variable(torch.randn(N, D_in))
y = Variable(torch.randn(N, D_out))
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
)
loss_fn = torch.nn.MSELoss(size_average=False)
# optimによってOptimizerを定義する. ここではAdamを使うが,ほかにも多くの手法が定義されている.
# torch.optim.Adamの最初に与える引数が,最適化を行う変数の集合である.
learning_rate = 1e-4
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
for t in range(500):
y_pred = model(x)
loss = loss_fn(y_pred, y)
if t % 50 == 0:
print(t, loss.data[0])
optimizer.zero_grad() # これはわざわざtが0出ないことを確かめなくてもエラーを起こさない
loss.backward()
# optimizerのstep()メソッドによって,最適化するパラメータを1回更新する.
optimizer.step()
0 668.1607055664062
50 200.53623962402344
100 51.36286163330078
150 8.457684516906738
200 0.8371148705482483
250 0.06822004914283752
300 0.005305096507072449
350 0.0003715920902322978
400 2.1446359824039973e-05
450 9.826173936744453e-07
PyTorch: Custom nn Modules
nn.Module
のサブクラスとして新たなmoduleを定義できる.
それには,与えられた入力(Variableのインスタンス)をautogradの演算で望む出力(Variableのインスタンス)に変換する写像をforward
として実装する. Program 5は3層のネットワークを一つのmoduleとして定義して作ったnetworkの実装例である.
# Program 5
import torch
from torch.autograd import Variable
class TwoLayerNet(torch.nn.Module):
def __init__(self, D_in, H, D_out):
"""
constuctorにおいて2つのnn.Linearをインスタンス化して,Variableの一員とする
"""
super(TwoLayerNet, self).__init__()
self.linear1 = torch.nn.Linear(D_in, H)
self.linear2 = torch.nn.Linear(H, D_out)
def forward(self, x):
h_relu = self.linear1(x).clamp(min=0)
y_pred = self.linear2(h_relu)
return y_pred
N, D_in, H, D_out = 64, 1000, 100, 10
x = Variable(torch.randn(N, D_in))
y = Variable(torch.randn(N, D_out), requires_grad=False)
model = TwoLayerNet(D_in, H, D_out)
# loss functionとopimizerを定義する.
criterion = torch.nn.MSELoss(size_average=False)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)
for t in range(500):
y_pred = model(x)
loss = criterion(y_pred, y)
if t % 50 == 0:
print(t, loss.data[0])
optimizer.zero_grad()
loss.backward()
optimizer.step()
0 719.2647705078125
50 33.10668182373047
100 2.121030569076538
150 0.22128432989120483
200 0.030644414946436882
250 0.005116437561810017
300 0.00095479900483042
350 0.00019043088832404464
400 3.9648610254516825e-05
450 8.519250513927545e-06
0 件のコメント:
コメントを投稿