| 13 | namespace mx = mlx::core; |
| 14 | |
| 15 | int main() { |
| 16 | int num_features = 100; |
| 17 | int num_examples = 1'000; |
| 18 | int num_iters = 10'000; |
| 19 | float learning_rate = 0.01; |
| 20 | |
| 21 | // True parameters |
| 22 | auto w_star = mx::random::normal({num_features}); |
| 23 | |
| 24 | // The input examples (design matrix) |
| 25 | auto X = mx::random::normal({num_examples, num_features}); |
| 26 | |
| 27 | // Noisy labels |
| 28 | auto eps = 1e-2 * mx::random::normal({num_examples}); |
| 29 | auto y = mx::matmul(X, w_star) + eps; |
| 30 | |
| 31 | // Initialize random parameters |
| 32 | mx::array w = 1e-2 * mx::random::normal({num_features}); |
| 33 | |
| 34 | auto loss_fn = [&](mx::array w) { |
| 35 | auto yhat = mx::matmul(X, w); |
| 36 | return (0.5f / num_examples) * mx::sum(mx::square(yhat - y)); |
| 37 | }; |
| 38 | |
| 39 | auto grad_fn = mx::grad(loss_fn); |
| 40 | |
| 41 | auto tic = timer::time(); |
| 42 | for (int it = 0; it < num_iters; ++it) { |
| 43 | auto grads = grad_fn(w); |
| 44 | w = w - learning_rate * grads; |
| 45 | mx::eval(w); |
| 46 | } |
| 47 | auto toc = timer::time(); |
| 48 | |
| 49 | auto loss = loss_fn(w); |
| 50 | auto error_norm = std::sqrt(mx::sum(mx::square(w - w_star)).item<float>()); |
| 51 | auto throughput = num_iters / timer::seconds(toc - tic); |
| 52 | std::cout << "Loss " << loss << ", |w - w*| = " << error_norm |
| 53 | << ", Throughput " << throughput << " (it/s)." << std::endl; |
| 54 | } |