Engee 文档
Notebook

回归使用神经网络(一个最小的例子)

在这个例子中,我们将讨论什么最小操作允许你训练一个完全连接的神经网络*(fully-connected,FC)*回归问题。

任务说明

让我们训练最经典类型的神经网络来"预测"一些一维函数的值。 我们的目标是创建最简单的算法,我们稍后会使复杂化(而不是相反)

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

epochs = Количество_циклов_обучения;
learning_rate = Коэффициент_скорость_обучения;
In [ ]:
using Flux

Xs = Float32.( 0:0.1:10 );                    # Генерация данных для обучения
Ys = Float32.( Xs .+ 2 .* rand(length(Xs)) ); # <- ожидаемые от нейросети выходные данные
data = [(Xs', Ys')];                          # В таком формате данные передаются в функцию loss
model = Dense( 1 => 1 )                       # Архитектура нейросети: один FC-слой
opt_state = Flux.setup( Adam( learning_rate ), model ); # Алгоритм оптимизации
for i in 1:epochs
    Flux.train!( model, data, opt_state) do m, x, y
        Flux.mse( m(x), y ) # Функция потерь - ошибка на каждом элементе датасета
    end
end
X_прогноз = [ [x] for x in Xs ]               # Нейросеть принимает векторы, даже если у нас функция от одного аргумента
Y_прогноз = model.( X_прогноз )               # Для каждого [x] нейросеть вычисляет нам [y]

gr()                                          # Мы получили "вектор из векторов", который преобразуем для вывода на график
plot( Xs, Ys, label="Исходная выборка", legend=:topleft, lw=2 )
plot!( Xs, vec(hcat(Y_прогноз...)), label="Прогноз", lw=2 )
Out[0]:

更改学习过程的参数,并使用<svg width="24"height="24"viewBox="0 0 24 24"fill="none"xmlns="重新启动单元格http://www.w3.org/2000/svg "><path d="M8 11.5V5L17 11.5L8 18v11.5z"fill="url(#paint0_linear_44954_74187)"stroke="url(#paint1_linear_44954_74187)"stroke-width="4.16987"stroke-linejoin="round"><LinearGradient id="paint0_linear_44954_74187"X1="12.5"Y1="5"x2="12.5"y2="18"gradientunits="userspaceonuse"><stop offset="1"stop-color="#0e8312"><lineargradient Id="paint1_linear_44954_74187"X1="12.5"Y1="5"x2="12.5"y2="18"gradientunits="userspaceonuse"><stop offset="1"stop-color="#0e8312">评估如何更改设置将影响预测质量。

在画布上以块的形式创建神经网络

我们的神经网络有这样一个简单的结构,很容易将它转移到画布上,并在我们自己的块库中使用它。

👉**此模型可以独立于脚本运行。**模型的"回调"包含训练神经网络的所有代码,因此在第一次打开文件时 neural_regression_simple.engee 如果变量 model 它还不存在,神经网络正在重新训练。

该模型可以很容易地从工作区中的块组装。 它从变量工作区获取参数,但它们可以作为固定矩阵和向量输入到这些块的属性中。

image.png

让我们运行这个模型并比较结果。:

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

data = engee.run( "neural_regression_simple" );

# Поскольку в модели все операции у нас матричные, нам снова приходится "разглаживать" переменную Y
plot!( data["Y"].time, vec(hcat(data["Y"].value...)), label="Блок regression_net", lw=2 )
Out[0]:

如果图的结构与神经网络的结构相同,那么运行"从代码"和"从画布"的结果也将相同。

通常,神经网络的结构变化频率低于数据集和任务语句。 因此,很有可能两次模拟结构:首先在代码中,然后在画布上以图形块的形式。

守则的解释

让我们回顾一下我们的简短代码并评论有趣的点。

我们使用 Float32 而不是 Float64,在Julia中默认使用它(没有它,一切都可以工作,但是库 Flux 它会发出一次性警告)。

Xs=Float32。( 0:0.1:10 );
Ys=Float32.(Xs。+ 2 .*兰德(长度(Xs)));

准确度 Float32 对于神经网络来说绰绰有余,由于较粗的位网格,它们的预测误差通常超过舍入误差。 此外,在GPU上执行,当我们到达它时,使用这种类型的数据会更快。

数据将通过迭代器馈送到损失函数。 数据集内部应该有元组(Tuple)与数据列-一列输入,一列输出。 还有其他几种提交数据的方法,现在我们将重点介绍下面的方法。

数据=[(X',Ys')];

神经网络由单个元素组成-输入和权重的线性组合,加上偏移量(没有激活函数,或者等价地,具有线性激活函数)。 我们甚至没有开始围绕物体。 Dense 按设计 Chain(),通常用于创建多层神经网络*(尽管两个网络的工作方式相同)*。

模型=密集(1=>1)

让我们设置Adam优化算法(自适应矩估计),这是神经网络训练中最有效的优化算法之一。 我们传递给他的唯一参数是学习率系数。

opt_state=通量。设置(Adam(learning_rate),model_cpu)

**现在是训练模型的时候了。**我们通过样本执行一定数量的重复通过,计算损失函数并在减小误差梯度的方向上调整神经网络的所有变量。

损失函数(loss 函数)是模型在训练期间显式执行的唯一地方。 它通常用每个数据元素上的误差总和( cost 功能)。 在这里,我们简单地使用通量库中的标准均方误差(mean squared error,MSE)函数。

为我在1:时代
    通量。火车!(model,data,opt_state)做m,x,y
        通量。mse(m(x),y)
    结束
结束

它仍然使用训练好的模型。 我们将把输入数据作为一个函数传递给它,并得到输出预测

Y_prognosis=模型。(X_prognosis)
X_prognosis=[[X]X中的X]

结论

我们花了10行代码来生成数据并训练神经网络,还有5行代码在图表上显示预测。 小的变化将使神经网络多层化或在XLSX表中的数据上训练它。

我们发现,在训练之后,将神经网络转移到画布上并将其用作系统图中的另一个块是相当容易的,并且在方案的足够简化下,甚至从中生成C代码。 通过这种方式,我们可以确保从数据采样到控制器的端到端系统更新过程。

示例中使用的块