- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
有人可以清楚地解释 LSTM RNN 的反向传播吗?这是我正在使用的类型结构。我的问题不是提出什么是反向传播,我理解它是计算假设误差和用于调整神经网络权重的输出的逆序方法。我的问题是 LSTM 反向传播与常规神经网络有何不同。
我不确定如何找到每个门的初始误差。您是否对每个门使用第一个误差(通过假设减去输出计算得出)?或者通过一些计算来调整每个门的误差?我不确定细胞状态在 LSTM 的反向传播中如何发挥作用(如果有的话)。我已经彻底寻找了 LSTM 的良好来源,但尚未找到。
最佳答案
这是个好问题。您当然应该查看建议的帖子以了解详细信息,但这里的完整示例也会有所帮助。
我认为首先讨论一个普通的 RNN(因为 LSTM 图特别令人困惑)并理解它的反向传播是有意义的。
说到反向传播,关键思想是网络展开,这是将 RNN 中的递归转换为前馈序列的方法(如上图所示)。请注意,抽象 RNN 是永恒的(可以任意大),但每个特定的实现都是有限的,因为内存是有限的。因此,展开的网络实际上是一个长前馈网络,几乎没有复杂性,例如不同层的权重是共享的。
让我们看一个经典的例子,char-rnn by Andrej Karpathy 。这里,每个 RNN 单元产生两个输出 h[t]
(馈入下一个单元的状态)和 y[t]
(此步骤的输出)以下公式,其中 Wxh
、Whh
和 Why
是共享参数:
在代码中,它只是三个矩阵和两个偏置向量:
# model parameters
Wxh = np.random.randn(hidden_size, vocab_size)*0.01 # input to hidden
Whh = np.random.randn(hidden_size, hidden_size)*0.01 # hidden to hidden
Why = np.random.randn(vocab_size, hidden_size)*0.01 # hidden to output
bh = np.zeros((hidden_size, 1)) # hidden bias
by = np.zeros((vocab_size, 1)) # output bias
前向传递非常简单,这个例子使用了softmax和交叉熵损失。请注意,每次迭代都使用相同的 W*
和 h*
数组,但输出和隐藏状态不同:
# forward pass
for t in xrange(len(inputs)):
xs[t] = np.zeros((vocab_size,1)) # encode in 1-of-k representation
xs[t][inputs[t]] = 1
hs[t] = np.tanh(np.dot(Wxh, xs[t]) + np.dot(Whh, hs[t-1]) + bh) # hidden state
ys[t] = np.dot(Why, hs[t]) + by # unnormalized log probabilities for next chars
ps[t] = np.exp(ys[t]) / np.sum(np.exp(ys[t])) # probabilities for next chars
loss += -np.log(ps[t][targets[t],0]) # softmax (cross-entropy loss)
现在,向后传递的执行方式与前馈网络完全相同,但 W*
和 h*
数组的梯度会累积所有梯度细胞:
for t in reversed(xrange(len(inputs))):
dy = np.copy(ps[t])
dy[targets[t]] -= 1
dWhy += np.dot(dy, hs[t].T)
dby += dy
dh = np.dot(Why.T, dy) + dhnext # backprop into h
dhraw = (1 - hs[t] * hs[t]) * dh # backprop through tanh nonlinearity
dbh += dhraw
dWxh += np.dot(dhraw, xs[t].T)
dWhh += np.dot(dhraw, hs[t-1].T)
dhnext = np.dot(Whh.T, dhraw)
上面的两遍都是以 len(inputs)
大小的 block 完成的,它对应于展开的 RNN 的大小。您可能希望使其更大以捕获输入中更长的依赖关系,但您需要通过存储每个单元格的所有输出和梯度来付出代价。
LSTM 图片和公式看起来很吓人,但是一旦您编写了简单的 RNN,LSTM 的实现就几乎相同了。例如,这是向后传递:
# Loop over all cells, like before
d_h_next_t = np.zeros((N, H))
d_c_next_t = np.zeros((N, H))
for t in reversed(xrange(T)):
d_x_t, d_h_prev_t, d_c_prev_t, d_Wx_t, d_Wh_t, d_b_t = lstm_step_backward(d_h_next_t + d_h[:,t,:], d_c_next_t, cache[t])
d_c_next_t = d_c_prev_t
d_h_next_t = d_h_prev_t
d_x[:,t,:] = d_x_t
d_h0 = d_h_prev_t
d_Wx += d_Wx_t
d_Wh += d_Wh_t
d_b += d_b_t
# The step in each cell
# Captures all LSTM complexity in few formulas.
def lstm_step_backward(d_next_h, d_next_c, cache):
"""
Backward pass for a single timestep of an LSTM.
Inputs:
- dnext_h: Gradients of next hidden state, of shape (N, H)
- dnext_c: Gradients of next cell state, of shape (N, H)
- cache: Values from the forward pass
Returns a tuple of:
- dx: Gradient of input data, of shape (N, D)
- dprev_h: Gradient of previous hidden state, of shape (N, H)
- dprev_c: Gradient of previous cell state, of shape (N, H)
- dWx: Gradient of input-to-hidden weights, of shape (D, 4H)
- dWh: Gradient of hidden-to-hidden weights, of shape (H, 4H)
- db: Gradient of biases, of shape (4H,)
"""
x, prev_h, prev_c, Wx, Wh, a, i, f, o, g, next_c, z, next_h = cache
d_z = o * d_next_h
d_o = z * d_next_h
d_next_c += (1 - z * z) * d_z
d_f = d_next_c * prev_c
d_prev_c = d_next_c * f
d_i = d_next_c * g
d_g = d_next_c * i
d_a_g = (1 - g * g) * d_g
d_a_o = o * (1 - o) * d_o
d_a_f = f * (1 - f) * d_f
d_a_i = i * (1 - i) * d_i
d_a = np.concatenate((d_a_i, d_a_f, d_a_o, d_a_g), axis=1)
d_prev_h = d_a.dot(Wh.T)
d_Wh = prev_h.T.dot(d_a)
d_x = d_a.dot(Wx.T)
d_Wx = x.T.dot(d_a)
d_b = np.sum(d_a, axis=0)
return d_x, d_prev_h, d_prev_c, d_Wx, d_Wh, d_b
现在,回到你的问题。
My question is how is LSTM backpropagation different then regular Neural Networks
它们是不同层中的共享权重,以及您需要注意的其他变量(状态)。除此之外,没有任何区别。
Do you use the first error (calculated by hypothesis minus output) for each gate? Or do you adjust the error for each gate through some calculation?
首先,损失函数不一定是 L2。在上面的示例中,它是交叉熵损失,因此初始误差信号得到其梯度:
# remember that ps is the probability distribution from the forward pass
dy = np.copy(ps[t])
dy[targets[t]] -= 1
请注意,它与普通前馈神经网络中的误差信号相同。如果使用 L2 损失,信号确实等于真实值减去实际输出。
对于 LSTM,情况稍微复杂一些:d_next_h = d_h_next_t + d_h[:,t,:]
,其中 d_h
是损失函数的上游梯度,这意味着每个单元的误差信号都会被累积。但再一次,如果您展开 LSTM,您将看到与网络布线的直接对应。
关于machine-learning - LSTM RNN 反向传播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41555576/
我能否获得一个具有两个参数的递归Prolog谓词,称为反向,它返回列表的反向: 示例查询和预期结果: α-反向([a,b,c],L)。 L = [c,b,a]。 由两个称为palindrome的参数组
在使用 get_dummies() 将分类数据转换为数字数据后,我的数据框看起来像这样 score1 score2 country_CN country _AU category_leader ca
我有一张 table ,上面有一个国家/地区列表。说这些国家之一是“马其顿” 如果搜索“马其顿共和国”,什么 SQL 查询会返回“马其顿”记录? 我相信在 linq 中它会是这样的 var count
我们有一个角色继承结构,它假设每个人都默认获得最低级别的角色,而不是最高级别的过滤,如下图所示: role.Everyone //lowest level; everyone gets this ro
我正在使用 $.each() 解析数组,但在其中,我使用 .splice() 方法,因此我需要向后迭代。这可能吗? var store = [...]; //... var rules = [...]
我有一个 SPLObjectStorage 对象,其中 Player 对象作为键,分数作为与之关联的信息。玩家对象按照从最高分到最低分的顺序添加到存储中,但我现在需要以相反的顺序遍历它们。 我还需要能
我无法理解这一点:如果我给 Prolog reverse([], A). 它工作得很好,如果我给它 reverse(A, [] ). 并根据第一个建议回答 ; 它挂起!为什么? (GNU Prolog
我有一个 SPLObjectStorage 对象,其中 Player 对象作为键,分数作为与之关联的信息。玩家对象按照从最高分到最低分的顺序添加到存储中,但我现在需要以相反的顺序遍历它们。 我还需要能
我有一个HashMap看起来像: HashMap playerHashMap = new HashMap<>(); 玩家是包含姓名、号码、年龄等的对象。 现在我已经对它进行了排序,它看起来像这样: k
我有这个: file://localhost/Volumes/Untitled%20RAID%20Set%201/Callum/iTunes/Music/Steppenwolf/Steppenwolf
我正在使用 std::regex 并希望找到与某个用户定义的正则表达式字符串匹配的字符串中的最后一个位置。 例如,给定正则表达式 :.* 和字符串“test:55:last”,我想找到“:last”,
有一个表 ServErog(服务),它被重新引导到 4 个表 ServA、ServB、ServC、ServD(它们是不同的非统一服务),其中包含 servtype(服务类型)和 type_id(来自其
这个问题在这里已经有了答案: What is the best way to convert date from JavaScript string in format YYYYMMDD to Ja
我知道如何获得包含几个词的所有结果: SELECT * FROM `table` WHERE MATCH (`row`) AGAINST ('+word1 +word2' IN BOOLEAN MOD
你好,我有这个 html 代码: .container{ width: 450; height: 400; border:1px solid
我想知道是否有任何方法可以使用相同的 CSS 过渡实例来将其向前移动然后向后/向后移动。例如,假设我有这种转变: @-webkit-keyframes fade-transition { fr
假设我有这些字符串: char ref[30] = "1234567891234567891"; char oth[30] = "1234567891234567891"; 我想在 C++ 中使用 S
所以我有这段代码,它使 xcode 崩溃 void strrev(const std::string& str) { for(size_t i=str.length();i>=0;i--)
我正在使用下面的代码使每张图片 1 对 1 淡入淡出。我怎样才能反向执行此操作以使图片以相反的顺序加载? img {display:none;} $('img').each(function(
我正在尝试弄清楚如何改变 FrameLayout 堆叠其子项的方式。 目前它是最新的(先进先出)。我想更改它,使最新的 child 位于底部(FILO)。我试着查看 FrameLayout 的源代码,
我是一名优秀的程序员,十分优秀!