#神经网络 #机器学习 #数据分析 #数据科学 #梯度下降

bin+lib neural_networks_rust

具有模型指定和数据预处理功能的神经网络框架

6个版本 (3个重大更改)

0.5.0 2023年7月4日
0.3.1 2023年5月4日
0.2.0 2023年4月29日
0.1.1 2023年4月25日

#601机器学习

Download history 39/week @ 2024-04-01

每月下载量65次

MIT/Apache

300KB
7.5K SLoC

Rust中的神经网络[已迁移]

该项目已被jiro-nncrate替代。

从头开始使用Rust实现GPU绑定神经网络+数据操作的实用工具。

这绝对不是一个生产就绪的框架。

请随意提供反馈。

用法

将以下内容添加到您的项目的Cargo.toml文件中

[dependencies]
neural_networks_rust = "*"

预处理+CNN示例

MNIST(手写数字识别)工作流程示例

// Step 1: Enrich the features of your data (eg. the "columns") with metadata using a Dataset Specification
// The specification is necessary for guiding further steps (preprocessing, training...)

// Extract features from a spreadsheet to start building a dataset specification
// You could also start blank and add the columns and metadata manually
let mut dataset_spec = Dataset::from_file("dataset/train.csv");
// Now we can add metadata to our features
dataset_spec
    // Flag useless features for removal
    .remove_features(&["size"])
    // Tell the framework which column is an ID (so it can be ignored in training, used in joins, and so on)
    .tag_feature("id", IsId)
    // Tell the framework which column is the feature to predict
    // You could very well declare multiple features as Predicted
    .tag_feature("label", Predicted)
    // Since it is a classification problem, indicate the label needs One-Hot encoding during preprocessing
    .tag_feature("label", OneHotEncode)
    // You may also want to normalize everything except the ID & label during preprocessing
    .tag_all(Normalized.except(&["id", "label"]));

// Step 2: Preprocess the data

// Create a pipeline with all the necessary steps
let mut pipeline = Pipeline::basic_single_pass();
// Run it on the data
let (dataset_spec, data) = pipeline
    .load_data_and_spec("dataset/train.csv", dataset_spec)
    .run();

// Step 3: Specify and build your model

// A model is tied to a dataset specification
let model = ModelBuilder::new(dataset_spec)
    // Some configuration is also tied to the model
    // All the configuration calls are optional, defaults are picked otherwise
    .batch_size(128)
    .loss(Losses::BCE)
    .epochs(20)
    // Then you can start building the neural network
    .neural_network()
        // Specify all your layers
        // A convolution network is considered a layer of a neural network in this framework
        .conv_network(1)
            // Now the convolution layers
            .full_dense(32, 5)
                // You can set the activation function for any layer and many other parameters
                // Otherwise defaults are picked
                .relu() 
                .adam()
                .dropout(0.4)
            .end()
            .avg_pooling(2)
            .full_dense(64, 5)
                .relu()
                .adam()
                .dropout(0.5)
            .end()
            .avg_pooling(2)
        .end()
        // Now we go back to configuring the top-level neural network
        .full_dense(128)
            .relu()
            .adam()
        .end()
        .full_dense(10)
            .softmax()
            .adam()
        .end()
    .end()
    .build();

println!(
    "Model parameters count: {}",
    model.to_network().get_params().count()
);

// Step 4: Train the model

// Monitor the progress of the training on a nice TUI (with other options coming soon)
TM::start_monitoring();
// Use a SplitTraining to split the data into a training and validation set (k-fold also available)
let mut training = SplitTraining::new(0.8);
let (preds_and_ids, model_eval) = training.run(&model, &data);
TM::stop_monitoring();

// Step 5: Save the resulting predictions, weights and model evaluation

// Save the model evaluation per epoch
model_eval.to_json_file("mnist_eval.json");

// Save the weights
let model_params = training.take_model();
model_params.to_json_file("mnist_weights.json");

// Save the predictions alongside the original data
let preds_and_ids = pipeline.revert(&preds_and_ids);
pipeline
    .revert(&data)
    .inner_join(&preds_and_ids, "id", "id", Some("pred"))
    .to_csv_file("mnist_values_and_preds.csv");

然后您可以使用第三方crate(如gnuplot(推荐),plotly(也推荐)或甚至plotters)来绘制结果。

有关更深入的示例,包含更多可配置的工作流程,请查看examples文件夹。

功能

由于它是一个框架,所以它相当具有观点,并且有很多功能。但这里有一些主要的

NNs(密集层、全层...)、CNNs(密集层、直接层、平均池化...)、一切都是批处理的,SGD、Adam、动量、Glorot、许多激活函数(Softmax、Tanh、ReLU...)、学习率调度、K-Folds、分割训练、可缓存的和可撤销的流水线(归一化、特征提取、异常值过滤、值映射、独热编码、对数缩放...)、损失函数(二元交叉熵、均方误差)、模型指定为代码、预处理指定为代码、性能指标(R²...)、任务监控(进度、日志)、多后端(CPU、GPU,见后端)、多精度(见精度)。

范围和目标

主要目标

  • 实现足够的算法,使其适用于大多数用例
  • 不要止步于NNs,还要实现CNNs、RNNs和我们可以做到的任何东西
  • 处理可以被认为是“后端”的辅助用例(模型构建、训练、预处理)
  • 为核心功能制作具有观点的API,并为不够简单的有用支持库提供包装器(DataFrames、线性代数...)
  • 在严谨性和错误处理之上简化API(但不是不安全的Rust)
  • 使其能够工业化和配置工作流程(例如,数据预处理、模型构建、训练、评估...)
  • 尽量不让它比Python慢1000倍,比C++慢10倍(否则还有什么意义?)

侧边/未来目标

  • 实现一些罕见但有趣的算法(直接层、前向层...)
  • WebAssembly和WebGPU支持
  • Rust原生GPU后端通过wgpu(我可以做梦,对吧?)
  • 通过PyO3提供Python绑定
  • 用于模型构建的图形工具

非目标

  • 数据可视化
  • 符合其他框架/标准
  • 完美的错误处理(不要因为unwrapexpect感到羞愧)

后端

通过Cargo功能切换后端

  • arrayfire(CPU/GPU)
    • ✅ 可用视觉功能
    • ✅ GPU支持
    • 🫤 CPU支持较慢
    • 🫤 安装困难(参见 安装Arrayfire
    • 🫤 C++库,段错误...
  • ndarray
    • ✅ 最快的CPU后端
    • ✅ 纯Rust
    • 🫤 视觉功能尚不可用
    • 🫤 仅限CPU
  • nalgebra
    • ✅ 纯Rust
    • 🫤 视觉功能不可用(且未计划)
    • 🫤 仅限CPU

精度

您可以使用f64功能启用高达f64的精度。

不支持低于f32的精度(尚不支持)。

安装Arrayfire

要使用arrayfire功能进行快速计算(在CPU或GPU上使用Arrayfire的C++/CUDA/OpenCL后端,如果已安装,则首先尝试OpenCL,然后是CUDA,然后是C++),您需要首先安装Arrayfire。确保安装步骤100%正常工作,没有奇怪的错误警告,因为它们可能以相当微妙的方式失败。

安装Arrayfire后,您

  1. AF_PATH设置为您的Arrayfire安装目录(例如:/opt/Arrayfire)。
  2. 将lib文件的路径添加到环境变量中
    • Linux: LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib64
    • OSX: DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$AF_PATH/lib
    • Windows: 将%AF_PATH%\lib添加到PATH
  3. 如果使用Linux,请运行sudo ldconfig
  4. 运行cargo clean
  5. 禁用默认功能并激活arrayfire功能
[dependencies]
neural_networks_rust = { 
    version = "*", 
    default_features = false, 
    features = ["arrayfire"] 
}

如果您想在Linux上使用Arrayfire的CUDA功能(在Windows 11 WSL2上的Ubuntu和RTX 3060上进行了测试),请查看此指南

依赖关系

~36-52MB
~880K SLoC