使用多层神经网络的回归
在这项工作中,我们需要训练一个神经网络来预测来自两个参数的连续函数的输出,并将其作为另一个块放在Engee画布上。 例如,作为替代模型来替代一些复杂的子系统。
数据描述
我们的数据是由表单的过程生成的 :
Pkg.add(["JLD2", "Flux"])
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个示例的样本中,每个示例都有两个特征: x1 和 x2)
Ys -矩阵尺寸 1200х1 (预测栏)
学习过程
让我们设置训练过程的参数,并运行一个相当简单的循环版本。
# @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)和一个输出的神经网络。 重要的是神经网络的输出具有线性激活函数。
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" ) # Выведем хронику обучения
将神经网络传输到Engee画布
在变量中 model 新训练的神经网络进行存储。
我们使用canvas上的元素重新创建了它的结构。:
我们的模型需要一个变量 model,从那里它得到的参数。 如果没有这样的变量,模型将尝试查找文件。 model.jld2 在主目录中。 如果找不到此文件,模型将创建一个带有随机参数的空神经网络。
完全连接的层由最常见的块组装而成 Product 和 Add,执行输入乘以矩阵和位移向量的加法。
激活功能,为了更清晰,不是隐藏在层内,而是带出。
让我们在一组几百个随机点上运行这个模型。
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:
model_x1 = model_data["X1"].value;
model_x2 = model_data["X2"].value;
model_y = vec( hcat( model_data["Y"].value... ));
我们展示结果
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)
)
保存模型
最后,如果缺少此文件,我们将训练好的神经网络保存到一个文件中。
if !isfile( "model.jld2" )
using JLD2
jldsave("model.jld2"; model)
end
结论
我们训练了一个由三个完全连接的层组成的多层神经网络。 然后我们将其所有系数转移到画布中,以便在方便的面向模型的上下文中使用*(比通过代码使用神经网络更方便)*。
这项工作很容易与任何表格数据重复和缩放神经网络,以满足项目的需要。 将训练好的网络保存到文件中,您可以在不重新训练神经网络的情况下,将模型与Engee图的其他元素一起执行。
如果需要,权重和偏移可以写入块中。 Constant 在画布上,并得到一个块与神经网络,无论文件可用性 model.jld2.
