Skip to main content

Sgd

Struct Sgd 

Source
pub struct Sgd {
    pub learning_rate: LearningRate,
    pub momentum: f64,
    pub weight_decay: f64,
    pub dampening: f64,
    pub nesterov: bool,
    /* private fields */
}
Expand description

Stochastic gradient descent with optional momentum, dampening, Nesterov momentum and weight decay, as MLX’s optimizers.SGD.

Fields§

§learning_rate: LearningRate

The learning rate.

§momentum: f64

The momentum strength (0 disables momentum).

§weight_decay: f64

L2 weight decay added to the gradient.

§dampening: f64

Dampening for momentum.

§nesterov: bool

Nesterov momentum.

Implementations§

Source§

impl Sgd

Source

pub fn new(learning_rate: impl Into<LearningRate>) -> Self

Plain SGD.

Examples found in repository?
examples/mnist.rs (line 130)
101fn main() -> Result<()> {
102    let args: Vec<String> = std::env::args().skip(1).collect();
103    let dir = args
104        .iter()
105        .find(|a| !a.starts_with("--"))
106        .cloned()
107        .unwrap_or_else(|| "data/mnist".into());
108    let epochs: usize = args
109        .iter()
110        .position(|a| a == "--epochs")
111        .and_then(|i| args.get(i + 1))
112        .map_or(10, |v| v.parse().expect("--epochs takes a number"));
113    let asynchronous = args.iter().any(|a| a == "--async");
114    let compiled = args.iter().any(|a| a == "--compile");
115    if args.iter().any(|a| a == "--cpu") {
116        set_default_stream(Stream::default_for(Device::cpu()));
117    }
118    let (train_x, train_y, n) = load(&dir, "train").inspect_err(|_| {
119        eprintln!("cannot read MNIST from {dir}: run `just mnist` (it downloads the data)");
120    })?;
121    let (test_x, test_y, n_test) = load(&dir, "t10k")?;
122    let pixels = train_x.len() / n;
123    let test_x = Array::from_slice(&test_x, &[n_test, pixels])?;
124    let test_y = Array::from_slice(&test_y, &[n_test])?;
125
126    let (batch, lr) = (256, 0.1);
127    random::seed(0);
128    let mut model = Mlp::new(&[pixels, 32, 32, 10])?;
129    nuvec::eval(&arrays(&model))?;
130    let mut optimizer = Sgd::new(lr);
131    // The step as a function of the parameters and the batch, returning new parameters.
132    let k = arrays(&model).len();
133    let template = model.clone();
134    let step = nuvec::compile(move |xs: &[Array]| {
135        let mut m = template.clone();
136        m.update_trainable(&xs[..k])?;
137        let (x, y) = (&xs[k], &xs[k + 1]);
138        let (_, grads) = value_and_grad(&m, |m: &Mlp| {
139            cross_entropy(&m.forward(x)?, y, Reduction::Mean)
140        })?;
141        Sgd::new(lr).update(&mut m, &grads)?;
142        Ok(arrays(&m))
143    });
144    let mut shuffle = Shuffle(0);
145    let device = nuvec::default_stream().device;
146    let mut times = Vec::new();
147    let mut accuracy = 0.0;
148    for epoch in 0..epochs {
149        let tic = Instant::now();
150        let perm = shuffle.permutation(n);
151        for ids in perm.chunks(batch) {
152            let mut xb = Vec::with_capacity(ids.len() * pixels);
153            for &i in ids {
154                xb.extend_from_slice(&train_x[i * pixels..(i + 1) * pixels]);
155            }
156            let yb: Vec<u32> = ids.iter().map(|&i| train_y[i]).collect();
157            let x = Array::from_slice(&xb, &[ids.len(), pixels])?;
158            let y = Array::from_slice(&yb, &[ids.len()])?;
159            if compiled {
160                let mut args = arrays(&model);
161                args.extend([x, y]);
162                model.update_trainable(&step(&args)?)?;
163            } else {
164                let (_, grads) = value_and_grad(&model, |m: &Mlp| {
165                    cross_entropy(&m.forward(&x)?, &y, Reduction::Mean)
166                })?;
167                optimizer.update(&mut model, &grads)?;
168            }
169            if asynchronous {
170                nuvec::async_eval(&arrays(&model))?;
171            } else {
172                nuvec::eval(&arrays(&model))?;
173            }
174        }
175        let predictions = argmax(&model.forward(&test_x)?, Some(1), false)?;
176        let hits = astype(&equal(&predictions, &test_y)?, DType::F32)?;
177        accuracy = mean(&hits, &[], false)?.item::<f32>()?;
178        let seconds = tic.elapsed().as_secs_f64();
179        times.push(seconds);
180        println!("Epoch {epoch}: Test accuracy {accuracy:.3}, Time {seconds:.3} (s)");
181    }
182    let mut steady: Vec<f64> = times.iter().skip(1).copied().collect();
183    steady.sort_by(f64::total_cmp);
184    let median = steady.get(steady.len() / 2).copied().unwrap_or(times[0]);
185    println!(
186        "RESULT device={device} async={asynchronous} compiled={compiled} accuracy={accuracy:.4} epoch_seconds={median:.4}"
187    );
188    Ok(())
189}
Source

pub fn momentum(self, momentum: f64) -> Self

Sets the momentum.

Source

pub fn weight_decay(self, weight_decay: f64) -> Self

Sets the weight decay.

Source

pub fn nesterov(self, nesterov: bool) -> Self

Enables Nesterov momentum.

Trait Implementations§

Source§

impl Clone for Sgd

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Sgd

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Optimizer for Sgd

Source§

fn apply( &mut self, parameters: &[Array], gradients: &[Array], ) -> Result<Vec<Array>>

One step: the updated parameters.
Source§

fn update<M: Module>( &mut self, model: &mut M, gradients: &[Array], ) -> Result<()>

Applies one step to model: gradients are in the order of Module::trainable_parameters.

Auto Trait Implementations§

§

impl !RefUnwindSafe for Sgd

§

impl !UnwindSafe for Sgd

§

impl Freeze for Sgd

§

impl Send for Sgd

§

impl Sync for Sgd

§

impl Unpin for Sgd

§

impl UnsafeUnpin for Sgd

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.