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()は逆伝播ん(逆方向の伝播)に対応する。乗算レイヤは下記のように実装できる。

class MulLayer:
    def __init__(self):
        self.x = None
        self.y = None

    def forward(self, x, y):
        self.x = x
        self.y = y                
        out = x * y

        return out

    def backward(self, dout):
        dx = dout * self.y
        dy = dout * self.x

        return dx, dy

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

# coding: utf-8


class MulLayer:
    def __init__(self):
        self.x = None
        self.y = None

    def forward(self, x, y):
        self.x = x
        self.y = y                
        out = x * y

        return out

    def backward(self, dout):
        dx = dout * self.y
        dy = dout * self.x
        
        return dx, dy

apple = 100
apple_num = 2
tax = 1.1

mul_apple_layer = MulLayer() # 1st layer
mul_tax_layer = MulLayer() # 2nd layer

# forward
apple_price = mul_apple_layer.forward(apple, apple_num)
price = mul_tax_layer.forward(apple_price, tax)

# backward
dprice = 1
dapple_price, dtax = mul_tax_layer.backward(dprice)
dapple, dapple_num = mul_apple_layer.backward(dapple_price)

print("price:", int(price))
print("dApple:", dapple)
print("dApple_num:", int(dapple_num))
print("dTax:", dtax)

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

$python 16_simplelayer.py

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