Подгонка нейронной сети с ReLU к полиномиальным функциям

Из любопытства я пытаюсь подогнать нейронную сеть с выпрямленными линейными блоками к полиномиальным функциям. Например, я хотел бы увидеть, насколько легко (или сложно) нейронной сети придумать приближение для функцииf(x) = x^2 + x. Следующий код должен уметь это делать, но, похоже, ничего не узнает. Когда я бегу

using Base.Iterators: repeated
ENV["JULIA_CUDA_SILENT"] = true
using Flux
using Flux: throttle
using Random

f(x) = x^2 + x
x_train = shuffle(1:1000)
y_train = f.(x_train)
x_train = hcat(x_train...)

m = Chain(
    Dense(1, 45, relu),
    Dense(45, 45, relu),
    Dense(45, 1),
    softmax
)

function loss(x, y) 
    Flux.mse(m(x), y)
end

evalcb = () -> @show(loss(x_train, y_train))
opt = ADAM()

@show loss(x_train, y_train)

dataset = repeated((x_train, y_train), 50)

Flux.train!(loss, params(m), dataset, opt, cb = throttle(evalcb, 10))

println("Training finished")

@show m([20])

он возвращается

loss(x_train, y_train) = 2.0100101f14
loss(x_train, y_train) = 2.0100101f14
loss(x_train, y_train) = 2.0100101f14
Training finished
m([20]) = Float32[1.0]

Любой здесь видит, как я могу подогнать сеть f(x) = x^2 + x?

1 ответ

Решение

Кажется, в вашей пробной версии есть несколько ошибок, которые в основном связаны с тем, как вы используете свой оптимизатор и обрабатываете свой ввод - ничего плохого с Julia или Flux. Предлагаемое решение действительно обучается, но ни в коем случае не является оптимальным.

  • Нет смысла включать выход softmax для задачи регрессии. Softmax используется в задачах классификации, где выходные данные вашей модели представляют вероятности и, следовательно, должны находиться в интервале (0,1). Понятно, что ваш многочлен имеет значения за пределами этого интервала. В подобных регрессионных задачах обычно используется активация линейного выхода. Это означает, что в Flux не следует определять активацию вывода на уровне вывода.
  • Форма ваших данных имеет значение. train! вычисляет градиенты для loss(d...) где d это партия в вашем data. В вашем случае мини-партия состоит из 1000 образцов, и эта же партия повторяется 50 раз. Нейронные сети часто обучаются с меньшими размерами пакетов, но с большим набором выборок. В коде, который я предоставил, все партии состоят из разных данных.
  • Для обучения нейронных сетей, как правило, рекомендуется нормализовать вводимые данные. Ваш ввод принимает значения от 1 до 1000. В моем примере применяется простое линейное преобразование для получения входных данных в правильном диапазоне.
  • Нормализация также может применяться к выходным данным. Если выходные данные большие, это может привести к (слишком) большим градиентам и обновлениям веса. Другой подход - сильно снизить скорость обучения.
using Flux
using Flux: @epochs
using Random

normalize(x) = x/1000
function generate_data(n)
    f(x) = x^2 + x
    xs = reduce(hcat, rand(n)*1000)
    ys = f.(xs)
    (normalize(xs), normalize(ys))
end
batch_size = 32
num_batches = 10000
data_train = Iterators.repeated(generate_data(batch_size), num_batches)
data_test = generate_data(100)


model = Chain(Dense(1,40, relu), Dense(40,40, relu), Dense(40, 1))
loss(x,y) = Flux.mse(model(x), y)

opt = ADAM()
ps = Flux.params(model)
Flux.train!(loss, ps, data_train, opt , cb = () -> @show loss(data_test...))
Другие вопросы по тегам