HELLO CYBERNETICS

深層学習、機械学習、強化学習、信号処理、制御工学、量子計算などをテーマに扱っていきます

Pytorchのニューラルネットの書き方

 

 

follow us in feedly

f:id:s0sem0y:20170925014700j:plain

 

 はじめに

Pytorchはニューラルネットを柔軟に設計できるように、様々な実装の方法が提供されています。今回はその中でも基本的な書き方をいくつか紹介することにします。書きたいニューラルネットの規模やカスタマイズしたい内容によって書き方を変えれば、効率よく素早いコーディングが可能になるはずです。

 

前提として以下がimportされている状態で進めます。

 

f:id:s0sem0y:20171020015212p:plain

 

簡単なフィードフォワードニューラルネットワーク

今回は隠れ層が2つで、出力層が1つの3層フィードフォワードニューラルネットワークを例に使います。

 

nn.Module

nn.Moduleを継承して書くスタイルは、Chainerでchainer.Chainを継承して各スタイルに似ています。若干違うところは、各層が受け取る入力の大きさについてもしっかり明示してあげなければいけないところです。現状、任意の置きさを受け取れるようにNoneを指定することはできません。

 

また、順伝播は「forward」で書くことになります。モデルに値を渡した時には、このメソッドが自動的に呼び出される仕組みです。

 

以下に例を載せます。

f:id:s0sem0y:20171020015630p:plain

 

※ 上記の `fowrard()` メソッドに関して、

h = F.relu(self.l2(h))

h = F.relu(self.l3(h))

が正しいです。上記のままでは異なる線形変換に個別に入力を入れていることになり、更に、出力には self.l3 しか効かなくなってしまいます。 

 

MyMLPのインスタンスmodel1をプリントしてあげると、処理の中身を見ることができます。地味に便利です。ただし、ここでは活性化関数reluの情報は表示されていないことに注意してください。

 

こちらの実装方法は、パラメータを持つ部分と、パラメータを持たない部分を分離することを意識する場合に用いられるかと思われます(これはChainerのlinksとfunctionsを分けたときの基本思想だと思います)。

 

__init__で渡すのはあくまで学習パラメータを持つクラスたちであり、forwardの方は単に具体的な計算処理を書いていくというスタイルです。

 

nn.Module part2

モデルをprintで出力する場合には、__init__で渡してあるものだけが表示されます。したがって、こちらに情報を集約してやることにしましょう。活性化関数もnn.ReLUなどのクラスが準備されているので、以下のような実装が可能です。

 

f:id:s0sem0y:20171020020317p:plain

 

※ 上記の `fowrard()` メソッドに関して、

h = F.relu(self.l2(h))

h = F.relu(self.l3(h))

が正しいです。上記のままでは異なる線形変換に個別に入力を入れていることになり、更に、出力には self.l3 しか効かなくなってしまいます。 

 

 

こちらでは、活性化関数の情報も出力できているのが分かります。

 

こちらでは、__init__に学習パラメータを持たないnn.ReLUが入り込んでいます(別にそれほどわかりづらくなるわけではないですが)。特に処理内容が変わるわけではありませんが、printで出力できるか否かなどの表面上の違いが出ることは抑えておいても良いと思われます。

 

 

Sequential

Sequentialはこれまでの書き方とは全く違う方法です。

KerasのSequentialに似た書き方ができます。

 

ご覧の通り、必要な処理をひたすらnn.Sequentialに順番に渡していくだけです。これの中身は上記で書いたモデルと同じものになっています。極めて素早く簡単に実装ができるので、何か簡単なモデルの実装や、動作をちょっとだけ見てみたいという場合にオススメです。

 

f:id:s0sem0y:20171020020805p:plain

 

この方法ではネットワークの分岐などは基本的に書くことができません。

 

Sequential part2

Sequentialで各層に名前を付ける方法を見ます。

Moduleを使えば定義した時の変数名がそのまま名前になっていましたが、Sequentialでは単に番号が付けられているだけでした。PythonのOrdinalDictを使ってやれば名前を付けることができます。

 

f:id:s0sem0y:20171020021857p:plainr

 

ただ、Sequentialは単純なモデルしか組めないため、そもそもこれ単体で名前を付けなければならないほど複雑な状況は考えづらいので、使いみちは少ないと思います。

 

 

nn.ModuleList

これは必要な層をリストで渡してやることで、層のイテレータを作ってくれます。これによってforward処理を簡単に書けるようになります。

 

f:id:s0sem0y:20171020022957p:plain

 

今回の簡単なニューラルネットでこれを使う意義は全くありませんが、Pythonのリストの操作に慣れていれば、for文や内包表記を使ってもっと素早く深いニューラルネットを構築することができるでしょう。

 

 

次回は

次回がもしもあれば、torch.nn.Parameterを使ったより低レベルな実装方法を見るかもしれません。

 

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com

s0sem0y.hatenablog.com