UnityのGetAxisRawで連続入力を妨げるコード

3つ以上の選択肢やコマの移動などに。
GetButtonUpはあるが、GetAxisRawUpはないためサンプルコードを公開しました。
もっとスマートな方法があるかもしれません。

Deep Learning ビッグデータ取得

聖母の名前を使うので、はばかられるので、(変なソフトになったときにヤバイので)カオリ(Kaeori)という名称にすることにした。ビクターのDJとは全く関係がない。

さて、カオリに対しての入力「こんにちは」にたいしての、カオリの正解の一つの出力は、「いまいそがしいの、またね」だとする。

ビッチ系の重みと、清楚系の重み、不思議ちゃん系の重み、ガテン系の重みなどをつけて、たかだか2層のレイヤで実装できそうである。問題は、その出力数値のインデックスに対応する辞書配列の用意であるが、ツイッターのリプライや日本語の例文集(あるのかわからないが…)を使用して作成すればよいと考える。

17 DeepLearning 誤差逆伝播法の実装

17.1 ニューラルネットワークの学習の全体図

学習手順は下記のようになる。

前提

ニューラルネットワークは、適応可能な重みとバイアスがあり、この重みとバイアスを訓練データに適応するように調整することを「学習」と呼ぶ。ニューラルネットワークの学習は次の4つの手順で行う。

ステップ1(ミニバッチ)

訓練データの中からランダムに一部のデータを選び出す。

ステップ2(勾配の算出)

各重みパラメータに関する損失関数の勾配を求める。

ステップ3(パラメータの更新)

重みパラメータを勾配方向に微小量だけ更新する。

ステップ4(繰り返す)

ステップ1、ステップ2、ステップ3を繰り返す。

誤差逆伝播法を使用するのは、ステップ2の勾配の算出である。数値微分のみを使用する順方向の勾配の算出法は簡単に実装できる反面、計算に多くの時間がかかる。よって、誤差逆伝播法を用いる。

17.2  誤差逆伝播法に対応した
ニューラルネットワークの実装

TwoLayerNet クラスのインスタンス変数

インスタンス変数 説明
params ニューラルネットワークのパラメータを保持するディクショナリ変数。params[‘W1’]は1層目の重み、params[‘b1’]は1層目のバイアス。
params[‘W2’]は2番目の重み、params[‘b2’]は2層目のバイアス。
layers ニューラルネットワークのレイヤを保持する順番付きディクショナリ変数。layers[‘Affine1’],layers[‘Relu1’],layers[‘Affine2’]といったように順番付きディクショナリで各レイヤを保持する。
lastLayer ニューラルネットワークの最後のレイヤ。この例では、SoftMaxWithLossレイヤ。

TwoLayerNet クラスのメソッド

メソッド 説明
__init__(self,input_size, hidden_size, output_size, weight_init_std) ニューラルネットワークのパラメータを保持するディクショナリ変数。params[‘W1’]は1層目の重み、params[‘b1’]は1層目のバイアス。
params[‘W2’]は2番目の重み、params[‘b2’]は2層目のバイアス。
predict(self, x) ニューラルネットワークのレイヤを保持する順番付きディクショナリ変数。layers[‘Affine1’],layers[‘Relu1’],layers[‘Affine2’]といったように順番付きディクショナリで各レイヤを保持する。
loss(self, x, t) 損失関数の値を求める。引数のxは画像データ、tは正解ラベル
accuracy(self, x, t) 認識精度を求める。
numerical_gradient(self, x, t) 重みパラメータに対する勾配を数値微分によって求める。(順伝播 参考として載せるのみで使用しない。)
gradient(self, x, t) 重みパラメータに対する勾配を誤差逆伝播法によって求める。

OrderedDict()についてはPythonのOrderedDictの使い方を参照。

two_layer_net.py

train_neuralnet.py

出力は下図のようになる。

こちらのgithubにフルコードがあります。

16 Deep Learning 逆伝播 2

16.3  リンゴの例

最初に、リンゴなどを買う例の計算グラフを紹介した。リンゴのみに着目すると、
下図のようになる。

この場合の変数は、リンゴの値段、リンゴの個数、消費税である。これら3つの変数それぞれが、最終的な支払金額にどのように影響するかということである。左端の3つの灰色の数字が最終的な支払金額220にどのように影響するか、を表す。「支払金額のリンゴの値段に関する偏微分」、「支払金額のリンゴの個数に関する偏微分」、「支払金額のリンゴの消費税に関する偏微分」を求めることに相当する。これを計算グラフの逆伝播を使って解くと上図のようになる。すなわち、「支払金額のリンゴの値段に関する偏微分」は2.2、「支払金額のリンゴの個数に関する偏微分」は110、「支払金額のリンゴの消費税に関する偏微分」は200である。消費税のスケールとリンゴの値段と個数のスケールは違うので、消費税の影響を表す値が大きくなっている。(消費税の1は100%、リンゴの個数、値段は1個、1円)

前述した通り、乗算ノードの逆伝播では入力信号と”ひっくり返った”積が下流へ流れる。加算ノードはそのまま下流へ流れる。暇な方は下図の空欄を埋めてほしい。

16.4  単純なレイヤの実装

この上のリンゴの買い物の例をPythonで実装する。ここでは、計算グラフの乗算ノードを「乗算レイヤ(MulLayer)」、加算ノードを「加算レイヤ(AddLayer)」という名前で実装する。

16.4.1  乗算レイヤの実装

レイヤはforward()とbackward()という共通のメソッド(関数あるいはインターフェース)を持つように実装する。forward()は順伝播(順方向の伝播)、backward()は逆伝播ん(逆方向の伝播)に対応する。乗算レイヤは下記のように実装できる。

__init__(self)は他言語のコンストラクタに対応し、インスタンス変数の初期化を行う。コンストラクタやインスタンスとは何かとはプログラミングに興味があれば調べてほしい。
forward()では、x、yの2つの引数を受け取り、それらを乗算して出力する。一方、backward()では上流から伝わってきた微分、あるいは信号(dout: d out)に対して、順伝播の”ひっくり返した値”を乗算して下流に流す。
このクラスを使って、下図を実装する。

16_simplelayer.pyとして上記のコードを保存する。その後、コマンドプロンプトで実行すると下記の出力が得られる。

$python 16_simplelayer.py

上図の灰色の数字とdで始まる変数の値が一致していることに注目されたい。

16 Deep Learning 逆伝播

逆伝播とはなにか?なんのために存在するのか?と疑問に思うのは当然である。
結論から言うと、順伝播のほかに、逆伝播が、勾配の更新に必要だからである。
順伝播だけだと、計算量が異常に増えるため、逆伝播が必要だという認識のもと、
この写経を読んでいただきたい所存である。

16.1 加算ノードの逆伝播

数式z=x+yに対して、逆伝播を考える。z=x+yの微分を解析的に計算すると以下のようになる。

\[ \begin{array}{l} \frac{\partial z}{\partial x} = 1 \\ \frac{\partial z}{\partial y} = 1 \tag{16.1} \end{array} \]

上式(16.1)の通り、dz/dxとdz/dyは、ともに1となる。

計算グラフで表すと下図のようになる。

この例では、上流から伝わった微分をdL/dzとしたが、最終的にLを出力する大きな計算グラフを想定している。

分かりにくいので具体例を示す。10+5=15という計算があるとして、上流から1.3の値が流れてくるとする。これを計算グラフで書くと下図のようになる。

加算ノードの逆伝播は入力信号を次のノードへ出力するだけなので、上図のように1.3をそのまま次の(逆方向の)ノードへ流す。

16.2 乗算ノードの逆伝播

乗算ノードの逆伝播について説明する。ここでは、z=xyという式を考える。この式の解析的な微分は、次式(16.2)で表される。

\[ \begin{array}{l} \frac{\partial z}{\partial x} = y \\ \frac{\partial z}{\partial y} = x \tag{16.2} \end{array} \]

乗算の逆伝播の場合は、上流の値に、順伝播の際の入力信号を”ひっくり返した値”を乗算して下流へ流す。

乗算の逆伝播は、入力信号をひっくり返した値を乗算するので、1.3*5 = 6.5、
1.3*10=13とそれぞれ計算できる。

加算の逆伝播では、上流の値をただ下流に流すだけだったので、順伝播の入力信号の値は必要なかったが、一方乗算の逆伝播では、順伝播のときの入力信号の値が必要になる。このため、乗算ノードの実装時には、順伝播の入力信号を保持する。