AnyMath 文档
Notebook

配置神经网络学习过程

在这个例子中,我们将创建一个训练神经网络的环境,使用方便的图形形式进行控制。

network_training.gif

任务说明

神经网络的发展早已不再是具有多年编写代码经验的研究人员的领域。 今天,它是工程师,分析师和产品科学家的工具。 然而,入门门槛通常仍然很高:即使对于具有三层的简单全连接网络,您也需要记住Flux等库的语法。jl并正确地从CSV加载数据集并输出正确的图形。.. 这就是图形界面(Gui)来拯救的地方。 它们允许您专注于任务的本质-致力于数据质量和解释结果,而不是每个人在第一阶段犯的琐碎错误。

让我们创建一个用于训练神经网络的接口,它仍然会隐藏加载,分发,训练和检查神经网络质量的相同数学和数据操作。

准备操作包括安装用于训练神经网络的库:

In [ ]:
# 编译Flux库可能需要一分钟。
Pkg.add(["Flux", "Interpolations"])
using Flux, CSV, DataFrames, Random
using Flux: mse
using Statistics, Interpolations
gr()

现在我们将开发一个GUI,允许您移动滑块并训练具有所需神经元数量的神经网络,这将加载数据并训练神经网络。

假设:脚本文件夹包含火车。csv和测试。csv文件。 每个文件的第一列包含预测变量,其余列包含属性。 我们正在解决一个回归问题。

In [ ]:
# 让我们使用此脚本移动到目录。
cd(@__DIR__)

train_filename = "train.csv" # @param {type:"string"}
test_filename = "test.csv" # @param {type:"string"}

train_df = CSV.read(train_filename, DataFrame, types=Float32)
test_df = CSV.read(test_filename, DataFrame, types=Float32)

# 我们假设第一列包含预测值,其余列包含符号
X_train = Matrix(train_df[:, 2:end])'  # (n_features, n_samples)
X_test = Matrix(test_df[:, 2:end])'    # (n_features, n_samples)
y_train_raw = reshape(train_df[:, 1], 1, :)  # (1, n_samples)
y_test_raw = reshape(test_df[:, 1], 1, :)    # (1, n_samples)

# 标志正常化
X_train_mean = mean(X_train, dims=2)
X_train_std = std(X_train, dims=2)

# 使用列车选择参数标准化列车和测试
X_train_norm = (X_train .- X_train_mean) ./ X_train_std
X_test_norm = (X_test .- X_train_mean) ./ X_train_std

# 标准化目标值
y_train_mean = mean(y_train_raw)
y_train_std = std(y_train_raw)

y_train_norm = (y_train_raw .- y_train_mean) ./ y_train_std
y_test_norm = (y_test_raw .- y_train_mean) ./ y_train_std

features_count = size(X_train_norm, 1)
l1_neurons = 30 # @param {type:"slider",min:1,max:30,step:1}
l2_neurons = 28 # @param {type:"slider",min:1,max:30,step:1}
l3_neurons = 25 # @param {type:"slider",min:1,max:30,step:1}
l4_neurons = 13 # @param {type:"slider",min:1,max:30,step:1}
l5_neurons = 1 # @param {type:"slider",min:1,max:30,step:1}
n_epochs = 499 # @param {type:"slider",min:1,max:500,step:1}

# 回归体系结构
model = Chain(
    Dense(features_count => l1_neurons, relu),
    Dense(l1_neurons => l2_neurons, relu),
    Dense(l2_neurons => l3_neurons, relu),
    Dense(l3_neurons => l4_neurons, relu),
    Dense(l4_neurons => l5_neurons, relu),
    Dense(l5_neurons => 1)
)

# 培训课程
loss(m, x, y) = mse(m(x), y)

opt_state = Flux.setup(Adam(0.001), model)
data = [(X_train_norm, y_train_norm)]
train_losses = []
test_losses = []

# 开始培训
for epoch in 1:n_epochs
    Flux.train!(loss, model, data, opt_state)
    push!(train_losses, loss(model, X_train_norm, y_train_norm))
    push!(test_losses, loss(model, X_test_norm, y_test_norm))
end

# 在尺度之间转换的函数
denormalize_y(y_norm) = y_norm .* y_train_std .+ y_train_mean
denormalize_X(X_norm, dim) = X_norm .* X_train_std[dim] .+ X_train_mean[dim]

test_loss = loss(model, X_test_norm, y_test_norm)
println("测试上的\nMSE(在标准化尺度上):$(round(test_loss,digits=6))")
println("测试上的RMSE(以初始单位):$(round(sqrt(test_loss)*y_train_std,digits=2))")

# 来自测试的第一个对象的预测示例
prediction_norm = model(X_test_norm[:, 1:1])
actual_norm = y_test_norm[:, 1:1]

prediction = denormalize_y(prediction_norm)
actual = denormalize_y(actual_norm)

println("示例(归一化):通过$(round)预测。(prediction_norm,digits=3)),真的$(round。(actual_norm,数字=3))")
println("示例(初始比例):预测$(圆形。(预测,数字=2)),真的$(圆。(实际,数字=2))")

# 图1:学习曲线
p1 = plot(1:n_epochs, train_losses, label="Train Loss", lw=2, marker=:circle, markersize=2)
plot!(p1, 1:n_epochs, test_losses, label="Test Loss", lw=2, marker=:square, markersize=2)
title!(p1, "学习动态(归一化MSE)")
xlabel!(p1, "时代")
ylabel!(p1, "MSE")

# 图2:三维表面
if features_count >= 2
    n_points = 30
    
    # 规范化空间中的范围
    x1_range_norm = range(extrema(X_train_norm[1, :])..., length=n_points)
    x2_range_norm = range(extrema(X_train_norm[2, :])..., length=n_points)
    
    # 在规范化空间中创建网格
    grid_x1_norm = repeat(x1_range_norm', n_points, 1)
    grid_x2_norm = repeat(x2_range_norm, 1, n_points)
    
    # 对于剩余的符号,我们取平均值(在标准化空间中)
    grid_other_norm = zeros(features_count-2, n_points, n_points)
    for i in 3:features_count
        grid_other_norm[i-2, :, :] .= mean(X_train_norm[i, :])
    end
    
    # 为网格创建一组完整的要素(在规范化空间中)
    grid_points_norm = vcat(
        reshape(grid_x1_norm, 1, n_points, n_points),
        reshape(grid_x2_norm, 1, n_points, n_points),
        grid_other_norm
    )
    grid_points_flat_norm = reshape(grid_points_norm, features_count, n_points * n_points)
    
    # 网格上模型的预测(在标准化尺度上)
    predictions_norm = model(grid_points_flat_norm)
    predictions_2d_norm = reshape(predictions_norm, n_points, n_points)
    
    # 将预测转换为原始比例以进行可视化
    predictions_2d_original = denormalize_y(predictions_2d_norm)
    
    # 将网格坐标转换为原始比例以进行可视化
    x1_range_original = denormalize_X(x1_range_norm, 1)
    x2_range_original = denormalize_X(x2_range_norm, 2)
    
    # 原始比例中的初始数据点(列车)
    X1_train_original = denormalize_X(X_train_norm[1, :], 1)
    X2_train_original = denormalize_X(X_train_norm[2, :], 2)
    y_train_original = vec(denormalize_y(y_train_norm))
    
    # 测试原始比例中的数据点
    X1_test_original = denormalize_X(X_test_norm[1, :], 1)
    X2_test_original = denormalize_X(X_test_norm[2, :], 2)
    y_test_original = vec(denormalize_y(y_test_norm))
    
    # 初始尺度下的预测面
    p2 = surface(x1_range_original, x2_range_original, predictions_2d_original, 
                 alpha=0.6, label="神经网络预测",
                 camera=(30, 30), color=:reds)
    
    # 增加训练点数(蓝色)
    scatter!(p2, X1_train_original, X2_train_original, y_train_original, 
             label="列车数据", 
             color=:blue, 
             markersize=4,
             alpha=0.7,
             markeralpha=0.6)
    
    # 添加测试点(绿色)
    scatter!(p2, X1_test_original, X2_test_original, y_test_original, 
             label="测试数据", 
             color=:green, 
             markersize=4,
             alpha=0.7,
             markeralpha=0.6,
             marker=:square)
    
    title!(p2, "预测(红色)Vs火车(蓝色)vs测试(绿色)")
    xlabel!(p2, "签名1")
    ylabel!(p2, "签名2")
    zlabel!(p2, "目标变量")
    
    # #输出统计信息进行验证
    # println("\n Ranges for visualization:")
    # println("x1: [$(round(minimum(x1_range_original), digits=2)), $(round(maximum(x1_range_original), digits=2))]")
    # println("x2: [$(round(minimum(x2_range_original), digits=2)), $(round(maximum(x2_range_original), digits=2))]")
    # println("y(预测):[$(round(最小值(预测_2d_original),数字=2)),$(round(最大值(预测_2d_original),数字=2))]")
    # println("y (train): [$(round(minimum(y_train_original), digits=2)), $(round(maximum(y_train_original), digits=2))]")
    # println("y (test): [$(round(minimum(y_test_original), digits=2)), $(round(maximum(y_test_original), digits=2))]")
    
    plot(p1, p2, layout=(1, 2), titlefont=font(9), guidesfont=font(7), size=(1100,500))
else
    plot(p1, titlefont=font(9), guidesfont=font(7), size=(800,300))
end
MSE на тесте (в нормализованном масштабе): 0.076717
RMSE на тесте (в исходных единицах): 351.24

Пример (нормализованный): предсказано Float32[-0.478;;], реально Float32[-0.961;;]
Пример (исходный масштаб): предсказано Float32[764.79;;], реально Float32[153.06;;]
Out[0]:
No description has been provided for this image

通过双击表单以输入参数来隐藏代码。

检查该单元的自动执行的启用(按钮 应该是绿色)。

并将输出发布到单元格的右侧,如果它位于底部。 你的工具包准备好了!

结论

此任务的代码简洁,解决了一个特定的问题。 但是,由于我们将此功能打包到图形界面中,因此您只需选择每个层中的神经元数量并查看预测质量如何变化。

这是针对未知数据训练前5-10个神经网络的最快方法,并查看这种类型的模型是否适合您的任务。