来自代理神经网络的C代码
我们提出了一个用于全连接神经网络的简单生成器的项目,允许您将神经网络放置在Engee代码块或微控制器中。
环境准备
安装必要的库:
# Pkg.add(["ChainPlots", "Flux"])
using DataFrames, CSV, Flux, Random, Statistics
using Flux: mse
using ChainPlots
gr();
我们收集了一定范围的输入值的数据,并从[燃料电池系统]项目中保存了模型的输出值(https://engee.com/community/ru/catalogs/projects/sistema-toplivnykh-elementov )作者shestakoviktor。要研究前面的步骤,请参阅项目[Surrogate neural network training](https://engee.com/community/ru/catalogs/projects/obuchenie-surrogatnoi-neiroseti )。
我们还需要有关当前项目中的输入和输出的信息,因此我们将重复输入和输出数据的声明。
out_vars = ["功率千瓦", "Voltage Sensor.V", "的燃料电池。thermal_port。T", "燃料电池。i_FC"]
v1 = Dict(:block=>"燃料箱/氢气压力(bar)",:param=>"Value", :units=>"", :delta=>2.0, :lower=>2.0, :upper=>20.0)
v2 = Dict(:block=>"燃料箱/燃料供应",:param=>"slope", :units=>"", :delta=>10/60, :lower=>50/60, :upper=>150/60)
adj_vars = vcat(DataFrame.([v1, v2])...)
n_features, n_targets = nrow(adj_vars), length(out_vars)
我们已经确定了模型的输入和输出变量的数量,现在我们可以简单地从实验中下载数据。
训练代理神经网络
在少量数据上训练神经网络几乎是一个免费的过程,所以让我们重复训练,并且只从以前的项目中获取数据。
include("$(@__DIR__)/scripts/create_plots.jl");
include("$(@__DIR__)/scripts/prepare_data.jl");
include("$(@__DIR__)/scripts/plot_predictions.jl");
l1_neurons = 11 # @param {type:"slider",min:1,max:30,step:1}
l2_neurons = 8 # @param {type:"slider",min:1,max:30,step:1}
l3_neurons = 8 # @param {type:"slider",min:1,max:30,step:1}
l4_neurons = 8 # @param {type:"slider",min:1,max:30,step:1}
l5_neurons = 8 # @param {type:"slider",min:1,max:30,step:1}
n_epochs = 1500 # @param {type:"slider",min:1,max:1500,step:1}
learning_rate_base = 1 # @param {type:"slider",min:1,max:9,step:1}
learning_rate_exp = -3 # @param {type:"slider",min:-6,max:1,step:1}
models_list = []
loss_list = []
loss_plot_list = []
for i = 1:5
include("$(@__DIR__)/scripts/prepare_and_train_net.jl")
append!(models_list, [model])
append!(loss_plot_list, [train_losses])
append!(loss_list, loss(model, X_train_norm, y_train_norm))
end
min_id = findmin(loss_list)[2]
train_losses = loss_plot_list[min_id]
model = models_list[min_id]
best_loss = loss_list[min_id]
# 图1:学习曲线
p_loss = plot(1:n_epochs, train_losses, label="Train Loss", lw=2, marker=:circle, markersize=2)
title!(p_loss, "学习动态(归一化MSE)")
xlabel!(p_loss, "时代")
ylabel!(p_loss, "MSE")
println("接收错误值(MSE): ", best_loss)
# 所有目标变量的曲面图
surface_plots = [plot_predictions(model, X_train_norm, y_train_norm,
X_train_mean, X_train_std, y_train_mean, y_train_std, i,
title=out_vars[i])
for i in 1:n_targets]
# surface_plots = create_plots(predict_df, :reds, out_var, in_vars, result_df) for out_var in out_vars]
# 一起显示所有图形
plot(plot(p_loss, plot(surface_plots...)), plot(model), layout=(2,1), size=(1200,900))
为神经网络生成代码并配置模型
我们已经将数据转化为算法,模型的所有系数都位于神经网络中。 model. 由于这个神经网络只包含完全连接的层,因此我们很容易从中生成可移植的C代码。:
include("$(@__DIR__)/scripts/generate_inline_c_code.jl");
cd(@__DIR__)
engee.open("nnet_model.engee")
engee.set_param!( "nnet_model/C Function", "InputPort1Size" => "($n_features,)")
engee.set_param!( "nnet_model/C Function", "OutputPort1Size" => "($n_targets,)")
engee.set_param!( "nnet_model/C Function", "OutputCode" => generate_inline_c_code(model, n_features, n_targets))
此代码自动放置在以下模型中,其中执行输入数据的归一化和算法的输出数据的反向操作。:
让我们检查生成的模型
要直接在目标模型上测试此神经网络的质量,请在源表的所有点上运行它并检查预测。:
predict_df = CSV.read("$(@__DIR__)/data/outputfile.csv", DataFrame)
predict_df = filter(row -> all(isfinite, row), predict_df)
in_vars = names(predict_df)[1:n_features];
out_vars = names(predict_df)[n_features+1:end];
for var in out_vars predict_df[!, Symbol(var)] = missings(Float64, nrow(predict_df)); end
加载数据后,剩下的就是创建一个循环,我们将在其中更改块值。 Константа 并保存模型执行的结果。
您可以注释掉此单元格,然后将使用以前保存的数据。
for row in eachrow(predict_df)
const_value = "[" * join([string(row[col]) for col in names(predict_df)[1:n_features]], ',') * "]"
engee.set_param!( "nnet_model/常量", "Value"=>const_value )
data = engee.run()
for (i,var) in enumerate(out_vars) row[Symbol(var)] = data["Y"].value[end][i]; end
end
predict_df = coalesce.(predict_df, NaN);
CSV.write("$(@__DIR__)/data/outputfile_predictions.csv", predict_df);
为了不为每个实验重复运行模型,让我们准备好从结果表中打开数据并构建图表的机会。:
# 初始训练数据
result_df = DataFrame(CSV.File("$(@__DIR__)/data/outputfile.csv"))
# 神经网络预测的数据
predict_df = DataFrame(CSV.File("$(@__DIR__)/data/outputfile_predictions.csv"))
p = [create_plots(predict_df, :reds, out_var, in_vars, result_df) for out_var in out_vars]
plot(p..., legend=false, size=(1500,500), titlefont=font(9), guidefont=font(7))
图上的点(预测)与物理模型实验后获得的表面很好地匹配。
结论
我们已经实现了将神经网络转移到c代码块的方法,这将允许我们处理任何维度的数据(神经网络的任意数量的输入和输入)。
结果的可视化适用于两个输入变量,如果有更多数据,您应该简单地将可视化限制为两个变量或将其删除。
.png)
.png)