2

最近我发现 Julia lang 变得更强大了,是时候重新审视它了。但是在每个教程中,我都发现双重推理存在同样的问题——对于每个批次,您必须计算模型以获得梯度,然后重新计算它以获得损失和其他指标。这似乎很荒谬,它必须是一条出路。我可以在不重新计算的情况下在梯度更新步骤之前获得模型预测及其损失吗?这里我为 MLP 和 MNIST 做了一个例子

using Flux, Flux.Data.MNIST, Statistics
using Flux: onehotbatch, onecold, crossentropy
using Flux.Optimise: update!
using Flux.Data: DataLoader
using Printf


X = hcat(float.(reshape.(MNIST.images(), :))...) |> gpu
Y = onehotbatch(MNIST.labels(), 0:9) |> gpu
m = Chain(
    Dense(784, 32, relu),
    Dense(32, 32, relu),
    Dense(32, 10),
    softmax
) |> gpu

loss(ŷ, y) = Flux.crossentropy(ŷ, y)
accuracy(x, y) = mean(onecold(cpu(x)) .== onecold(cpu(y)))
dl = DataLoader(X, Y, batchsize=128)
ps = params(m)
opt = Descent(0.1)
@progress for i = 1:10
    @info "Epoch $i"

    for (x, y) in dl
        gs = gradient(ps) do
            loss(m(x), y)
        end
        update!(opt, ps, gs)
    end

    vloss, vacc = [], []
    for (x,y) in dl
        ŷ = m(x)
        l = loss(ŷ, y)

        push!(vloss, l)
        push!(vacc, accuracy(ŷ, y))
    end
    @printf "Train :: loss: %-5f acc: %-5f\n" mean(vloss) mean(vacc)
end
4

1 回答 1

1

顺便说一句,反向模式 AD 的工作方式是,每次计算梯度时,无论如何都会返回所谓的“前向值”。如果您查看gradient Zygote 中的定义方式,您会发现可以使用pullback同时获取两者:

function value_and_gradient(f, args...)
    y, back = pullback(f, args...)
    return y, back(sensitivity(y))
end

sensitivity只是one,或者是不可微输出类型的错误。

于 2020-03-31T08:22:47.480 回答