- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
一段时间以来,我一直在苦思冥想,无法弄清楚我在实现这些 RNN 时做错了什么(如果有的话)。为了让你们省去前向阶段,我可以告诉你们这两个实现计算相同的输出,所以前向阶段是正确的。问题出在倒退阶段。
这是我的 python 反向代码。它非常接近但不完全遵循 karpathy 的 neuraltalk 风格:
def backward(self, cache, target,c=leastsquares_cost, dc=leastsquares_dcost):
'''
cache is from forward pass
c is a cost function
dc is a function used as dc(output, target) which gives the gradient dc/doutput
'''
XdotW = cache['XdotW'] #num_time_steps x hidden_size
Hin = cache['Hin'] # num_time_steps x hidden_size
T = Hin.shape[0]
Hout = cache['Hout']
Xin = cache['Xin']
Xout = cache['Xout']
Oin = cache['Oin'] # num_time_steps x output_size
Oout=cache['Oout']
dcdOin = dc(Oout, target) # this will be num_time_steps x num_outputs. these are dc/dO_j
dcdWho = np.dot(Hout.transpose(), dcdOin) # this is the sum of outer products for all time
# bias term is added at the end with coefficient 1 hence the dot product is just the sum
dcdbho = np.sum(dcdOin, axis=0, keepdims=True) #this sums all the time steps
dcdHout = np.dot(dcdOin, self.Who.transpose()) #reflects dcdHout_ij should be the dot product of dcdoin and the i'th row of Who; this is only for the outputs
# now go back in time
dcdHin = np.zeros(dcdHout.shape)
# for t=T we can ignore the other term (error from the next timestep). self.df is derivative of activation function (here, tanh):
dcdHin[T-1] = self.df(Hin[T-1]) * dcdHout[T-1] # because we don't need to worry about the next timestep, dcdHout is already corrent for t=T
for t in reversed(xrange(T-1)):
# we need to add to dcdHout[t] the error from the next timestep
dcdHout[t] += np.dot(dcdHin[t], self.Whh.transpose())
# now we have the correct form for dcdHout[t]
dcdHin[t] = self.df(Hin[t]) * dcdHout[t]
# now we've gone through all t, and we can continue
dcdWhh = np.zeros(self.Whh.shape)
for t in range(T-1): #skip T bc dHdin[T+1] doesn't exist
dcdWhh += np.outer(Hout[t], dcdHin[t+1])
# and we can do bias as well
dcdbhh = np.sum(dcdHin,axis=0, keepdims=True)
# now we need to go back to the embeddings
dcdWxh = np.dot(Xout.transpose(), dcdHin)
return {'dcdOout': dcdOout, 'dcdWxh': dcdWxh, 'dcdWhh': dcdWhh, 'dcdWho': dcdWho, 'dcdbhh': dcdbhh, 'dcdbho': dcdbho, 'cost':c(Oout, target)}
这里是 theano 代码(主要是从我在网上找到的另一个实现复制的。我将权重初始化为我的纯 python rnn 的随机权重,以便一切都相同。):
# input (where first dimension is time)
u = TT.matrix()
# target (where first dimension is time)
t = TT.matrix()
# initial hidden state of the RNN
h0 = TT.vector()
# learning rate
lr = TT.scalar()
# recurrent weights as a shared variable
W = theano.shared(rnn.Whh)
# input to hidden layer weights
W_in = theano.shared(rnn.Wxh)
# hidden to output layer weights
W_out = theano.shared(rnn.Who)
# bias 1
b_h = theano.shared(rnn.bhh[0])
# bias 2
b_o = theano.shared(rnn.bho[0])
# recurrent function (using tanh activation function) and linear output
# activation function
def step(u_t, h_tm1, W, W_in, W_out):
h_t = TT.tanh(TT.dot(u_t, W_in) + TT.dot(h_tm1, W) + b_h)
y_t = TT.dot(h_t, W_out) + b_o
return h_t, y_t
# the hidden state `h` for the entire sequence, and the output for the
# entrie sequence `y` (first dimension is always time)
[h, y], _ = theano.scan(step,
sequences=u,
outputs_info=[h0, None],
non_sequences=[W, W_in, W_out])
# error between output and target
error = (.5*(y - t) ** 2).sum()
# gradients on the weights using BPTT
gW, gW_in, gW_out, gb_h, gb_o = TT.grad(error, [W, W_in, W_out, b_h, b_o])
# training function, that computes the error and updates the weights using
# SGD.
现在这是疯狂的事情。如果我运行以下命令:
fn = theano.function([h0, u, t, lr],
[error, y, h, gW, gW_in, gW_out, gb_h, gb_o],
updates={W: W - lr * gW,
W_in: W_in - lr * gW_in,
W_out: W_out - lr * gW_out})
er, yout, hout, gWhh, gWhx, gWho, gbh, gbo =fn(numpy.zeros((n,)), numpy.eye(5), numpy.eye(5),.01)
cache = rnn.forward(np.eye(5))
bc = rnn.backward(cache, np.eye(5))
print "sum difference between gWho (theano) and bc['dcdWho'] (pure python):"
print np.sum(gWho - bc['dcdWho'])
print "sum differnce between gWhh(theano) and bc['dcdWho'] (pure python):"
print np.sum(gWhh - bc['dcdWhh'])
print "sum difference between gWhx (theano) and bc['dcdWxh'] (pure pyython):"
print np.sum(gWhx - bc['dcdWxh'])
print "sum different between the last row of gWhx (theano) and the last row of bc['dcdWxh'] (pure python):"
print np.sum(gWhx[-1] - bc['dcdWxh'][-1])
我得到以下输出:
sum difference between gWho (theano) and bc['dcdWho'] (pure python):
-4.59268040265e-16
sum differnce between gWhh(theano) and bc['dcdWhh'] (pure python):
0.120527063611
sum difference between gWhx (theano) and bc['dcdWxh'] (pure pyython):
-0.332613468652
sum different between the last row of gWhx (theano) and the last row of bc['dcdWxh'] (pure python):
4.33680868994e-18
因此,我得到了隐藏层和输出权之间的权重矩阵的导数,但不是隐藏层 -> 隐藏或输入 -> 隐藏的权重矩阵的导数。但这个疯狂的事情是我总是得到权重矩阵输入的最后一行 ->隐藏正确。这对我来说太疯狂了。我不知道这里发生了什么。请注意,权重矩阵 input -> hidden 的最后一行不对应于最后一个时间步或任何东西(例如,这可以通过我为最后一个时间步正确计算导数但没有正确地传播回时间来解释)。 dcdWxh 是 dcdWxh 所有时间步长的总和——那么我怎样才能得到这一行正确而其他行都没有呢???
有人可以帮忙吗?我在这里完全没有想法。
最佳答案
您应该计算两个矩阵之差的逐点绝对值之和。由于特定的学习任务(您是否模拟零函数?:),无论是哪个,普通总和可能接近于零。
最后一行大概实现了来自常量神经元的权重,即偏差,因此您 - 似乎 - 总是获得正确的偏差(但是,检查绝对值的总和)。
它看起来也像矩阵的行优先和列优先符号混淆,就像在
gWhx - bc['dcdWxh']
它读起来像权重从“隐藏到 x”与“x 到隐藏”相反。
我宁愿将此作为评论发布,但我缺乏这样做的声誉。对不起!
关于python - pure-python RNN 和 theano RNN 计算不同的梯度——提供的代码和结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27544698/
在我学习期间Typoclassopedia我遇到了这个证明,但我不确定我的证明是否正确。问题是: One might imagine a variant of the interchange law
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 已关闭 8 年前。 Improve
我的理解是,“纯 OCaml”是指 OCaml 中标准的所有内容,包括其非“纯”功能特性,而“纯功能”是指通常的属性:没有副作用、没有异常处理等。从这个意义上说,“纯 OCaml” 实现与使用 C 或
Haskell 被称为“纯函数式语言”。 在这种情况下“纯粹”是什么意思?这会给程序员带来什么后果? 最佳答案 在纯函数式语言中,您不能做任何有副作用的事情。 副作用意味着计算表达式会改变某些内部状态
这是接口(interface)契约类的一部分。 [Pure] public bool IsDirty() { throw new NotImplementedException(); } pu
我想问一下 pure-g 和 pure-g-r 有什么区别。我曾经认为响应式会让我的 div 在较低的分辨率下不会崩溃但是使用 pure-g 也帮助我实现了同样的效果,所以我对它们之间的正确区别感到困
在source code of GHC.Base , Applicative Maybe 定义为: instance Applicative Maybe where pure = Just
这个问题在这里已经有了答案: Purpose of (0, obj.method)(param1, param2) in Closure Compiler minified code (1 个回答)
如何向 React 发出信号,表明函数组件是“纯”的,相当于组件类的 React.PureComponent ? function C(props) { return {props.n} } 没有
已阅读官方React documentation ,我遇到过this关于PureComponent: Furthermore, React.PureComponent’s shouldComponen
我有以下代码片段,我想知道它是纯 C 还是包含一些 C++ 元素。这个问题源于我认为它只是 C,但有些编译器不接受代码。 // User struct derived from Function
一个简单的问题。我应该如何在数据库中存储电话号码和电子邮件地址?只是像 email@email.com 这样的纯文本(或数字),还是用 key 对其进行编码更好(有点像密码在数据库中的保存方式)。在那
有人可以向我展示一个示例,说明我如何使用 purecss.io 来实现固定宽度/响应式设计,类似于 bootstrap 等 960 网格???? 流体宽度根本不适用于我的特定设计,这是我目前拥有的:
是否有一套通用规则/指南可以帮助您了解何时更喜欢pragma Pure,pragma Preelaborate或其他什么东西? standard (Ada 2012)中提供的规则和定义有些繁琐,我很高
我试图区分包含字母字符数据的单元格和数字数据单元格。我使用 istext() 和 isnumber() 取得了部分成功。但是当出现字母数字字符时,这种逻辑就会失败。 我的目的是检测只有字母的单元格。包
在Clash官方网站上,有以下示例: >>> sampleN @System 4 (register 0 (pure (8 :: Signed 8))) 我知道什么是纯函数,但为什么这里有 this
据我了解,javascript 要么在浏览器中运行,要么作为 Node.js 中的后端运行。 浏览器或 Node.js,根据您运行 JavaScript 的位置,将通过 Web API 或 C++ A
class Applicative f => Monad f where return :: a -> f a (>>=) :: f a -> (a -> f b) ->
在我看来,Fortran 中所谓的纯函数对于那些使用函数式编程的人来说似乎不够纯粹。这是我的问题。假设我有以下代码: MODULE basics IMPLICIT NONE INTEGER,
在Clash官方网站上,有以下示例: >>> sampleN @System 4 (register 0 (pure (8 :: Signed 8))) 我知道什么是纯函数,但为什么这里有 this
我是一名优秀的程序员,十分优秀!