ついにnnパッケージを利用してニューラルネットを構築します。
この流れだと、nnパッケージの便利さがよくわかるね。
PyTorchチュートリアル「LEARNING PYTORCH WITH EXAMPLES」のnnパッケージの項目を進めていきます。
前回の記事は、こちらをご参考ください。
こんな人の役に立つかも
・機械学習プログラミングを勉強している人
・PyTorchで機械学習プログラミングを勉強している人
・PyTorchでニューラルネットワークを勉強している人
nnモジュールについて
計算グラフとautogradは、複雑な演算子を定義して自動的に導関数をとるための非常に強力なパラダイムです。 ただし、大規模なニューラルネットワークの場合、直接autogradを利用すると、勾配の算出などの直接的な仕組みを考えなければならないので、もう少し抽象化された概念として扱いたいです。
ニューラルネットワークを扱うときには、入力層、中間層、出力層などのように、層としてネットワークを考え、それぞれのノードには「重み」や「バイアス」という訓練可能なパラメータを持つモデルとして考えたいです。
TensorFlowでは、「Keras、TensorFlow-Slim、TFLearn」などのパッケージが計算グラフなどの直接的な実装を隠蔽して、より抽象的にニューラルネットワークを扱えるようにしています。
PyTorchではnnパッケージがこの抽象化を行います。nnパッケージは、ニューラルネットワークの層の概念と同等の一連の「モジュール」を提供してくれます。 モジュールは、入力テンソルを受信して出力テンソルを計算します。学習可能なパラメータを含むテンソルなどの内部状態も保持する場合があります。
nnパッケージは、ニューラルネットワークのトレーニング時に一般的に使用される有用な損失関数も定義します。(例えば平均二乗誤差です。)
文章が硬くなってきたね。
Google翻訳を参考に指定たら、こうなってきました。
nnパッケージを使うことの利点
・ニューラルネットワークの概念をそのままプログラムで実装できる
・autogradを意識しないプログラミング(重みの更新部分を除く^^;)
・一般的な損失関数も簡単に定義可能
チュートリアルプログラムの実装
まず、importからです。
また、ネットワークで利用する値、入力データ、出力データを作成します。ここまでは前回までと同様の処理内容です。
# -*- coding: utf-8 -*-
import torch
# N :バッチサイズ
# D_in :入力次元数
# H :隠れ層の次元数
# D_out:出力次元数
N, D_in, H, D_out = 64, 1000, 100, 10
# ランダムな入力データと出力データの作成
x = torch.randn(N, D_in)
y = torch.randn(N, D_out)
nnモジュールを利用して、ネットワークの流れをモデルとして定義します。
nn.Linearは線形変換を行います。入力、出力を引数に取ります。 ReLUは、ReLUでの変換を行います。2層のニューラルネットワークでは、次のようなモデルになります。もちろん、訓練パラメータも保持しています。
#ニューラルネットワークの定義
model = torch.nn.Sequential(
torch.nn.Linear(D_in, H),
torch.nn.ReLU(),
torch.nn.Linear(H, D_out),
)
#平均二乗誤差
loss_fn = torch.nn.MSELoss(reduction='sum')
#学習率
learning_rate = 1e-4
#エポック
for t in range(500):
# ①順伝播: 入力を与えて順伝播させます。
y_pred = model(x)
# ②損失を計算します。
loss = loss_fn(y_pred, y)
if t % 100 == 99:
print(t, loss.item())
# ③逆伝播の前に勾配を初期化します。
model.zero_grad()
# 逆伝播:
loss.backward()
# ④重みの更新. Each parameter is a Tensor, so
# we can access its gradients like we did before.
with torch.no_grad():
for param in model.parameters():
param -= learning_rate * param.grad
①順伝播をシンプルに表記できています。
②上で定義したMESLossを変更するだけで簡単にいろいろな誤差を試すことができるようになりました。
③逆伝播の勾配初期化は必要です。また、最初に定義したモデルが「requires_grad = True」としているため、最終的な計算結果であるlossをbackwardすることで微分値である勾配を求めることができます。
④nnモジュールでニューラルネットワークを定義した場合、model.parameters()のようにパラメータを取得することができますので、for文ですべてのパラメータにアクセスしてそれぞれに勾配降下法で重みを更新していきます。
ここだけテンソルのように一括で計算できていないので少し気持ち悪い感じがします。
後に出てくるoptimのでここも簡単になるね。
実行結果は以下の様になります。
99 1.7279762029647827
199 0.027289215475320816
299 0.0008932463242672384
399 3.5993754863739014e-05
499 1.688112320152868e-06
本日のGitHubです、実行時にご利用ください。
続きの記事はこちらです。