バックプロップでソフトマックスの勾配を適用する方法


8

私は最近、MNISTの10桁分類のモデルを学習する必要がある宿題をしました。HWにはいくつかの足場コードがあり、私はこのコードのコンテキストで作業することになっていた。

私の宿題は機能します/テストに合格しましたが、今はすべてをゼロから実行しようとしています(自分のnnフレームワーク、ハードウェアスキャフォールディングコードなし)。バックプロップステップでソフトマックスの壮大さを適用して立ち往生しています。足場コードは正しくない可能性があります。

ハードウェアでは、nnの最後のノードとして、「softmax loss」と呼ばれるものを使用します。つまり、何らかの理由で、ソフトマックスをアクティベーション関数として扱い、クロスエントロピーを個別の損失関数として扱うのではなく、クロスエントロピー損失と一緒にソフトマックスのアクティベーションに参加することにしました。

hw loss funcは次のようになります(最低限私が編集します)。

class SoftmaxLoss:
    """
    A batched softmax loss, used for classification problems.
    input[0] (the prediction) = np.array of dims batch_size x 10
    input[1] (the truth) = np.array of dims batch_size x 10
    """
    @staticmethod
    def softmax(input):
        exp = np.exp(input - np.max(input, axis=1, keepdims=True))
        return exp / np.sum(exp, axis=1, keepdims=True)

    @staticmethod
    def forward(inputs):
        softmax = SoftmaxLoss.softmax(inputs[0])
        labels = inputs[1]
        return np.mean(-np.sum(labels * np.log(softmax), axis=1))

    @staticmethod
    def backward(inputs, gradient):
        softmax = SoftmaxLoss.softmax(inputs[0])
        return [
            gradient * (softmax - inputs[1]) / inputs[0].shape[0],
            gradient * (-np.log(softmax)) / inputs[0].shape[0]
        ]

ご覧のように、フォワードでは、softmax(x)を実行してから、エントロピー損失をクロスします。

しかし、バックプロップでは、クロスエントロピーの導関数のみを実行し、ソフトマックスの導関数を実行しないようです。Softmaxはそのままです。

また、softmaxへの入力に関するsoftmaxの導関数も必要ではありませんか?

それがsoftmaxの派生物を取るべきだと仮定すると、私はこのハードウェアが実際にテストに合格する方法がわかりません...

今、私自身のゼロからの実装では、ソフトマックスとクロスエントロピーを別々のノードにしました(pとtは予測と真実を表します)。

class SoftMax(NetNode):
    def __init__(self, x):
        ex = np.exp(x.data - np.max(x.data, axis=1, keepdims=True))
        super().__init__(ex / np.sum(ex, axis=1, keepdims=True), x)

    def _back(self, x):
        g = self.data * (np.eye(self.data.shape[0]) - self.data)
        x.g += self.g * g
        super()._back()

class LCE(NetNode):
    def __init__(self, p, t):
        super().__init__(
            np.mean(-np.sum(t.data * np.log(p.data), axis=1)),
            p, t
        )

    def _back(self, p, t):
        p.g += self.g * (p.data - t.data) / t.data.shape[0]
        t.g += self.g * -np.log(p.data) / t.data.shape[0]
        super()._back()

ご覧のように、私のクロスエントロピー損失(LCE)はハードウェアのそれと同じ導関数を持っています。これは、損失自体の導関数であるため、まだソフトマックスに入らないためです。

しかし、それでも、私はそれを損失の導関数とつなげるために、ソフトマックスの導関数を実行する必要があります。これは私が行き詰まるところです。

次のように定義されたsoftmaxの場合:

a

導関数は通常、次のように定義されます。

b

しかし、私はsoftmaxへの入力と同じサイズのテンソルをもたらす導関数が必要です。この場合、batch_size x 10です。したがって、10のコンポーネントだけに上記を適用する必要があるかどうかはわかりません。すべての出力(すべての組み合わせ)に関して、またはc行列形式で、すべての入力を区別します。


これをcodereviewまたはstackoverflowに投稿する必要があると思います
DuttaA 2018年

どうして?それはニューラルネットのバックプロップの質問です。AIスタック交換に属しています。

反対票を投じた人はAIに精通していない可能性があります...さて、問題は、バックプロパゲーションのコンテキスト、ニューラルネットワークのコンテキスト、機械学習のコンテキスト、コンテキストの偏微分を適用することです。 「AI」の文脈での教師あり学習の。これのどの部分か:1-研究の欠如を示します2-は「AI」に関連していません、3-は「私にcodezを送信する」種類の質問、4-は意見の質問です5-は質問の範囲が広すぎます?

ai.seのfaqから「それは...機械学習の実装についてではない」
mico

@micoわかりましたはい、そうです。しかし、私はそれを予想外に見つけました。つまり、AIアルゴリズムの数学と実装について議論することは、この分野(学問レベルを含む)では一般的な慣行です。
SaldaVonSchwartz 2018

回答:


5

これにさらに取り組んだ後、私はそれを理解しました:

  1. 宿題の実装では、選択の問題としてソフトマックスとクロスエントロピー損失を組み合わせますが、アクティベーション関数としてソフトマックスを分離しておくという私の選択も有効です。

  2. 宿題の実装には、実際にbackpropパスのsoftmaxの派生物がありません。

  3. 入力に関するsoftmaxの勾配は、実際には各入力に関する各出力の部分的です。

勾配1

ベクトル(勾配)フォームの場合: 勾配2

私のベクトル化されたnumpyコードではこれは単純です:

self.data * (1. - self.data)

ここで、self.data入力のソフトマックスは、以前に往路から計算。


3
これは正しいとは思いません。また、smax(x_i)/ x_jを計算する必要があります。ここで、j≠iで、個々の勾配をすべて合計します。これは、x_iのソフトマックスを計算するときに、他のすべてのパラメーターもソフトマックスの値を決定するために使用されるためです。
harveyslash
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.