1

在我上一个关于使用 Flux 训练循环神经网络的困惑之后,我更深入地研究了 Flux 训练过程,现在我更加困惑了。我认为我的麻烦在于在loss函数中使用总和,因此损失会考虑到序列中的许多点。请参见此处,其中损失定义为:

loss(x, y) = sum((Flux.stack(m.(x),1) .- y) .^ 2)

如果x是具有多个点的序列,并且y是每个点的对应输出,则此loss函数评估整个序列的损失。我想了解的是 Flux 如何采用这样的函数的梯度。想象一下将其简化为:

L(x, y) = sum((Flux.stack(m.(x), 1) .- y))

我们还可以创建一个非常简单的循环神经“网络”作为单个 1 -> 1 节点,没有激活函数:

m = Flux.RNN(1, 1, x -> x)

这(有点)相当于:

h = [0.0]
function m(x)
    y = Wx .* x + Wh .* h .+ b
    global h = y
    return y
end

loss相对于的梯度是Wx多少?取一个包含两个点的序列,x = [x1, x2] 和 y* = [y1*, y2*]。将 x1 通过 RNN 得到:

y1 = h2 = Wx*x1 + Wh*h1 + b

然后把 x2 通过,你得到:

y2 = h3 = Wx*x2 + Wh*h2 + b = Wx*x2 + Wh*(Wx*x1 + Wh*h1 + b) + b。

现在计算损失:

L = y1 - y1* + y2 - y2* = Wx*x1 + Wh*h1 + b - y1* + Wx*x2 + Wh*(Wx*x1 + Wh*h1 + b) + b - y2*

很明显,dL/dWx 应该是 x1 + x2 + Wh*x1。所以让我们说x并且y是:

x = [[0.3], [2.5]]
y = [0.5, 1.0]

并且参数被初始化为:

Wxs = [0.5]
Whs = [0.001]
bs = [0.85]

如果计算 dL/DWx = x1 + x2 + Wh*x1,则为 2.8003。您也可以尝试有限差分:

h = [0.0]
q = loss(x, y)
Wx .+= 0.01
h = [0.0]
r = loss(x, y)
abs(q - r)/0.01 # = 2.8003

并得到 2.8003。但是如果你使用 Flux 的gradient功能:

Wx = [0.5]
h = [0.0]
gs = gradient(() -> loss(x, y), params(Wx, Wh, b))
gs[Wxs] # = 2.8025

你得到 2.8025,这似乎是 x1 + x2 + Wh*x2。我不明白为什么结果会有所不同,尤其是考虑到在评估两个不同的损失函数本身时一切都是一致的。有什么我忽略的吗?里面有什么奇怪的事情gradient吗?

4

0 回答 0