Я не думаю, что простые функции можно использовать в качестве слоев в Flux. Вам нужно использовать макрос @functor
, чтобы добавить дополнительную функциональность для сбора параметров: https://fluxml.ai/Flux.jl/stable/models/basics/#Layer -helpers-1
В вашем случае, переписав Even
, InvEven
, Odd
и InvOdd
, как это должно помочь:
struct Even
model
end
(e::Even)(x) = x .+ even_mask(x).*e.model(even_duplicate(x))
Flux.@functor Even
После добавления этого определения
Flux.params(Even(m1))
Должен возвращать непустой список
EDIT
Еще более простой способ реализовать Even
и друзей - использовать встроенный слой SkipConnection :
Even(m) = SkipConnection(Chain(even_duplicate, m),
(mx, x) -> x .+ even_mask(x) .* mx)
Я подозреваю, что это это разница в версии, но с Julia 1.4.1 и Flux v0.10.4 я получаю ошибку BoundsError: attempt to access () at index [1]
при запуске тренировки l oop, мне нужно заменить данные на
x = [(rand(4,100), 0)]
В противном случае потеря применяется к каждой записи в массиве x
. поскольку train!
разбивает loss
более x
.
Следующая ошибка mutating arrays is not supported
связана с реализацией *_mask
и *_duplicate
. Эти функции создают массив нулей и затем изменяют его, заменяя значения из ввода.
Вы можете использовать Zygote.Buffer для реализации этого кода способом, который можно дифференцировать.
using Flux
using Zygote: Buffer
function even_mask(x)
s1, s2 = size(x)
weight_mask = Buffer(x)
weight_mask[2:2:s1,:] = ones(Int(s1/2), s2)
weight_mask[1:2:s1,:] = zeros(Int(s1/2), s2)
return copy(weight_mask)
end
function odd_mask(x)
s1, s2 = size(x)
weight_mask = Buffer(x)
weight_mask[2:2:s1,:] = zeros(Int(s1/2), s2)
weight_mask[1:2:s1,:] = ones(Int(s1/2), s2)
return copy(weight_mask)
end
function even_duplicate(x)
s1, s2 = size(x)
x_ = Buffer(x)
x_[1:2:s1,:] = x[1:2:s1,:]
x_[2:2:s1,:] = x[1:2:s1,:]
return copy(x_)
end
function odd_duplicate(x)
s1, s2 = size(x)
x_ = Buffer(x)
x_[1:2:s1,:] = x[2:2:s1,:]
x_[2:2:s1,:] = x[2:2:s1,:]
return copy(x_)
end
Even(m) = SkipConnection(Chain(even_duplicate, m),
(mx, x) -> x .+ even_mask(x) .* mx)
InvEven(m) = SkipConnection(Chain(even_duplicate, m),
(mx, x) -> x .- even_mask(x) .* mx)
Odd(m) = SkipConnection(Chain(odd_duplicate, m),
(mx, x) -> x .+ odd_mask(x) .* mx)
InvOdd(m) = SkipConnection(Chain(odd_duplicate, m),
(mx, x) -> x .- odd_mask(x) .* mx)
m1 = Chain(Dense(4,6,relu), Dense(6,5,relu), Dense(5,4))
m2 = Chain(Dense(4,7,relu), Dense(7,4))
forward = Chain(Even(m1), Odd(m2))
inverse = Chain(InvOdd(m2), InvEven(m1))
function loss(x, y)
z = forward(x)
return 0.5*sum(z.*z)
end
opt = Flux.ADAM(1e-6)
x = [(rand(4,100), 0)]
function train!()
for i=1:100
Flux.train!(loss, Flux.params(forward), x, opt)
println(loss(x[1]...))
end
end
На этом этапе вы получите настоящее удовольствие от глубоких сетей. После одного шага обучения обучение расходится до NaN
со скоростью обучения по умолчанию. Снижение начальной скорости тренировки до 1e-6 помогает, и потеря выглядит так, как будто она уменьшается.