Engee 文档
Notebook

使用多层神经网络的回归

在这项工作中,我们需要训练一个神经网络来预测来自两个参数的连续函数的输出,并将其作为另一个块放在Engee画布上。 例如,作为替代模型来替代一些复杂的子系统。

数据描述

我们的数据是由表单的过程生成的 :

In [ ]:
Pkg.add(["JLD2", "Flux"])
In [ ]:
Nx1, Nx2 = 30, 40
x1 = Float32.( range( -3, 3, length=Nx1 ) )
x2 = Float32.( range( -3, 3, length=Nx2 ) )
Xs = [ repeat( x1, outer=Nx2)  repeat( x2, inner=Nx1) ];
# Первый пример выходных данных
Ys = @. 3*(1-Xs[:,1])^2*exp(-(Xs[:,1]^2) - (Xs[:,2]+1)^2) - 10*(Xs[:,1]/5 - Xs[:,1]^3 - Xs[:,2]^5)*exp(-Xs[:,1]^2-Xs[:,2]^2) - 1/3*exp(-(Xs[:,1]+1) ^ 2 - Xs[:,2]^2);
# Второй пример выходных данных
#Ys = @. 1*(1-Xs[:,1])^2*exp(-(Xs[:,1]^2) - (Xs[:,2]+1)^2) - 15*(Xs[:,1]/5 - Xs[:,1]^3 - Xs[:,2]^6)*exp(-Xs[:,1]^2-Xs[:,2]^2) - 1/3*exp(-(Xs[:,1]+1) ^ 2 - Xs[:,2]^2);

Xs -矩阵尺寸 1200x2 (在1,200个示例的样本中,每个示例都有两个特征: x1x2)

Ys -矩阵尺寸 1200х1 (预测栏)

学习过程

让我们设置训练过程的参数,并运行一个相当简单的循环版本。

In [ ]:
# @markdown ## Настройка параметров нейросети
# @markdown *(двойной клик позволяет скрыть код)*
# @markdown
Параметры_по_умолчанию = false #@param {type: "boolean"}
if Параметры_по_умолчанию
    Коэффициент_скорости_обучения = 0.01
    Количество_циклов_обучения = 2000
else
    Количество_циклов_обучения = 2001 # @param {type:"slider", min:1, max:2001, step:10}
    Коэффициент_скорости_обучения = 0.08 # @param {type:"slider", min:0.001, max:0.5, step:0.001}
end

epochs = Количество_циклов_обучения;
learning_rate = Коэффициент_скорости_обучения;

让我们创建一个具有两个输入,两个中间状态(大小20和5)和一个输出的神经网络。 重要的是神经网络的输出具有线性激活函数。

In [ ]:
using Flux
model = Chain( Dense( 2 => 20, relu ),      # Структура модели, которую мы будем обучать
               Dense( 20 => 5, relu ),
               Dense( 5 => 1 ) )
data = [ (Xs', Ys') ]                       # Зададим структуру данных
loss( , y ) = Flux.mse( , y )             # и функцию потерь, в которую они будут передаваться процедурой обучения
loss_history = []                           # Будем сохранять историю обучения
opt_state = Flux.setup( Adam( learning_rate ), model ); # Алгоритм оптимизации
for i in 1:epochs
    Flux.train!( model, data, opt_state) do m, x, y
        loss( m(x), y ) # Функция потерь - ошибка на каждом элементе датасета
    end
    push!( loss_history, loss( model(Xs'), Ys' ) ) # Запомним значение функции потерь
end
plot( loss_history, size=(300,200), label="loss" ) # Выведем хронику обучения
Out[0]:

将神经网络传输到Engee画布

在变量中 model 新训练的神经网络进行存储。

我们使用canvas上的元素重新创建了它的结构。:

image.png

我们的模型需要一个变量 model,从那里它得到的参数。 如果没有这样的变量,模型将尝试查找文件。 model.jld2 在主目录中。 如果找不到此文件,模型将创建一个带有随机参数的空神经网络。

完全连接的层由最常见的块组装而成 ProductAdd,执行输入乘以矩阵和位移向量的加法。

image.png

激活功能,为了更清晰,不是隐藏在层内,而是带出。

image.png

让我们在一组几百个随机点上运行这个模型。

In [ ]:
if "neural_regression_multilayer"  getfield.(engee.get_all_models(), :name)
    engee.load( "$(@__DIR__)/neural_regression_multilayer.engee");
end
model_data = engee.run( "neural_regression_multilayer" );

该模型向我们返回矩阵的矩阵。 您可以通过使用画布块来解决此问题,也可以实现您自己的功能版本。 flatten:

In [ ]:
model_x1 = model_data["X1"].value;
model_x2 = model_data["X2"].value;
model_y = vec( hcat( model_data["Y"].value... ));

我们展示结果

In [ ]:
gr()

plot(
    surface( Xs[:,1], Xs[:,2], vec(Ys), c=:viridis, cbar=:false, title="Обучающая выборка", titlefont=font(10)),
    wireframe( x1, x2, vec(model( Xs' )), title="Прогноз от нейросети (через скрипт)", titlefont=font(10) ),
    scatter( model_x1, model_x2, model_y, ms=2.5, msw=.5, leg=false, zcolor=model_y,
        xlimits=(-3,3), ylimits=(-3,3), title="Прогноз от модели на холсте", titlefont=font(10) ),
    layout=(1,3), size=(1000,400)
)
Out[0]:

保存模型

最后,如果缺少此文件,我们将训练好的神经网络保存到一个文件中。

In [ ]:
if !isfile( "model.jld2" )
    using JLD2
    jldsave("model.jld2"; model)
end

结论

我们训练了一个由三个完全连接的层组成的多层神经网络。 然后我们将其所有系数转移到画布中,以便在方便的面向模型的上下文中使用*(比通过代码使用神经网络更方便)*。

这项工作很容易与任何表格数据重复和缩放神经网络,以满足项目的需要。 将训练好的网络保存到文件中,您可以在不重新训练神经网络的情况下,将模型与Engee图的其他元素一起执行。

如果需要,权重和偏移可以写入块中。 Constant 在画布上,并得到一个块与神经网络,无论文件可用性 model.jld2.