Softmax-with-Lossレイヤ

Softmax-with-Lossレイヤを実装

def softmax(x):
    if x.ndim == 2:
        x = x.T
        x = x - np.max(x, axis=0)
        y = np.exp(x) / np.sum(np.exp(x), axis=0)
        return y.T 
    x = x - np.max(x)
    return np.exp(x) / np.sum(np.exp(x))

def cross_entropy_error(y, t):
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
        
    if t.size == y.size:
        t = t.argmax(axis=1)
             
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t] + 1e-7)) / batch_size

class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None
        self.t = None

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        return self.loss

    def backward(self, dy=1):
        batch_size = self.t.shape[0]
        dx = (self.y - self.t) / batch_size
        return dx

Softmaxレイヤは入力された値を正規化し、出力の和が1になるようにします。
入力に対してSoftmaxで処理し、誤差を求める関数で、出力層に配置します。

\( y(k) = \frac{\exp(a_k)}{\sum^n_{i=1}\exp(a_i)} \)

多値の識別問題に使います。
正規化するだけなので、重みの順序は変わりません。

損失関数として交差エントロピー誤差を使います。
logの中身が0にならないよう、1e-7といった小さい値を足しておきます。
損失関数を使う事により、学習の進捗が浮動小数点で扱えるようになり、離散的な問題の最適化においても、プラトーに遭遇しにくくなるようです。

ニューラルネットワークはとにかく0, 1のような離散数を出さないようにする工夫が多いですね。