{"id":14992135,"url":"https://github.com/AnicetNgrt/jiro-nn","last_synced_at":"2025-09-25T14:30:57.496Z","repository":{"id":151821795,"uuid":"621302375","full_name":"AnicetNgrt/jiro-nn","owner":"AnicetNgrt","description":"A Deep Learning and preprocessing framework in Rust with support for CPU and GPU.","archived":false,"fork":false,"pushed_at":"2023-10-03T16:59:01.000Z","size":18379,"stargazers_count":127,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-15T15:31:06.540Z","etag":null,"topics":["adam","classification","cuda","data-analysis","deep-learning","dropout","gpu","gpu-computing","machine-learning","ml","nalgebra","neural-networks","nn","opencl","pipelines","regression","rust","sgd"],"latest_commit_sha":null,"homepage":"https://linktr.ee/jironn","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AnicetNgrt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-03-30T11:49:24.000Z","updated_at":"2025-01-15T13:20:19.000Z","dependencies_parsed_at":null,"dependency_job_id":"ef38c7ba-9107-4eb7-a101-54add9b30965","html_url":"https://github.com/AnicetNgrt/jiro-nn","commit_stats":{"total_commits":183,"total_committers":1,"mean_commits":183.0,"dds":0.0,"last_synced_commit":"9b683e7344ecb87b50ee7a3c41f14ac3b94b804d"},"previous_names":["anicetngrt/neural_networks_rust"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnicetNgrt%2Fjiro-nn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnicetNgrt%2Fjiro-nn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnicetNgrt%2Fjiro-nn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AnicetNgrt%2Fjiro-nn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AnicetNgrt","download_url":"https://codeload.github.com/AnicetNgrt/jiro-nn/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234200174,"owners_count":18795139,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adam","classification","cuda","data-analysis","deep-learning","dropout","gpu","gpu-computing","machine-learning","ml","nalgebra","neural-networks","nn","opencl","pipelines","regression","rust","sgd"],"created_at":"2024-09-24T15:00:45.825Z","updated_at":"2025-09-25T14:30:51.775Z","avatar_url":"https://github.com/AnicetNgrt.png","language":"Rust","funding_links":[],"categories":["Machine Learning"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"192\" height=\"108\" src=\"https://raw.githubusercontent.com/AnicetNgrt/jiro-nn/main/doc_assets/jiro.svg\" alt=\"logo\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\" style=\"padding-bottom: 10px\"\u003eLow-friction high-detail Deep Learning framework in Rust\u003c/p\u003e\n\n**Disclaimer:** This project was mainly a learning project, is not production-ready and is now on hold. Please use [candle](https://github.com/huggingface/candle) or others if you want a production-ready framework. Thanks for checking out my code :)\n\n- [Usage](#usage)\n  - [Installation \\\u0026 cargo features](#installation--cargo-features)\n  - [Bare-bones XOR example](#bare-bones-xor-example)\n  - [Preprocessing + CNNs example](#preprocessing--cnns-example)\n- [Features](#features)\n  - [Scope and goals](#scope-and-goals)\n  - [Backends](#backends)\n  - [Precision](#precision)\n- [Installing Arrayfire](#installing-arrayfire)\n\n## Usage\n\n### Installation \u0026 cargo features\n\nAdd this in your project's `Cargo.toml` file, by replacing `\u003cBACKEND\u003e` with the backend you want to use (see [Backends](#backends)):\n\n```toml\n[dependencies]\njiro_nn = { \n    version = \"*\", \n    default-features = false, \n    features = [\"\u003cBACKEND\u003e\", \"data\"] # \"data\" is optional and enables the preprocessing and dataframes features\n}\n```\n\n| feature                       | description                                                                                                                                                                                                | compile-time cost        |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |\n| `data` *(default feature)*    | adds `DataTable`, a simpler API for `polars` dataframes ; enables `Kfolds` training ; adds the `preprocessing` module for creating pipelines depending on dataset configurations                           | High                     |\n| `parquet`                     | adds Apache Parquet files support for eveything related to the `data` feature                                                                                                                              | Medium                   |\n| `ipc`                         | adds Arrow files support for eveything related to the `data` feature                                                                                                                                       | Medium                   |\n| `ndarray` *(default feature)* | changes the `Matrix` and `Image` types to a CPU-bound backend powered by the `ndarray` crate. *`Image` and convolution operations are not fully implemented with this backend, But it's in the works.*       | Low                      |\n| `nalgebra`                    | changes the `Matrix` and `Image` types to a CPU-bound backend powered by the `nalgebra` crate. *`Image` and convolution operations are not fully implemented with this backend, and probably won't ever be.* | Low                      |\n| `arrayfire`                   | changes the `Matrix` and `Image` types to a GPU and CPU backend powered by the `arrayfire` crate. Ideal for Convolutional Networks. *Requires the ArrayFire C++ library. See [Installing Arrayfire](#installing-arrayfire)*                    | Low, but hard to install |\n| `f64`                         | changes the `Scalar` type from being backed by `f32` to being backed by `f64`                                                                                                                     | None                     |\n\n\n\n### Bare-bones XOR example\n\nPredicting the XOR function with a simple neural network:\n\n```rust\nlet x = vec![\n    vec![0.0, 0.0],\n    vec![1.0, 0.0],\n    vec![0.0, 1.0],\n    vec![1.0, 1.0],\n];\n\nlet y = vec![\n    vec![0.0], \n    vec![1.0], \n    vec![1.0], \n    vec![0.0]\n];\n\nlet network_model = NetworkModelBuilder::new()\n    .full_dense(3)\n        .tanh()\n    .end()\n    .full_dense(1)\n        .tanh()\n    .end()\n.build();\n\nlet in_size = 2;\nlet mut network = network_model.to_network(in_size);\nlet loss = Losses::MSE.to_loss();\n\nfor epoch in 0..1000 {\n    let error = network.train(epoch, \u0026x, \u0026y, \u0026loss, 1);\n    println!(\"Epoch: {} Error: {}\", epoch, error);\n}\n```\n\n### Preprocessing + CNNs example\n\nMNIST (hand-written digits recognition) workflow example:\n\n```rust\n// Step 1: Enrich the features of your data (eg. the \"columns\") with metadata using a Dataset configuration\n// The configuration is necessary for guiding further steps (preprocessing, training...)\n\n// Extract features from a spreadsheet to start building a dataset configuration\n// You could also start blank and add the columns and metadata manually\nlet mut dataset_config = Dataset::from_file(\"dataset/train.csv\");\n// Now we can add metadata to our features\ndataset_config\n    // Flag useless features for removal\n    .remove_features(\u0026[\"size\"])\n    // Tell the framework which column is an ID (so it can be ignored in training, used in joins, and so on)\n    .tag_feature(\"id\", IsId)\n    // Tell the framework which column is the feature to predict\n    // You could very well declare multiple features as Predicted\n    .tag_feature(\"label\", Predicted)\n    // Since it is a classification problem, indicate the label needs One-Hot encoding during preprocessing\n    .tag_feature(\"label\", OneHotEncode)\n    // You may also want to normalize everything except the ID \u0026 label during preprocessing\n    .tag_all(Normalized.except(\u0026[\"id\", \"label\"]));\n\n// Step 2: Preprocess the data\n\n// Create a pipeline with all the necessary steps\nlet mut pipeline = Pipeline::basic_single_pass();\n// Run it on the data\nlet (dataset_config, data) = pipeline\n    .load_data(\"dataset/train.csv\", Some(dataset_config))\n    .run();\n\n// Step 3: Specify and build your model\n\n// A model is tied to a dataset configuration\nlet model = ModelBuilder::new(dataset_config)\n    // Some configuration is also tied to the model\n    // All the configuration calls are optional, defaults are picked otherwise\n    .batch_size(128)\n    .loss(Losses::BCE)\n    .epochs(20)\n    // Then you can start building the neural network\n    .neural_network()\n        // Specify all your layers\n        // A convolution network is considered a layer of a neural network in this framework\n        .conv_network(1)\n            // Now the convolution layers\n            .full_dense(32, 5)\n                // You can set the activation function for any layer and many other parameters\n                // Otherwise defaults are picked\n                .relu() \n                .adam()\n                .dropout(0.4)\n            .end()\n            .avg_pooling(2)\n            .full_dense(64, 5)\n                .relu()\n                .adam()\n                .dropout(0.5)\n            .end()\n            .avg_pooling(2)\n        .end()\n        // Now we go back to configuring the top-level neural network\n        .full_dense(128)\n            .relu()\n            .adam()\n        .end()\n        .full_dense(10)\n            .softmax()\n            .adam()\n        .end()\n    .end()\n    .build();\n\nprintln!(\n    \"Model parameters count: {}\",\n    model.to_network().get_params().count()\n);\n\n// Step 4: Train the model\n\n// Monitor the progress of the training on a nice TUI (with other options coming soon)\nTM::start_monitoring();\n// Use a SplitTraining to split the data into a training and validation set (k-fold also available)\nlet mut training = SplitTraining::new(0.8);\nlet (preds_and_ids, model_eval) = training.run(\u0026model, \u0026data);\nTM::stop_monitoring();\n\n// Step 5: Save the resulting predictions, weights and model evaluation\n\n// Save the model evaluation per epoch\nmodel_eval.to_json_file(\"mnist_eval.json\");\n\n// Save the weights\nlet model_params = training.take_model();\nmodel_params.to_json_file(\"mnist_weights.json\");\n\n// Save the predictions alongside the original data\nlet preds_and_ids = pipeline.revert(\u0026preds_and_ids);\npipeline\n    .revert(\u0026data)\n    .inner_join(\u0026preds_and_ids, \"id\", \"id\", Some(\"pred\"))\n    .to_csv_file(\"mnist_values_and_preds.csv\");\n```\n\nYou can then plot the results using a third-party crate like `gnuplot` *(recommended)*, `plotly` *(also recommended)* or even `plotters`.\n\n*For more in-depth examples, with more configurable workflows spanning many scripts, check out the `examples` folder.*\n\n## Features\n\nSince it is a framework, it is quite opinionated and has a lot of features. But here are the main ones:\n\nNNs (Dense Layers, Full Layers...), CNNs (Dense Layers, Direct Layers, Mean Pooling...), everything batched, SGD, Adam, Momentum, Glorot, many activations (Softmax, Tanh, ReLU...), Learning Rate Scheduling, K-Folds, Split training, cacheable and revertable Pipelines (normalization, feature extraction, outliers filtering, values mapping, one-hot-encoding, log scaling...), loss functions (Binary Cross Entropy, Mean Squared Errors), model building as code, preprocessing configuration as code, performance metrics (R²...), tasks monitoring (progress, logging),  multi-backends (CPU, GPU, see [Backends](#backends)), multi-precision (see [Precision](#precision)).\n\n### Scope and goals\n\nMain goals:\n\n- Implement enough algorithms so that it can fit most use-cases\n- Don't stop at NNs, also implement CNNs, RNNs, and whatever we can\n- Handle side use-cases that could also be considered \"backend\" (model building, training, preprocessing)\n- Craft opinionated APIs for the core features, and wrappers for useful support libraries if they are not simple enough (DataFrames, Linear Algebra...)\n- APIs simplification above rigor and error handling (but no unsafe Rust)\n- Make it possible to industrialize and configure workflows (eg. data preprocessing, model building, training, evaluation...)\n- Trying not to be 1000x harder than Python and 10x slower than C++ (otherwise what's the point?)\n\nSide/future goals:\n\n- Implement rare but interesting algorithms (Direct layers, Forward Layers...)\n- WebAssembly and WebGPU support\n- Rust-native GPU backend via wgpu (I can dream, right?)\n- Python bindings via PyO3\n- Graphic tool for model building\n\nNon-goals:\n\n- Data visualization\n- Compliance with other frameworks/standards\n- Perfect error handling (don't be ashamed of `unwrap` and `expect`)\n\n### Backends\n\nSwitch backends via Cargo features:\n\n- `arrayfire` (CPU/GPU)\n    - ✅ Vision available\n    - ✅ GPU support\n    - 🫤 Slower CPU support\n    - 🫤 Hard to install (see [Installing Arrayfire](#installing-arrayfire))\n    - 🫤 C++ library, segfaults...\n- `ndarray`\n    - ✅ Fastest CPU backend\n    - ✅ Pure Rust\n    - 🫤 Vision not (yet) available\n    - 🫤 CPU only\n- `nalgebra`\n    - ✅ Pure Rust\n    - 🫤 Vision not available (and not planned)\n    - 🫤 CPU only\n\n### Precision\n\nYou can enable precision up to `f64` with the `f64` feature.\n\nPrecision below `f32` is not supported (yet).\n\n## Installing Arrayfire\n\nYou need to first [install Arrayfire](https://arrayfire.org/docs/installing.htm#gsc.tab=0) in order to use the `arrayfire` feature for fast compute on the CPU or the GPU using Arrayfire's C++/CUDA/OpenCL backends (it will first try OpenCL if installed, then CUDA, then C++). Make sure all the steps of the installation work 100% with no weird warning, as they may fail in quite subtle ways.\n\nOnce you installed Arrayfire, you:\n\n1. Set the `AF_PATH` to your Arrayfire installation directory (for example: `/opt/Arrayfire`).\n2. Add the path to lib files to the environement variables:\n    - Linux: `LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$AF_PATH/lib64`\n    - OSX: `DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$AF_PATH/lib`\n    - Windows: Add `%AF_PATH%\\lib` to PATH\n3. Run `sudo ldconfig` if on Linux\n4. Run `cargo clean`\n5. Disable default features and activate the `arrayfire` feature\n\n```toml\n[dependencies]\njiro_nn = { \n    version = \"*\", \n    default_features = false, \n    features = [\"arrayfire\"] \n}\n```\n\nIf you want to use the CUDA capabilities of Arrayfire on Linux (was tested on Windows 11 WSL2 with Ubuntu and a RTX 3060), [check out this guide](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#ubuntu-installation).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAnicetNgrt%2Fjiro-nn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAnicetNgrt%2Fjiro-nn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAnicetNgrt%2Fjiro-nn/lists"}