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: LearningRateThe learning rate.
momentum: f64The momentum strength (0 disables momentum).
weight_decay: f64L2 weight decay added to the gradient.
dampening: f64Dampening for momentum.
nesterov: boolNesterov momentum.
Implementations§
Source§impl Sgd
impl Sgd
Sourcepub fn new(learning_rate: impl Into<LearningRate>) -> Self
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}Sourcepub fn weight_decay(self, weight_decay: f64) -> Self
pub fn weight_decay(self, weight_decay: f64) -> Self
Sets the weight decay.
Trait Implementations§
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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