【问题标题】:Using quantile in Flux (Julia) in loss function在损失函数中使用 Flux (Julia) 中的分位数
【发布时间】:2020-05-03 18:07:09
【问题描述】:

我正在尝试在损失函数中使用分位数进行训练! (对于某些稳健性,例如最小修剪平方),但它会改变数组并且 Zygote 会抛出来自 sort! 的错误 Mutating arrays is not supported。下面是一个简单的例子(内容当然没有意义):

using Flux, StatsBase
xdata = randn(2, 100)   
ydata = randn(100)

model = Chain(Dense(2,10), Dense(10, 1))


function trimmedLoss(x,y; trimFrac=0.f05)
        yhat = model(x)
        absRes = abs.(yhat .- y) |> vec
        trimVal = quantile(absRes, 1.f0-trimFrac) 
        s = sum(ifelse.(absRes .> trimVal,  0.f0 , absRes ))/(length(absRes)*(1.f0-trimFrac))
        #s = sum(absRes)/length(absRes)   # using this and commenting out the two above works (no surprise)    
end

println(trimmedLoss(xdata, ydata)) #works ok

Flux.train!(trimmedLoss, params(model), zip([xdata], [ydata]), ADAM())

println(trimmedLoss(xdata, ydata)) #changed loss?

这一切都在 Flux 0.10 和 Julia 1.2 中

提前感谢任何提示或解决方法!

【问题讨论】:

  • 这不是像教科书中的不可微损失函数示例吗?如果是这样,我已经看到了一些用无梯度优化器训练 Flux NN 的 hacky 代码,但我手头没有。
  • 或许你可以把问题分解成一个可微的损失和投影到一个凸集上,然后实现一个投影梯度法? OTOH,我不确定这是否明智,因为无论如何损失都不会是凸的......
  • 是的,当然严格来说它是不可微的。但是,启发式地,它与其他优化器(Levenberg-Marq 等)一起工作得很好,特别是当修剪的分数很小时。使用随机梯度下降,恕我直言,它甚至应该更不重要。它在早期版本的 Flux 中工作,没有 Zygote。

标签: machine-learning julia flux.jl


【解决方案1】:

理想情况下,我们会为quantile 定义一个custom adjoint,以便开箱即用。 (请随时打开issue 提醒我们这样做。)

与此同时,有一个快速的解决方法。实际上是排序在这里造成了麻烦,所以如果你这样做 quantile(xs, p, sorted=true) 它会起作用。显然这需要对xs 进行排序以获得正确的结果,因此您可能需要使用quantile(sort(xs), ...)

根据您的 Zygote 版本,您可能还需要 sort 的伴奏。那很简单:

julia> using Zygote: @adjoint

julia> @adjoint function sort(x)
         p = sortperm(x)
         x[p], x̄ -> (x̄[invperm(p)],)
       end

julia> gradient(x -> quantile(sort(x), 0.5, sorted=true), [1, 2, 3, 3])
([0.0, 0.5, 0.5, 0.0],)

我们将在下一个 Zygote 版本中内置该功能,但现在,如果您将其添加到脚本中,它将使您的代码正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-31
    • 2020-10-05
    • 2019-03-16
    • 2021-02-20
    • 2018-05-13
    相关资源
    最近更新 更多