Skip to content

Latest commit

 

History

History
781 lines (558 loc) · 33.1 KB

29_rust_and_machine_learning.md

File metadata and controls

781 lines (558 loc) · 33.1 KB

🦀 30 Days of Rust: Day 29 - Rust and Machine Learning 🤖

LinkedIn Follow me on GitHub

Author: Het Patel

October, 2024

<< Day 28 | Day 30 >>

30DaysOfRust


📘 Day 29 - Rust and Machine Learning 🤖

👋 Welcome

Welcome to Day 29 of the 30 Days of Rust Challenge! 🎉

Today, we explore Rust and Machine Learning. With its growing ecosystem of libraries and tools, Rust is becoming a competitive choice for machine learning, offering high performance, memory safety, and ease of use.

By the end of this chapter, you’ll have the tools and understanding to get started building machine learning models in Rust.

🧠 What is Machine Learning?

Machine Learning (ML) is a field of artificial intelligence that enables computers to learn and make decisions based on data, rather than following strictly programmed instructions.

  • Supervised Learning: The algorithm is trained on labeled data to predict outcomes.
  • Unsupervised Learning: The algorithm finds patterns and relationships in data without labeled outputs.
  • Reinforcement Learning: The algorithm learns by interacting with an environment and receiving feedback.

Machine learning is used in applications like image recognition, natural language processing, and recommendation systems.

🦀 Why Use Rust for Machine Learning?

Rust offers several benefits when applied to machine learning:

  1. Performance: Rust’s compiled nature ensures low latency and high throughput, crucial for ML tasks that require intensive computation.
  2. Memory Safety: Rust guarantees memory safety without garbage collection, which is essential for large-scale data processing and working with GPUs.
  3. Concurrency: Rust’s powerful concurrency features allow efficient parallel processing, essential in training large models.
  4. Interfacing with C/C++: Rust can easily interface with low-level libraries and models written in C/C++ or Python.
  5. Growing Ecosystem: Although not as mature as Python, Rust’s ML ecosystem is rapidly developing, with libraries supporting key ML algorithms and tasks.

📦 Key Rust Libraries for Machine Learning

Several libraries make machine learning in Rust possible. Below are some of the most popular ones:

📊 ndarray

  • A high-dimensional array library for Rust, similar to NumPy in Python.
  • Useful for storing data, performing mathematical operations, and matrix manipulations.

Add to Cargo.toml:

[dependencies]
ndarray = "0.15"

ndarray is a library for handling n-dimensional arrays, which is central to many ML algorithms. It’s Rust’s answer to NumPy in Python.

  • Key Features:
    • Handles multi-dimensional arrays for numerical computations.
    • Supports slicing, reshaping, and advanced linear algebra operations.
    • Great for tasks like data manipulation, matrix multiplication, and element-wise operations.

Example: Creating a 2D Array

use ndarray::Array2;

let data = Array2::<f64>::zeros((3, 3));
println!("{:?}", data);

or

use ndarray::Array2;
let array = Array2::<f64>::zeros((3, 3));
println!("{:?}", array);

🧠 tch-rs

  • Rust bindings for LibTorch, PyTorch's C++ library.
  • Allows you to build, train, and deploy neural networks in Rust.
  • Supports automatic differentiation and GPU acceleration.

Add to Cargo.toml:

[dependencies]
tch = "0.5"

tch-rs is a Rust binding to PyTorch, one of the most powerful deep learning libraries. This allows you to use PyTorch’s GPU-accelerated features within the safe, fast Rust environment.

  • Key Features:
    • GPU acceleration for tensor operations (via CUDA).
    • Efficient support for creating and training neural networks.
    • Seamless interface to PyTorch’s deep learning models for tasks like image classification, NLP, and reinforcement learning.

Example: Creating a Tensor

use tch::{Tensor, Device};

let tensor = Tensor::randn(&[3, 3], (tch::Kind::Float, Device::Cpu));
println!("{:?}", tensor);

or

use tch::{Tensor, Device};
let x = Tensor::of_slice(&[1.0, 2.0, 3.0]).to_device(Device::Cuda(0));
println!("{:?}", x);

🔍 rustlearn

  • A machine learning library for Rust, offering simple implementations of algorithms like decision trees, linear regression, and k-nearest neighbors.
  • More suitable for classical machine learning algorithms rather than deep learning.

Add to Cargo.toml:

[dependencies]
rustlearn = "0.8"

rustlearn is a classical machine learning library in Rust. It implements many well-known ML algorithms like decision trees, k-means, and linear regression.

  • Key Features:
    • Implements algorithms such as logistic regression, random forests, and SVM.
    • Designed for fast performance with large datasets.
    • Uses ndarray for efficient data handling.

Example: Simple Linear Regression

use rustlearn::prelude::*;
use rustlearn::linear_models::LinearRegression;

let mut model = LinearRegression::default();
let X = ndarray::Array::random((10, 3), ndarray::RandNormal(0., 1.));
let y = ndarray::Array::random((10, 1), ndarray::RandNormal(0., 1.));
model.fit(&X, &y).unwrap();

or

use rustlearn::linear_models::LogisticRegression;
let mut model = LogisticRegression::default();
model.fit(&data, &target).unwrap();

🔬 linfa

  • A more recent library designed to provide a comprehensive toolkit for machine learning, including tools for data preprocessing, training, and evaluation.
  • Offers many algorithms like k-means, support vector machines, and decision trees.

Add to Cargo.toml:

[dependencies]
linfa = "0.6"

linfa is a modern machine learning framework inspired by Python's scikit-learn. It provides easy-to-use implementations of many classical machine learning algorithms.

  • Key Features:
    • Implements algorithms like linear regression, KNN, decision trees, and support vector machines (SVM).
    • Uses ndarray for efficient data storage and operations.
    • Well-documented API, aimed at making ML accessible in Rust.
use linfa::prelude::*;
use linfa_linear::LinearRegression;
let model = LinearRegression::fit(&data, &target).unwrap();

🧩 tract

tract is a high-performance inference engine for deep learning, designed to work seamlessly in Rust. It supports models trained with TensorFlow, ONNX, and other frameworks.

  • Key Features:
    • Inference on pre-trained models (supports both CPU and GPU).
    • Compatible with models in TensorFlow and ONNX formats.
    • Focused on production-quality performance with a minimal memory footprint.
use tract_onnx::prelude::*;
let model = tract_onnx::onnx().model_for_path("model.onnx")?.into_optimized()?;

This library is particularly useful for deploying deep learning models into production environments where performance is critical.

autodiff

autodiff is a Rust library for automatic differentiation (autodiff), enabling the easy computation of derivatives of functions. This is useful for training machine learning models where gradients need to be computed efficiently.

  • Key Features:
    • Computes gradients of functions with respect to their inputs.
    • Used for building custom optimization routines and training algorithms.
    • Supports both scalar and vectorized operations.
use autodiff::{autodiff, Vector};
let f = |x: Vector| x[0].powi(2) + x[1].powi(2); // x^2 + y^2
let gradient = autodiff::gradient(f, Vector::new(vec![1.0, 1.0])).unwrap();

🔧 Setting Up Your Machine Learning Project

  1. Install Rust: Ensure you have the latest version of Rust installed.

    rustup update
  2. Create a New Project:

    cargo new rust_ml_example --bin
    cd rust_ml_example
  3. Add Dependencies: Open Cargo.toml and add your chosen ML libraries.
    For example:

    [dependencies]
    ndarray = "0.15"
    rustlearn = "0.8"
  4. Build Your Model: Start writing the logic for your machine learning model, depending on the type of problem (regression, classification, etc.).

📈 Example: A Simple Linear Regression Model

In this example, we’ll use the rustlearn library to build a simple linear regression model.

1. Prepare the Dataset

use ndarray::Array2;

let X = Array2::<f64>::zeros((10, 3));  // Input features
let y = Array2::<f64>::zeros((10, 1));  // Target values

2. Train the Model

use rustlearn::linear_models::LinearRegression;

let mut model = LinearRegression::default();
model.fit(&X, &y).unwrap();

3. Make Predictions

let predictions = model.predict(&X).unwrap();
println!("Predictions: {:?}", predictions);

This is a basic implementation of linear regression in Rust. You can modify this with real datasets, optimize hyperparameters, and explore other algorithms.

or

Let’s walk through how to implement a simple linear regression model using the linfa crate.

Steps:

  1. Add Dependencies: Add linfa and ndarray to your Cargo.toml:

    [dependencies]
    linfa = "0.7"
    ndarray = "0.15"
  2. Prepare the Data: Create synthetic data for a linear regression task, where ( y = 3x + 2 ).

    use ndarray::Array2;
    let data = Array2::<f64>::random((100, 1), rand::distributions::Uniform::new(0., 10.));
    let target = data.mapv(|x| 3. * x + 2.); // y = 3x + 2
  3. Train the Model: Use linfa’s LinearRegression algorithm to fit the model to the data:

    use linfa::prelude::*;
    use linfa_linear::LinearRegression;
    
    let model = LinearRegression::fit(&data, &target).unwrap();
  4. Make Predictions: Once trained, use the model to make predictions on new data:

    let new_data = Array2::from_shape_vec((1, 1), vec![5.0]).unwrap();
    let prediction = model.predict(&new_data);
    println!("Prediction: {:?}", prediction);

⚙️ Working with Data in Rust for ML 📊

Data is a critical part of machine learning. Rust provides powerful tools for working with datasets.

📥 Data Loading

To load data, you can use libraries like csv or serde for reading from CSV files. Example with csv:

[dependencies]
csv = "1.1"
use csv::ReaderBuilder;
use std::error::Error;

fn load_data(file_path: &str) -> Result<Vec<Vec<f64>>, Box<dyn Error>> {
    let mut rdr = ReaderBuilder::new().has_headers(true).from_path(file_path)?;
    let mut data = Vec::new();
    
    for result in rdr.records() {
        let record = result?;
        let row: Vec<f64> = record.iter().map(|s| s.parse().unwrap()).collect();
        data.push(row);
    }
    
    Ok(data)
}

🔄 Data Preprocessing

Preprocessing is crucial for machine learning, and Rust provides libraries like ndarray for manipulating data efficiently. This includes normalization, scaling, or missing data imputation.

use ndarray::Array2;
let data = Array2::from_vec((5, 2), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]);
let normalized = data.mapv(|x| (x - x.mean().unwrap()) / x.std().unwrap());

🔧 Feature Engineering

Feature engineering involves transforming raw data into a format that is better suited for machine learning models. In Rust, you can use libraries like ndarray and polars to create new features, handle categorical variables, and scale numerical features.

  • Example: Encoding a categorical feature.
use polars::prelude::*;
let df = df![
    "color" => &["red", "blue", "green", "blue", "green"],
    "value" => &[1, 2, 3, 4, 5]
].unwrap();

let df = df
    .lazy()
    .with_columns(vec![
        col("color").apply(|s| match s.get(0) { "red" => 0, "blue" => 1, "green" => 2, _ => 0 }).into(),
    ])
    .collect()
    .unwrap();

🚀 Advanced Topics in Machine Learning with Rust ⚡

Welcome to the Advanced Topics in Machine Learning with Rust section! In this section, we will dive into some of the most sophisticated techniques and tools available to build and optimize machine learning models in Rust. From neural networks to distributed training, we’ll explore the depth of machine learning in Rust and how it competes with other languages like Python.

🧠 Neural Networks

Neural networks are the backbone of many machine learning models, and Rust provides several libraries that make building and training neural networks efficient and performant. In this section, we will cover the core concepts behind neural networks and how to implement them in Rust.

Key Concepts:

  1. Neurons & Layers: Neural networks are composed of layers, with each layer containing neurons that apply specific transformations to the input data.
  2. Activation Functions: Functions like ReLU, Sigmoid, and Tanh that decide whether a neuron should be activated based on its input.
  3. Backpropagation: The process of adjusting weights in the network to minimize the error between predicted and actual outputs.

Rust Libraries for Neural Networks:

  • Tch-rs: A Rust binding for PyTorch, providing access to tensor operations and neural network functionalities.
  • rustml: A lightweight machine learning library that includes tools for neural networks.

Example:

use tch::{Tensor, nn, Device};

fn main() {
    let vs = nn::VarStore::new(Device::cuda_if_available());
    let net = nn::seq()
        .add(nn::Linear::new(1, 2))
        .add(nn::Linear::new(2, 1));
    
    let input = Tensor::of_slice(&[1.0, 2.0]);
    let output = net.forward(&input);
    println!("{:?}", output);
}

💡 Deep Learning

Deep learning is a subfield of machine learning focused on using neural networks with many layers, often referred to as deep neural networks (DNNs). Rust's deep learning ecosystem is growing, and it's becoming increasingly powerful for training complex models like CNNs, RNNs, and transformers.

Key Concepts:

  1. Convolutional Neural Networks (CNNs): Primarily used for image data, CNNs are efficient in learning spatial hierarchies of features.
  2. Recurrent Neural Networks (RNNs): Ideal for sequence data (like time series or text), where past information influences the prediction.
  3. Transformers: The foundation for state-of-the-art models in NLP (Natural Language Processing).

Rust Libraries for Deep Learning:

  • Tch-rs: Provides extensive support for training deep learning models, including CNNs and RNNs.
  • ndarray: An n-dimensional array library useful for manipulating data before feeding it to deep learning models.

Example:

use tch::{Tensor, nn, Device, Kind};

fn main() {
    let vs = nn::VarStore::new(Device::cuda_if_available());
    let model = nn::seq()
        .add(nn::Conv2D::new(1, 32, 3, nn::ConvConfig { stride: 1, padding: 1 }))
        .add(nn::ReLU::new())
        .add(nn::Linear::new(32, 10));
    
    let input = Tensor::ones(&[1, 1, 28, 28], (Kind::Float, Device::cuda_if_available()));
    let output = model.forward(&input);
    println!("{:?}", output);
}

🔄 Data Pipelines and Preprocessing

Before training a model, it's critical to clean, process, and transform data into a format that the model can work with. Data preprocessing is essential to improving the performance of machine learning models.

Key Concepts:

  1. Data Cleaning: Handling missing values, filtering outliers, and correcting inconsistencies.
  2. Normalization: Scaling data values to a common range, such as [0, 1].
  3. Feature Engineering: Creating new features from existing data to better represent underlying patterns.
  4. Data Augmentation: Generating more data by applying transformations like rotation or flipping to images.

Rust Libraries for Data Pipelines:

  • Polars: A fast DataFrame library in Rust, ideal for efficient data manipulation.
  • ndarray: Useful for working with numerical data in multi-dimensional arrays.
  • csv: For reading and writing CSV files in Rust.

Example:

use polars::prelude::*;

fn main() -> Result<()> {
    let df = df![
        "name" => &["Alice", "Bob", "Charlie"],
        "age" => &[25, 30, 35],
        "city" => &["New York", "Los Angeles", "Chicago"]
    ]?;
    
    println!("{}", df);
    Ok(())
}

⚙️ Hyperparameter Tuning

Hyperparameter tuning refers to the process of selecting the optimal values for the hyperparameters of a model, such as the learning rate, batch size, number of layers, etc. It is crucial for improving the performance of a model.

Key Concepts:

  1. Grid Search: A brute-force approach to search through a predefined set of hyperparameters.
  2. Random Search: Randomly selecting hyperparameter combinations and testing them.
  3. Bayesian Optimization: An advanced method that builds a model to predict which hyperparameter combinations will perform the best.

Rust Libraries for Hyperparameter Tuning:

  • Hyperopt: A Rust port of the popular Python library for hyperparameter optimization.
  • Optuna: Another hyperparameter optimization library with Rust bindings.

Example:

use hyperopt::{fmin, tpe, space::uniform};
use rand::distributions::Uniform;

fn main() {
    let param_space = uniform(0.01, 0.1);
    let best = fmin(tpe::suggest, param_space, 100);
    println!("Best hyperparameters: {:?}", best);
}

🌍 Distributed Training with Rust

For large datasets and complex models, training on a single machine is not always feasible. Distributed training allows models to be trained across multiple machines, making it possible to scale up machine learning tasks efficiently.

Key Concepts:

  1. Data Parallelism: Splitting data across multiple devices and training on subsets in parallel.
  2. Model Parallelism: Distributing different parts of the model across multiple devices.
  3. Asynchronous Updates: Updating model weights asynchronously between devices.

Rust Libraries for Distributed Training:

  • Rust ML: Provides tools to support distributed training using MPI (Message Passing Interface).
  • TensorFlow Rust: Rust bindings for TensorFlow, enabling large-scale training on multiple machines.
  • Ray: A fast and simple framework for building distributed applications, useful for training large models.

Example:

use rayon::prelude::*;

fn train_model() {
    let data = vec![1, 2, 3, 4, 5];
    let result: Vec<i32> = data.par_iter().map(|&x| x * 2).collect();
    println!("{:?}", result);
}

🔧 Model Evaluation and Testing

Model evaluation is a critical step in the machine learning pipeline that helps to measure the performance of your model and ensure it generalizes well to unseen data. This step ensures that the model does not just memorize the training data but can make accurate predictions on new data.

Key Concepts in Model Evaluation:

  1. Train-Test Split:

    • Split your dataset into training and testing sets. A common ratio is 80/20 or 70/30 for training and testing, respectively.
    • This ensures the model is tested on data it hasn’t seen during training, simulating how it will perform in real-world scenarios.
  2. Cross-Validation:

    • Cross-validation involves splitting the data into multiple folds and training/testing the model on each fold. This reduces the variance in model evaluation and provides a more reliable performance estimate.
    • K-Fold Cross-Validation: Divide data into K subsets, train on K-1 folds, and test on the remaining fold. Repeat this process K times, rotating the test fold each time.
  3. Evaluation Metrics:

    • Accuracy: Measures the percentage of correct predictions. It's suitable for balanced datasets but may not be ideal for imbalanced classes.
    • Precision and Recall:
      • Precision: The ratio of correctly predicted positive observations to total predicted positives.
      • Recall (Sensitivity): The ratio of correctly predicted positive observations to total actual positives.
    • F1-Score: The harmonic mean of precision and recall, providing a balance between them.
    • AUC-ROC Curve: The area under the Receiver Operating Characteristic curve, used to evaluate binary classification models.
    • Confusion Matrix: A table used to evaluate classification performance, showing true positives, true negatives, false positives, and false negatives.

Model Testing:

  • Test Data: After training your model on the training data, evaluate it using the test data to assess its generalization.
  • Overfitting and Underfitting:
    • Overfitting: Happens when the model learns the training data too well and performs poorly on unseen data.
    • Underfitting: Happens when the model is too simple and cannot capture the underlying patterns of the data.

Example (Rust using rustlearn library):

use rustlearn::prelude::*;
use rustlearn::linear_models::LogisticRegression;
use rustlearn::metrics::accuracy_score;
use rustlearn::datasets::iris;

fn main() {
    let (data, target) = iris::load_data();
    
    let mut model = LogisticRegression::default();
    model.fit(&data, &target).unwrap();
    
    let predictions = model.predict(&data).unwrap();
    let accuracy = accuracy_score(&target, &predictions);
    
    println!("Accuracy: {:.2}%", accuracy * 100.0);
}

📉 Model Optimization and Performance Tuning

After evaluating the model, the next step is model optimization and performance tuning. The goal is to improve the model’s accuracy and ensure it performs well on both the training and testing datasets.

Techniques for Model Optimization:

  1. Hyperparameter Tuning:

    • Hyperparameters are parameters that are set before training the model (e.g., learning rate, regularization strength, number of trees in random forests, etc.).
    • Grid Search: Exhaustively search through a manually specified set of hyperparameters to find the best combination.
    • Random Search: Randomly sample hyperparameters, usually over a large search space. It’s less exhaustive than grid search but can often find good results faster.
    • Bayesian Optimization: A more advanced technique that models the performance of hyperparameters as a probabilistic function and uses this model to guide the search for optimal values.
  2. Regularization:

    • Regularization techniques help prevent overfitting by adding a penalty to the loss function based on the complexity of the model.
    • Common regularization methods include L2 regularization (Ridge) and L1 regularization (Lasso).
  3. Feature Engineering:

    • Feature Selection: Select the most important features to improve the model's performance and reduce overfitting. Methods include correlation-based filtering, recursive feature elimination, and tree-based feature importance.
    • Feature Scaling: Normalize or standardize features, especially for algorithms like logistic regression and SVMs that are sensitive to feature scaling.
  4. Ensemble Methods:

    • Bagging (Bootstrap Aggregating): Trains multiple models independently and combines their predictions. Examples include Random Forest.
    • Boosting: Trains models sequentially, where each new model corrects errors made by the previous one. Examples include Gradient Boosting and XGBoost.
    • Stacking: Combines multiple models to make a final prediction, typically by training a meta-model on the outputs of the base models.
  5. Learning Curves:

    • Plot learning curves for training and validation errors to monitor how the model’s performance improves with more data or training time. These curves help identify overfitting or underfitting.

Example (Rust using rustlearn library for Hyperparameter Tuning):

use rustlearn::prelude::*;
use rustlearn::ensemble::RandomForest;
use rustlearn::datasets::iris;
use rustlearn::metrics::accuracy_score;

fn main() {
    let (data, target) = iris::load_data();

    let mut model = RandomForest::new(100); // Set number of trees in the forest
    model.fit(&data, &target).unwrap();
    
    let predictions = model.predict(&data).unwrap();
    let accuracy = accuracy_score(&target, &predictions);
    
    println!("Optimized Model Accuracy: {:.2}%", accuracy * 100.0);
}

🚀 Hands-On Challenge

Problem Statement:

Build a machine learning pipeline to predict the species of Iris flowers using the Iris dataset.

Steps:

  1. Data Preprocessing:

    • Load the Iris dataset.
    • Split the data into training and testing sets.
    • Perform feature scaling (normalization) to improve the model's performance.
  2. Model Building:

    • Train a Random Forest model using the training data.
    • Tune the hyperparameters of the Random Forest model to improve accuracy.
    • Use cross-validation to evaluate model performance.
  3. Model Evaluation:

    • Calculate evaluation metrics such as accuracy, precision, recall, and F1-score.
    • Generate a confusion matrix to analyze the performance of the model on test data.
  4. Optimization:

    • Apply grid search or random search to fine-tune the hyperparameters.
    • Try using ensemble methods such as boosting or bagging to improve performance.

Deliverables:

  • Source code in Rust that includes data preprocessing, model training, and evaluation.
  • A report discussing the performance of the model and the results of optimization efforts.

or

Beginner:

  1. Create a simple linear regression model using rustlearn and a small dataset.
  2. Experiment with other machine learning models like k-means or decision trees.

Intermediate:

  1. Implement a neural network model using tch-rs and train it on a basic dataset.
  2. Perform data preprocessing using ndarray before training a model.

Advanced:

  1. Build a complete ML pipeline using linfa, including data preprocessing, model training, and evaluation.
  2. Try using a real-world dataset, like the Titanic dataset, and build a classification model.

💻 Exercises - Day 29

Exercise: Level 1

  1. Linear Regression Model:
    • Implement a simple linear regression model using linfa and test it with a synthetic dataset.
  2. Load and Preprocess Data:
    • Write a function to load a CSV file and preprocess the data (e.g., normalization).

🚀 Exercise: Level 2

  1. Classification with Logistic Regression:
    • Implement a binary classification task using logistic regression from linfa.
  2. Train a Decision Tree:
    • Train a decision tree classifier using rustlearn and evaluate its performance.

🏆 Exercise: Level 3 (Advanced)

  1. Build a Neural Network:
    • Using tch-rs, implement a simple feedforward neural network and train it on a dataset.
  2. Deep Learning with GPU Acceleration:
    • Train a deep learning model on a larger dataset using GPU with tch-rs.

🎥 Helpful Video References

  1. Why I Switched from Python to Rust for AI Deployment
  2. Let's Build Machine Learning...in RUST? From Begin

📚 Further Reading

Topic Resource
Machine Learning in Rust Awesome Rust ML
tch-rs Documentation tch-rs GitHub
linfa Documentation linfa GitHub
Rust and Data Science Rust for Data Science
Deep Learning Deep Learning

📝 Day 29 Summary

Today, you learned about machine learning with Rust:

  • Rust’s benefits for machine learning, such as performance, memory safety, and concurrency.
  • Key libraries like ndarray, tch-rs, rustlearn, and linfa that make machine learning possible in Rust.
  • How to create simple machine learning models like linear regression and extend them to more complex models.

Machine learning in Rust is a growing field, and while the ecosystem is still maturing, it offers significant advantages in terms of performance and memory safety. Keep experimenting with the libraries and models to strengthen your skills!

In today's session, we've explored some advanced topics in machine learning using Rust. From implementing neural networks to distributed training, Rust's performance and safety make it an excellent choice for building machine learning systems. These techniques will enhance the capabilities of any Rust machine learning project, enabling you to build scalable, optimized, and high-performance models.

Stay tuned for Day 30, where we will explore Project Wrap-Up & Advanced Concepts in Rust! 🚀

🌟 Great job on completing Day 29! Keep practicing, and get ready for Day 30!

Thank you for joining Day 29 of the 30 Days of Rust challenge! If you found this helpful, don’t forget to Star GIF star this repository, share it with your friends, and stay tuned for more exciting lessons ahead!

Stay Connected
📧 Email: Hunterdii
🐦 Twitter: @HetPate94938685
🌐 Website: Working On It(Temporary)

<< Day 28 | Day 30 >>