Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cs231n/assignment3/cs231n/rnn_layers.py/line:147 #4

Open
liferlisiqi opened this issue Apr 24, 2018 · 2 comments
Open

cs231n/assignment3/cs231n/rnn_layers.py/line:147 #4

liferlisiqi opened this issue Apr 24, 2018 · 2 comments

Comments

@liferlisiqi
Copy link

请问使用上面写的rnn_step_backward反向传播时,为什么dnext_h参数是dh[:, t, :] + stepdprev_h呢?如下:
stepdx, stepdprev_h, stepdWx, stepdWh, stepdb = rnn_step_backward(dh[:, t, :] + stepdprev_h, cache[t])

@Halfish
Copy link
Owner

Halfish commented Apr 27, 2018

这个是 truncate BPTT 算法,因为 RNN 公式中有一个 h_t = tanh(W_x * x_t + W_h * h_{t-1} + b),所以 t 时刻的交叉熵 L_t 不仅对 h_t 有导数,而且对 h_{t-1} 也有导数;递归的,又因为 h_{t-1} 也包含了 h_{t-2} 所以 L_t 对 h_{t-2} 实际上也是有导数的。可以参考 Recurrent Neural Networks Tutorial, Part 3 – Backpropagation Through Time and Vanishing Gradients 的前两张图片展示结果。反向传播的结果和前向传播的箭头正好是相反的,可以看出来是有两个方向的梯度回传回来的。

这里的实现是只取 truncate_size = 1,比如 t 时刻交叉熵 L_t 对 h_t 的导数是变量 dh[:, t, :](从图上看,是从上往下的梯度回传),但是 t+1 时刻的交叉熵也对 h_t 有导数(从图上看,是从右往左的梯度回传),这个导数放在了 stepdpred_h 这个变量里。两者加起来才是真正的导数(其实这样讲不严谨,如果 truncate_size = 2,需要把 t+2 时刻的情况也算上了;如果是原始的 BPTT,需要从最后一个时刻开始回传导数,这样才是真正的导数)。

注意到 t 时刻的 rnn_step_backward 算出了对 h_{t-1} 的导数(从右往左的梯度回传),那么暂时存放在 stepdprev_h 这个变量里,等到下时刻和交叉熵的导数加在一起(从上往下的梯度回传),才是 h_{t-1} 真正的导数。

@liferlisiqi
Copy link
Author

你的解释很详细,非常感谢。
你说的第三个点我好像明白了,是说h的导数是来自于下一时刻和自身两个方向是吧
然后第一、二点,你的意思是这里的实现是原始的BPTT的一种情况是吗?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants