Engee 文档
Notebook

将神经网络置于 Engee 功能块中

在本示例中,我们将把训练好的神经网络放在 Engee 画布上,作为一个块Engee Function - 从中生成 Julia 上的代码。

任务描述

之前我们训练了一个全连接神经网络,根据两个输入变量$x_1$ 和$x_2$ 预测$y$ 的值。我们已经有了一个文件model.jld2 ,训练好的神经网络就在其中。现在,我们将把它转化为 Julia 代码,并创建一个可用于任何模型的模块,或者创建我们自己的模块库。

⚠️ 在Engee Function 代码块中只能使用全局寻址。因此,如果您的示例位于/user/start/data_analysis/neural_regression_to_engee_function 以外的文件夹中,您需要编辑块Engee Function 中的代码,写入文件neural_net_code.jl 的完整路径。

创建代码块掩码

在块的正面放置一些图画会很方便,这样可以简化模型的感知。我们将使用神经网络的拓扑结构作为遮罩。

image.png

我们需要ChainPlots 库,该库可为函数plot() 创建神经网络可视化 "配方",之后我们只需将神经网络作为参数传递给图形输出函数即可。

In [ ]:
Pkg.add(["JLD2", "Flux", "ChainPlots", "Symbolics"])
In [ ]:
using Flux, JLD2, ChainPlots

model = load_object( "$(@__DIR__)/model.jld2" ) # Загрузим нейросеть из файла

gr()
p = plot( model, titlefontsize=10, size=(300,300),
    xticks=:none, series_annotations="", markersize=8,
    markercolor="white", markerstrokewidth=4, linewidth=1 )

savefig( p, "$(@__DIR__)/neural_net_block_mask.png"); # Сохраним график в PNG

☝️ 在块掩码中已经规定了图片链接。但遮罩不会自动更新。要在图块面上加载插图,请打开其属性(在遮罩视图中)并点击 "更新遮罩"。

为神经网络创建 Julia 代码

Julia 语言的一个特点将帮助我们创建代码。

由于Flux 库完全是用 Julia 编写的,因此神经网络的每一层都由 Julia 代码描述。如果输入的不是数字,而是库Symbolics 中的数学符号,会发生什么情况呢?

In [ ]:
using Symbolics
@variables x1 x2
s = model( [x1, x2] );

# Первые 200 символов этого кода
print( string(s[1])[1:200], "..." )
2.474068ifelse((0.98925877 + 0.38023216ifelse((1.1855042 + 0.8189067x1 - 0.93786836x2) < 0, 0, 1.1855042 + 0.8189067x1 - 0.93786836x2) + 1.3171272ifelse((1.784764x1 - 0.027649183 - 1.0800585x2) < 0, 0...

我们可以看到很多ifelse...事实上,ReLU 激活的神经网络可以重写为一个大型片断线性函数。

让我们将代码保存为 .jl 文件

如果我们将代码保存在文本文件中,就可以通过include() 命令将其包含在程序块Engee Function 中,但只能是绝对地址。但您始终需要将该代码文件保存在模型文件夹中。还有另一种方法--将代码和掩码放在Engee Function 块中,使组件自给自足。

In [ ]:
open("$(@__DIR__)/neural_net_code.jl", "w") do f
    println(f, "function nn(x1, x2)\n    $(s[1])\nend")
end

# Сразу же запустим этот код и получим прогноз нейросети:
include("$(@__DIR__)/neural_net_code.jl")
nn(1,2)
Out[0]:
2.5977383718979077

测试:从 Engee 功能块启动神经网络

让我们运行模型并将结果可视化。

In [ ]:
# Загрузим (если модель еще не открыта) и выполним модель
if "neural_regression_to_engee_function"  getfield.(engee.get_all_models(), :name)
    engee.load( "$(@__DIR__)/neural_regression_to_engee_function.engee");
end
model_data = engee.run( "neural_regression_to_engee_function" );

# Подготовим выходные переменные
model_x1 = model_data["X1"].value;
model_x2 = model_data["X2"].value;
model_y = vec( hcat( model_data["Y"].value... ));

# Построим график
scatter!( model_x1, model_x2, model_y, ms=2.5, msw=.5, leg=false, zcolor=model_y, c=:viridis,
         xlimits=(-3,3), ylimits=(-3,3), title="Прогноз от блока Engee Function", titlefont=font(10) )
Out[0]:

我们看到的是一个熟悉的函数,但每个输出点都是由一个神经网络 "预测 "的,该网络经过训练,可以模拟我们需要的依赖关系$y = f(x_1, x_2)$ 。

结论

使用库Symbolics 生成 Julia 函数代码一点也不难,即使该函数是来自库Flux 的神经网络。只需选择一种方便的方式将代码放到画布上,就可以将神经网络作为面向模型的项目中的一个组件。