iron_learn/
gradient_descent.rs

1//! The `gradient_descent` module provides gradient descent optimization
2
3use crate::Tensor;
4
5/// The `gradient_descent` function performs a single step of the gradient descent optimization algorithm.
6///
7/// # Arguments
8///
9/// * `x` - All values of all features arranged in a m * n matrix, where m is nuber of data points and n is number of features.
10/// * `w` - The current value of the weights for each feature, arranged in n * 1 tensor, where n is number of features.
11/// * `y` - The collected target values arranged in a m * 1 matrix, where m is the number of data points.
12/// * `l` - The learning rate, which controls the size of the update step.
13/// * `logistic` - The indicator for Logistic Regression. If set to true, the gradient descent used `Sigmoid` function as classification algorithm. 
14/// # Returns
15///
16/// The updated weight matrix
17///
18/// # Example
19///
20/// ```
21/// use iron_learn::Tensor;
22/// use iron_learn::gradient_descent::gradient_descent;
23///
24/// let learning_rate: f64 = 0.01;
25/// let w = Tensor::new(vec![2, 1], vec![3.0, 4.0]).unwrap();
26/// let x = Tensor::new(vec![1, 2], vec![3.0, 4.0]).unwrap();
27/// let y = Tensor::new(vec![1, 1], vec![5.0]).unwrap();
28///
29/// let w = gradient_descent(&x, &y, &w, learning_rate, false); // For linear regression
30/// ```
31///
32/// 
33#[deprecated(
34    since = "0.4.0"
35)]
36pub fn gradient_descent(x: &Tensor<f64>, y: &Tensor<f64>, w: &Tensor<f64>, l: f64, logistic: bool) -> Tensor<f64> {
37    let data_size = *(x.get_shape().first().unwrap()) as f64;
38    let lines = x.mul(w).unwrap();
39
40    let prediction = match logistic {
41        true => sigmoid(lines),
42        false => lines
43    };
44    
45    let loss = y.sub(&prediction).unwrap();
46    let d = x
47        .t()
48        .unwrap()
49        .mul(&loss)
50        .unwrap()
51        .scale(-1.0 * l / data_size);
52    w.sub(&d).unwrap()
53}
54
55/// Same as `gradient_descent`, only without the logistic flag parameter. This function invokes `gradient_descent` with the `logistic` flag set to `false`.
56pub fn linear_regression(x: &Tensor<f64>, y: &Tensor<f64>, w: &Tensor<f64>, l: f64) -> Tensor<f64> {
57    gradient_descent(x, y, w, l, false)
58}
59
60/// Same as `gradient_descent`, only without the logistic flag parameter. This function invokes `gradient_descent` with the `logistic` flag set to `true`.
61pub fn logistic_regression(x: &Tensor<f64>, y: &Tensor<f64>, w: &Tensor<f64>, l: f64) -> Tensor<f64> {
62    gradient_descent(x, y, w, l, true)
63}
64
65fn sigmoid(lines: Tensor<f64>) -> Tensor<f64> {
66    let result = Tensor::exp(&-lines);
67    let shape = result.get_shape();
68    let result = result.get_data().iter().map(|t|1.0/(1.0 + t)).collect();
69    Tensor::new(shape, result).unwrap()
70}