چگونه یک مدل یادگیری ماشینی در Rust بسازیم؟

منتشر شده در freecodecamp به تاریخ ۱۲ اکتبر ۲۰۲۲
لینک منبع: How to Build a Machine Learning Model in Rust

یادگیری ماشینی یک مفهوم واقعا جالب در برنامه‌نویسی کامپیوتر است. این شامل استفاده از داده‌ها برای آموزش یک برنامه کامپیوتری برای انجام وظایف است.

در طول فرآیند، برنامه با کشف الگوها از داده‌ها یاد می‌گیرد. این امر نیاز برنامه‌نویسان را به قوانین کد سخت در برخی برنامه‌ها کاهش می‌دهد.

زبان‌هایی مانند پایتون و R برای یادگیری و انجام وظایف یادگیری ماشینی عالی هستند. اما آن زبان‌ها مطلق نیستند. آن‌ها نقاط ضعفی دارند. برخی از برنامه‌های کاربردی یادگیری ماشینی ممکن است نیاز به انجام عملیات با سرعت بالا و کارایی منابع رایانه داشته باشند. Rust یک زبان برنامه‌نویسی قدرتمند و کارآمد است. اگرچه Rust یک اکوسیستم بالغ ندارد، اما ماهیت زبان برنامه‌‌نویسی آن را برای برنامه‌هایی که نیاز به سرعت و کارایی دارند عالی می‌کند.

برنامه‌نویسان Rust این آموزش را برای شروع یادگیری ماشینی مفید خواهند یافت و مهندسان یادگیری ماشینی این آموزش را برای شروع یادگیری ماشینی در Rust مفید خواهند یافت.

پیش‌نیازها

برای دنبال کردن این آموزش به موارد زیر نیاز دارید:

  • دانش Rust
  • و Rust نصب شده در سیستم شما

یادگیری ماشینی چیست؟

در یادگیری ماشینی، یک مدل یک شی نرم‌افزاری است که می‌تواند الگوها را از داده‌ها درک کند. آموزش یک مدل، فرآیند دادن داده به مدل برای ترسیم الگوها است. یادگیری ماشینی فرآیند آموزش یک مدل برای انجام وظایف است.

هنگامی که مدل خود را آموزش دادید، می‌توانید از آن برای نتیجه‌گیری از داده‌های جدید استفاده کنید. شما می‌توانید آن نتایج را بر اساس طبقه‌بندی‌ها یا پیش‌بینی‌ها قرار دهید. یک مدل پیش‌بینی‌کننده از داده‌های فعلی برای پیش‌بینی یک رویداد یا نتیجه استفاده می‌کند. یک مدل طبقه‌بندی از داده‌ها برای طبقه‌بندی یک شی یا مفهوم استفاده می‌کند.

نمودار زیر یک نمای کلی از فرآیند یادگیری ماشینی است:

شکل ۱. نمای کلی از فرآیند یادگیری ماشینی
شکل ۱. نمای کلی از فرآیند یادگیری ماشینی

درخت تصمیم چیست؟

الگوریتم درخت تصمیم یکی از ساده ترین الگوریتم‌های یادگیری ماشینی است. این الگوریتم، برخلاف بسیاری از الگوریتم‌های دیگر، مفهوم واقعی یادگیری ماشینی را ارائه می‌دهد.

درخت تصمیم یک الگوریتم یادگیری ماشینی برای کارهای طبقه‌بندی و رگرسیون است. یک درخت تصمیم مانند یک درخت ساختاریافته است. دارای گره ریشه، گره داخلی، گره برگ و شاخه است.

جدول زیر نمونه‌ای از داده‌ها است که طبقه‌بندی چهار حیوان را با خواص آن‌ها نشان می‌دهد:

یک مدل الگو(های) جدول را تشخیص می‌دهد، سپس درختی با این ساختار ایجاد می‌کند:

گره ریشه اولین گره در درخت تصمیم است. گره‌های برگ در خط نهایی درخت تصمیم قرار دارند. گره‌های داخلی بین گره‌های ریشه و گره‌های برگ قرار دارند. یک درخت تصمیم می‌تواند بیش از یک لایه گره داخلی داشته باشد.

در این مقاله از این الگوریتم استفاده خواهیم کرد.

شروع

مجموعه ای از ابزارها وجود دارد که به شما امکان می دهد برنامه های یادگیری ماشینی را در Rust ایجاد کنید. همه ابزارها عالی هستند، اما برای این آموزش ازLinfa استفاده خواهید کرد. Linfa یک جعبه ابزار است که شبیه به ابزار یادگیری ماشینی محبوب Python scikit-learn است.

در این بخش، نحوه راه اندازی یک پروژه Rust برای یادگیری ماشینی را یاد خواهید گرفت. فرآیند راه‌اندازی یک پروژه نسبتاً ساده است. تنها کاری که باید انجام دهید این است که این مراحل را دنبال کنید:

ابتدا یک پروژه جدید به نامml-project با دستور زیر ایجاد کنید:

cargo new --bin ml-project

سپس، وابستگی‌های زیر را در فایلCargo.toml در ml-project، در زیر [وابستگی] قرار دهید:

linfa = &quot0.6.0&quot
linfa-trees = &quot0.6.0&quot
linfa-datasets = { version = &quot0.6.0&quot, features = [&quotiris&quot] }

در نهایت دستور زیر را برای ساخت وابستگی‌ها اجرا کنید:

cargo build

ساخت محموله

در زیر توضیحی در مورد وابستگی‌ها ارائه شده‌است:

  • جعبه ابزار linfa بسته پایه برای مدل‌های یادگیری ماشینیLinfa است.
  • جعبه ابزار linfa-trees یک بسته فرعی برای ساخت مدل‌های درخت تصمیم است.
  • جعبه ابزار linfa-datasets بسته‌ای است که مجموعه داده‌های از قبل آماده شده را ارائه می‌دهد.

بسته linfa-datasets اختیاری است. اگر می‌خواهید مجموعه داده خود را آماده کنید، بخش بعدی را دنبال کنید.

چگونه مجموعه داده را آماده کنیم؟

بیشتر مدل‌های یادگیری ماشینی که در پروژه‌های روزمره استفاده می‌شوند با داده‌های خارجی آموزش داده می‌شوند، نه داده‌های ارائه‌شده توسط جعبه ابزار. در این بخش، یاد خواهید گرفت که چگونه مجموعه داده خود را از یک فایل csv آماده کنید.

ابتدا، اگر مجموعه داده‌ای ندارید که بتوانید از آن استفاده کنید، باید یک مجموعه داده دریافت کنید. می‌توانید مجموعه داده‌ای را ازKaggle دریافت کنید. برای این آموزش، از مجموعه داده بیماری قلبی استفاده خواهم کرد. مجموعه داده‌های بیماری قلبی مانند زیر است:

در این مجموعه داده، هدف نشان می‌دهد که یک فرد بیماری قلبی دارد. ۱ به این معنی است که آن‌ها بیماری قلبی دارند، ۰ به این معنی است که آن‌ها بیماری قلبی ندارند.

بقیه فیلدهای مجموعه داده جزئیات هر فرد است. یک مدل می‌تواند از این مجموعه داده یاد بگیرد و بتواند تشخیص دهد که آیا یک فرد بیماری قلبی دارد یا خیر.

پس از دانلود مجموعه داده، فایل csv را در پوشه src پروژه خود استخراج کنید.

.
├── Cargo.lock
├── Cargo.toml
└── src
├── heart.csv
└── main.rs

برای تهیه یک مجموعه داده، باید بسته‌های csv وndarray را به پروژه خود اضافه کنید. Cargo.toml را باز کنید و عبارت پایین را زیر [وابستگی] بنویسید:

csv = &quot1.1&quot
ndarray = &quot0.15.6&quot

اکنون، کارگو بیلد را برای دانلود بسته‌ها اجرا کنید و آماده حرکت هستید.

در مراحل بعدی، من شما را در ساخت تابع get_dataset راهنمایی خواهم کرد. تابع get_dataset فایل heart.csv را می‌خواند، محتوای آن را تجزیه می‌کند، مجموعه داده‌ای را با محتوای آن آماده می‌کند و مجموعه داده آماده شده را برمی‌گرداند. بیا شروع کنیم!

ابتدا بسته‌های لازم را وارد کنید:

use csv::Reader;
use std::fs::File;
use ndarray::{ Array, Array1, Array2 };
use linfa::Dataset;

سپس تابع get_dataset زیر را در main.rs بنویسید:

fn get_dataset() -> Dataset<f32, i32, ndarray::Dim<[usize; 1]>> {
let mut reader = Reader::from_path(&quot./src/heart.csv&quot).unwrap();
let headers = get_headers(&mut reader);
let data = get_data(&mut reader);
let target_index = headers.len() - 1;
let features = headers[0..target_index].to_vec();
let records = get_records(&data, target_index);
let targets = get_targets(&data, target_index);
return Dataset::new(records, targets)
.with_feature_names(features);
}

در نهایت، با اضافه کردن تعاریف get_headers، get_data، get_records و get_targets کار را به پایان برسانید:

fn get_headers(reader: &mut Reader<File>) -> Vec<String> {
return reader
.headers().unwrap().iter()
.map(|r| r.to_owned())
.collect();
}
fn get_records(data: &Vec<Vec<f32>>, target_index: usize) -> Array2<f32> {
let mut records: Vec<f32> = vec![];
for record in data.iter() {
records.extend_from_slice( &record[0..target_index] );
}
return Array::from( records ).into_shape((303, 13)).unwrap();
}
fn get_targets(data: &Vec<Vec<f32>>, target_index: usize) -> Array1<i32> {
let targets = data
.iter()
.map(|record| record[target_index] as i32)
.collect::<Vec<i32>>();
return Array::from( targets );
}
fn get_data(reader: &mut Reader<File>) -> Vec<Vec<f32>> {
return reader
.records()
.map(|r|
r
.unwrap().iter()
.map(|field| field.parse::<f32>().unwrap())
.collect::<Vec<f32>>()
)
.collect::<Vec<Vec<f32>>>();
}

در اینجا توضیح گام‌به‌گام تابع get_dataset آمده‌است:

ابتدا، یک خواننده با اشاره به ./src/heart.csv مقداردهی اولیه کنید:

let mut reader = Reader::from_path(&quot./src/heart.csv&quot).unwrap();

در مرحله بعد، هدرها و داده‌ها را از خواننده استخراج کنید:

let headers = get_headers(&mut reader);
let data = get_data(&mut reader);

سپس، شاخص هدف را در هدرها محاسبه کنید:

let target_index = headers.len() - 1;

پس از آن، ویژگی‌ها را از هدرها دریافت کنید:

let features = headers[0..target_index].to_vec();

در مرحله بعد، سوابق و اهداف را از داده‌ها بازیابی کنید:

let records = get_records(&data, target_index);
let targets = get_targets(&data, target_index);

در نهایت، مجموعه داده را با رکوردها، اهداف و ویژگی‌ها بسازید، سپس برگردانید:

return Dataset::new(records, targets)
.with_feature_names(features);

برای تکمیل تابع و مشاهده اینکه چگونه مجموعه داده به نظر می‌رسد، تابع اصلی خود را به صورت زیر در نظر بگیرید:

fn main() {
let dataset = get_dataset();
println!(&quot{:?}&quot, dataset);
}

هنگامی که آن تابع اصلی خود را تعیین کردید و آن را با کارگو اجرا کردید، مجموعه داده را در خروجی مشاهده خواهید کرد:

DatasetBase { records: [[63.0, 1.0, 3.0, 145.0, 233.0, ..., 0.0, 2.3, 0.0, 0.0, 1.0],
[37.0, 1.0, 2.0, 130.0, 250.0, ..., 0.0, 3.5, 0.0, 0.0, 2.0],
[41.0, 0.0, 1.0, 130.0, 204.0, ..., 0.0, 1.4, 2.0, 0.0, 2.0],
[56.0, 1.0, 1.0, 120.0, 236.0, ..., 0.0, 0.8, 2.0, 0.0, 2.0],
[57.0, 0.0, 0.0, 120.0, 354.0, ..., 1.0, 0.6, 2.0, 0.0, 2.0],
...,
[57.0, 0.0, 0.0, 140.0, 241.0, ..., 1.0, 0.2, 1.0, 0.0, 3.0],
[45.0, 1.0, 3.0, 110.0, 264.0, ..., 0.0, 1.2, 1.0, 0.0, 3.0],
[68.0, 1.0, 0.0, 144.0, 193.0, ..., 0.0, 3.4, 1.0, 2.0, 3.0],
[57.0, 1.0, 0.0, 130.0, 131.0, ..., 1.0, 1.2, 1.0, 1.0, 3.0],
[57.0, 0.0, 1.0, 130.0, 236.0, ..., 0.0, 0.0, 1.0, 1.0, 2.0]], shape=[303, 13], strides=[13, 1], layout=Cc (0x5), const ndim=2, targets: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], shape=[303], strides=[1], layout=CFcf (0xf), const ndim=1, weights: [], shape=[0], strides=[0], layout=CFcf (0xf), const ndim=1, feature_names: [&quotage&quot, &quotsex&quot, &quotcp&quot, &quottrestbps&quot, &quotchol&quot, &quotfbs&quot, &quotrestecg&quot, &quotthalach&quot, &quotexang&quot, &quotoldpeak&quot, &quotslope&quot, &quotca&quot, &quotthal&quot] }

نحوه ایجاد یک مدل درخت تصمیم

در این بخش، نحوه ایجاد یک مدل درخت تصمیم و آموزش آن را به شما نشان خواهم داد. مجموعه داده‌ای که استفاده خواهم کرد مجموعه داده عنبیه ارائه شده توسط linfa-datasets است.

مجموعه داده عنبیه حاوی رکوردی از عرض کاسبرگ، ارتفاع کاسبرگ، عرض گلبرگ و ارتفاع گلبرگ چند عنبیه است و هر رکورد را بر اساس گونه‌های دارای برچسب شماره طبقه‌بندی می‌کند.

کد مدل ساده است. فایل main.rs را باز کنید و موارد زیر را در آن قرار دهید:

use linfa_trees::DecisionTree;
use linfa::prelude::*;
fn main() {
let (train, test) = linfa_datasets::iris()
.split_with_ratio(0.9);
let model = DecisionTree::params()
.fit(&train).unwrap();
let predictions = model.predict(&test);
println!(&quot{:?}&quot, predictions);
println!(&quot{:?}&quot, test.targets);
}

در اینجا یک توضیح است:

ابتدا بسته‌های لازم را وارد کنید:

use linfa_trees::DecisionTree;
use linfa::prelude::*;

سپس مجموعه داده را واکشی کنید و به داده‌های آزمایشی و آموزشی تقسیم کنید:

let (train, test) = linfa_datasets::iris()
.split_with_ratio(0.9);

پس از آن، مدل را مقداردهی اولیه کنید و آن را با داده‌های آموزشی آموزش دهید:

let model = DecisionTree::params()
.fit(&train).unwrap();

سپس، از داده‌های تست برای انجام برخی پیش‌بینی‌ها استفاده کنید:

let predictions = model.predict(&test);

در نهایت، پیش‌بینی‌ها را با مقادیر واقعی مقایسه کنید:

println!(&quot{:?}&quot, predictions);
println!(&quot{:?}&quot, test.targets);

اگر برنامه را با کارگو اجرا کنید، دسته پیش‌بینی شده و دسته واقعی در ترمینال را به‌عنوان خروجی دریافت خواهید کرد:

$ cargo run
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], shape=[15], strides=[1], layout=CFcf (0xf), const ndim=1
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], shape=[15], strides=[1], layout=CFcf (0xf), const ndim=1

با توجه به موارد فوق می‌توانید دقت کنید که این مدل ۱۰۰٪ است. این همیشه برای همه مدل‌های یادگیری ماشینی صدق نمی‌کند. اگر قبل از آموزش مدل در بالا، مجموعه داده را به هم بزنید، ممکن است مدل دیگر دقیق نباشد.

هدف یادگیری ماشینی این است که تا حد امکان دقیق باشد. اکثر اوقات دقت ۱۰۰٪ امکان‌پذیر نیست.

نتیجه‌گیری

در این آموزش کمی در مورد یادگیری ماشینی یاد گرفتید و هم‌چنین نحوه ایجاد یک مدل درخت تصمیم با استفاده از Rust را دیدید.

مدل‌های یادگیری ماشینی در لینفا از فرآیند مشابهی در ساخت و آموزش پیروی می‌کنند، بنابراین تنها کاری که برای استفاده از انواع دیگر مدل‌ها باید انجام دهید این است که در مورد هر یک از آن‌ها اطلاعات کسب کنید و می‌توانید ادامه دهید.

با استفاده از مستندات آن می‌توانید درباره لینفا و مدل‌هایی که پشتیبانی می‌کند بیش‌تر بدانید.

با تشکر برای خواندن، و کد نویسی مبارک!

این متن با استفاده از ربات ‌ترجمه مقالات یادگیری ماشینی ترجمه شده و به صورت محدود مورد بازبینی انسانی قرار گرفته است.در نتیجه می‌تواند دارای برخی اشکالات ترجمه باشد.
مقالات لینک‌شده در این متن می‌توانند به صورت رایگان با استفاده از مقاله‌خوان ترجمیار به فارسی مطالعه شوند.