逆伝播におけるバイアス項の勾配


13

ニューラルネットワークをゼロから実装して、その背後にある数学を理解しようとしました。私の問題は、バイアスに関する導関数を取るときの逆伝播に完全に関連しており、逆伝播で使用されるすべての方程式を導き出しました。これで、バイアスに関する微分を除いて、すべての方程式がニューラルネットワークのコードと一致しています。

z1=x.dot(theta1)+b1

h1=1/(1+np.exp(-z1))
z2=h1.dot(theta2)+b2
h2=1/(1+np.exp(-z2))

dh2=h2-y
#back prop

dz2=dh2*(1-dh2)
H1=np.transpose(h1)
dw2=np.dot(H1,dz2)
db2=np.sum(dz2,axis=0,keepdims=True)

オンラインでコードを検索しましたが、なぜ行列を加算してdb2=np.sum(dz2,axis=0,keepdims=True)からスカラーが元のバイアスから減算されるのか、行列全体が減算されないのはなぜですか。誰かがその背後にある直感を与えるのを手伝ってくれる?バイアスに関して損失の偏微分をとるz2=h1.dot(theta2)+b2と、h1とthetaが0になり、b2が1になるため、dz2である上部勾配のみが得られ ます。したがって、上部の項は残ります。

b2+=-alpha*db2

回答:


6

バイアス項は非常に単純です。そのため、計算されたものが表示されないことがよくあります。実際には

db2 = dz2

したがって、単一のアイテムに対するバイアスの更新ルールは次のとおりです。

b2 += -alpha * dz2

そして

b1 += -alpha * dz1

数学の面では、あなたの損失が J、 あなたが知っています Jz 与えられたニューロンに対して バイアス項がある b。。。

Jb=Jzzb

そして

zb=1

なぜなら z=影響を受けないもの b+b


コピーしたコードはフォームを使用しているようです

db2=np.sum(dz2,axis=0,keepdims=True)

ネットワークは(ミニ)バッチで例を処理するように設計されているため、一度に複数の例の勾配を計算できます。合計は、結果を1つの更新に縮小します。これは、重みの更新コードも表示した場合に確認しやすくなります。


はい、まさにそれが私の考えでした。それは数学的にそれがどのように見えるかです。しかし、私が見たコードは、行列を合計し、それをb1に追加しました。
user34042 2017

theta1=theta1-alpha*dw1 theta2=theta2-alpha*dw2 私はまだそれを取得しません。そうすれば、同じ用語が 'b'ベクトルのすべての異なる用語に追加されます。そうしないと、単一の用語ごとに異なる重みがあり、ニューラルネットワークが最小値を達成するのに大きな違いが生じます。
user34042 2017

@ user34042:何かが正しくないようです-そのコードを入手したソースをリンクできますか?ミニバッチコードと単純なオンライングラディエントディセントが混在しているため、ソースが間違っているのではないかと思います。
Neil Slater


ソースはそれが間違っていると思います。NNはすべてのバイアス値が同じである種の作業を行うため、気付かなかった可能性があります。そして、先ほど触れたように、実際にはそのコードをバッチベースのシナリオで使用する可能性があるため、カットアンドペーストエラーになる可能性があります。
Neil Slater

10

db2=np.sum(dz2,axis=0,keepdims=True)一度も戸惑って答えられなかったのでその意味を説明したいと思います。

誘導体LWRT(損失)bであり、上流の誘導体で乗算ローカル誘導体

Lb=LZZb

複数のサンプルがZありL、両方が行列である場合。bはまだベクトルです。

ローカル導関数は単に1のベクトルです

Zb=bW×バツ+b=1

つまり、完全な微分は行列乗算であり、次のようになります(たとえば、2つのサンプルと3つの出力)

LZ×1=[][111]

これは行の合計であることに注意してください。

そして、そこdb2=np.sum(dz2, axis=0, keepdims=True)から来ています。これは、ローカルと上流の導関数の行列乗算の略語です。


0

最初に、シグモイド関数の勾配の式を修正する必要があります。

シグモイド関数の1次導関数は次のとおりです。 (1−σ(x))σ(x)

dz2の式は次のようになります。 dz2 = (1-h2)*h2 * dh2

σ(x)勾配ではなく、シグモイド関数の出力を使用する必要があります。

この勾配は多くの単一の入力から得られるため、バイアスの勾配を合計する必要があります(入力の数=バッチサイズ)。したがって、レイヤー2のバイアスを更新するには、これらを累積する必要があります。ただし、グラデーションはレイヤー1に到達するため、レイヤー2の多くのノードから取得されるため、レイヤー1のバイアスと重みを更新するには、すべてのグラデーションを合計する必要があります。このケースは、レイヤー2のバイアスの合計とは異なります。

アクティベーション関数を持つ2つの完全に接続されたレイヤーの実装は、シグモイド関数です。

lr = 1e-3
f = lambda x: 1.0/(1.0 + np.exp(-x))
# pass through layer 1
out_l1 = np.dot(x, W_1) + b_1

out_s1 = f(out_l1)

# pass through layer 2
out_l2 = np.dot(x, W_2) + b_2

out_s2 = f(out_l2)

loss = get_loss(out_s2, y)

# BACKWARD PASS
grad = out_s2 - y

d_h2 = (1 - out_s2) * out_s2 * grad

# Accumulate the gradient come from all examples
d_W2 = out_s1.T.dot(d_h2)
d_b2 = np.sum(d_h2, axis=0, keepdims=True)

# sum of gradient come out from prev node:
grad_1 = np.sum(d_W2.T, axis=0, keepdims=True)
d_h1 = (1 - out_l1) * out_l1 * grad_1

d_W1 = x.T.dot(d_h1)
d_b1 = np.sum(d_h1, axis=0, keepdims=True)

W_1 -= d_W1 * lr
b_1 -= d_b1 * lr

W_2 -= d_W2 * lr
b_2 -= d_b2 * lr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.