Add docs, delete old code, truncate scalars where possible (#21)
This commit is contained in:
@@ -1,35 +1,37 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
mod with_tensor;
|
||||
|
||||
use little_learner::auto_diff::{Differentiable, RankedDifferentiable, RankedDifferentiableTagged};
|
||||
|
||||
use little_learner::gradient_descent::gradient_descent;
|
||||
use little_learner::hyper::VelocityGradientDescentHyper;
|
||||
use little_learner::loss::{predict_plane, velocity_predictor};
|
||||
use little_learner::hyper;
|
||||
use little_learner::loss::predict_plane;
|
||||
use little_learner::not_nan::{to_not_nan_1, to_not_nan_2};
|
||||
use little_learner::predictor;
|
||||
use little_learner::scalar::Scalar;
|
||||
use little_learner::traits::Zero;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
fn main() {
|
||||
let plane_xs = [
|
||||
[1.0, 2.05],
|
||||
[1.0, 3.0],
|
||||
[2.0, 2.0],
|
||||
[2.0, 3.91],
|
||||
[3.0, 6.13],
|
||||
[4.0, 8.09],
|
||||
];
|
||||
let plane_ys = [13.99, 15.99, 18.0, 22.4, 30.2, 37.94];
|
||||
const PLANE_XS: [[f64; 2]; 6] = [
|
||||
[1.0, 2.05],
|
||||
[1.0, 3.0],
|
||||
[2.0, 2.0],
|
||||
[2.0, 3.91],
|
||||
[3.0, 6.13],
|
||||
[4.0, 8.09],
|
||||
];
|
||||
const PLANE_YS: [f64; 6] = [13.99, 15.99, 18.0, 22.4, 30.2, 37.94];
|
||||
|
||||
let hyper = VelocityGradientDescentHyper::naked(NotNan::new(0.001).expect("not nan"), 1000)
|
||||
.with_mu(NotNan::new(0.9).expect("not nan"));
|
||||
fn main() {
|
||||
let beta = NotNan::new(0.9).expect("not nan");
|
||||
let stabilizer = NotNan::new(0.000_000_01).expect("not nan");
|
||||
let hyper = hyper::RmsGradientDescent::default(NotNan::new(0.001).expect("not nan"), 3000)
|
||||
.with_stabilizer(stabilizer)
|
||||
.with_beta(beta);
|
||||
|
||||
let iterated = {
|
||||
let xs = to_not_nan_2(plane_xs);
|
||||
let ys = to_not_nan_1(plane_ys);
|
||||
let xs = to_not_nan_2(PLANE_XS);
|
||||
let ys = to_not_nan_1(PLANE_YS);
|
||||
let zero_params = [
|
||||
RankedDifferentiable::of_slice(&[NotNan::<f64>::zero(), NotNan::<f64>::zero()])
|
||||
.to_unranked(),
|
||||
@@ -42,8 +44,8 @@ fn main() {
|
||||
RankedDifferentiableTagged::of_slice_2::<_, 2>,
|
||||
&ys,
|
||||
zero_params,
|
||||
velocity_predictor(predict_plane),
|
||||
VelocityGradientDescentHyper::to_immutable,
|
||||
predictor::rms(predict_plane),
|
||||
hyper::RmsGradientDescent::to_immutable,
|
||||
)
|
||||
};
|
||||
|
||||
@@ -52,11 +54,14 @@ fn main() {
|
||||
let theta0 = theta0.attach_rank::<1>().expect("rank 1 tensor");
|
||||
let theta1 = theta1.attach_rank::<0>().expect("rank 0 tensor");
|
||||
|
||||
assert_eq!(theta0.collect(), [3.979645447136021, 1.976454920954754]);
|
||||
assert_eq!(
|
||||
theta1.to_scalar().real_part().into_inner(),
|
||||
6.169579045974949
|
||||
);
|
||||
let fitted_theta0 = theta0
|
||||
.collect()
|
||||
.iter()
|
||||
.map(|x| x.into_inner())
|
||||
.collect::<Vec<_>>();
|
||||
let fitted_theta1 = theta1.to_scalar().real_part().into_inner();
|
||||
assert_eq!(fitted_theta0, [3.985_350_099_342_649, 1.9745945728216352]);
|
||||
assert_eq!(fitted_theta1, 6.164_222_983_181_168);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@@ -1,136 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::iter::Sum;
|
||||
use std::ops::{Mul, Sub};
|
||||
|
||||
use little_learner::tensor;
|
||||
use little_learner::tensor::{extension2, Extensible2};
|
||||
use little_learner::traits::One;
|
||||
|
||||
type Point<A, const N: usize> = [A; N];
|
||||
|
||||
type Parameters<A, const N: usize, const M: usize> = [Point<A, N>; M];
|
||||
|
||||
fn dot_points<A: Mul, const N: usize>(x: &Point<A, N>, y: &Point<A, N>) -> A
|
||||
where
|
||||
A: Sum<<A as Mul>::Output> + Copy + Default + Mul<Output = A> + Extensible2<A>,
|
||||
{
|
||||
extension2(x, y, |&x, &y| x * y).into_iter().sum()
|
||||
}
|
||||
|
||||
fn dot<A, const N: usize, const M: usize>(x: &Point<A, N>, y: &Parameters<A, N, M>) -> Point<A, M>
|
||||
where
|
||||
A: Mul<Output = A> + Sum<<A as Mul>::Output> + Copy + Default + Extensible2<A>,
|
||||
{
|
||||
let mut result = [Default::default(); M];
|
||||
for (i, coord) in y.iter().map(|y| dot_points(x, y)).enumerate() {
|
||||
result[i] = coord;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn sum<A, const N: usize>(x: &tensor!(A, N)) -> A
|
||||
where
|
||||
A: Sum<A> + Copy,
|
||||
{
|
||||
A::sum(x.iter().cloned())
|
||||
}
|
||||
|
||||
fn squared<A, const N: usize>(x: &tensor!(A, N)) -> tensor!(A, N)
|
||||
where
|
||||
A: Mul<Output = A> + Extensible2<A> + Copy + Default,
|
||||
{
|
||||
extension2(x, x, |&a, &b| (a * b))
|
||||
}
|
||||
|
||||
fn l2_norm<A, const N: usize>(prediction: &tensor!(A, N), data: &tensor!(A, N)) -> A
|
||||
where
|
||||
A: Sum<A> + Mul<Output = A> + Extensible2<A> + Copy + Default + Sub<Output = A>,
|
||||
{
|
||||
let diff = extension2(prediction, data, |&x, &y| x - y);
|
||||
sum(&squared(&diff))
|
||||
}
|
||||
|
||||
pub fn l2_loss<A, F, Params, const N: usize>(
|
||||
target: F,
|
||||
data_xs: &tensor!(A, N),
|
||||
data_ys: &tensor!(A, N),
|
||||
params: &Params,
|
||||
) -> A
|
||||
where
|
||||
F: Fn(&tensor!(A, N), &Params) -> tensor!(A, N),
|
||||
A: Sum<A> + Mul<Output = A> + Extensible2<A> + Copy + Default + Sub<Output = A>,
|
||||
{
|
||||
let pred_ys = target(data_xs, params);
|
||||
l2_norm(&pred_ys, data_ys)
|
||||
}
|
||||
|
||||
pub fn predict_line<A, const N: usize>(xs: &tensor!(A, N), theta: &tensor!(A, 2)) -> tensor!(A, N)
|
||||
where
|
||||
A: Mul<Output = A> + Sum<<A as Mul>::Output> + Copy + Default + Extensible2<A> + One,
|
||||
{
|
||||
let mut result: tensor!(A, N) = [Default::default(); N];
|
||||
for (i, &x) in xs.iter().enumerate() {
|
||||
result[i] = dot(&[x, One::one()], &[*theta])[0];
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use little_learner::tensor::extension1;
|
||||
|
||||
#[test]
|
||||
fn test_extension() {
|
||||
let x: tensor!(u8, 1) = [2];
|
||||
assert_eq!(extension1(&x, &7, |x, y| x + y), [9]);
|
||||
let y: tensor!(u8, 1) = [7];
|
||||
assert_eq!(extension2(&x, &y, |x, y| x + y), [9]);
|
||||
|
||||
let x: tensor!(u8, 3) = [5, 6, 7];
|
||||
assert_eq!(extension1(&x, &2, |x, y| x + y), [7, 8, 9]);
|
||||
let y: tensor!(u8, 3) = [2, 0, 1];
|
||||
assert_eq!(extension2(&x, &y, |x, y| x + y), [7, 6, 8]);
|
||||
|
||||
let x: tensor!(u8, 2, 3) = [[4, 6, 7], [2, 0, 1]];
|
||||
assert_eq!(extension1(&x, &2, |x, y| x + y), [[6, 8, 9], [4, 2, 3]]);
|
||||
let y: tensor!(u8, 2, 3) = [[1, 2, 2], [6, 3, 1]];
|
||||
assert_eq!(extension2(&x, &y, |x, y| x + y), [[5, 8, 9], [8, 3, 2]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_l2_norm() {
|
||||
assert_eq!(
|
||||
l2_norm(&[4.0, -3.0, 0.0, -4.0, 3.0], &[0.0, 0.0, 0.0, 0.0, 0.0]),
|
||||
50.0
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_l2_loss() {
|
||||
let loss = l2_loss(
|
||||
predict_line,
|
||||
&[2.0, 1.0, 4.0, 3.0],
|
||||
&[1.8, 1.2, 4.2, 3.3],
|
||||
&[0.0, 0.0],
|
||||
);
|
||||
assert_eq!(loss, 33.21);
|
||||
|
||||
let loss = l2_loss(
|
||||
predict_line,
|
||||
&[2.0, 1.0, 4.0, 3.0],
|
||||
&[1.8, 1.2, 4.2, 3.3],
|
||||
&[0.0099, 0.0],
|
||||
);
|
||||
assert_eq!((100.0 * loss).round() / 100.0, 32.59);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l2_loss_non_autodiff_example() {
|
||||
let xs = [2.0, 1.0, 4.0, 3.0];
|
||||
let ys = [1.8, 1.2, 4.2, 3.3];
|
||||
let loss = l2_loss(predict_line, &xs, &ys, &[0.0099, 0.0]);
|
||||
assert_eq!(loss, 32.5892403);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user