#![doc = include_str!("../README.md")]
pub use yscv_autograd as autograd;
pub use yscv_cli as cli;
pub use yscv_detect as detect;
pub use yscv_eval as eval;
pub use yscv_imgproc as imgproc;
pub use yscv_kernels as kernels;
pub use yscv_model as model;
pub use yscv_onnx as onnx;
pub use yscv_optim as optim;
pub use yscv_recognize as recognize;
pub use yscv_tensor as tensor;
pub use yscv_track as track;
pub use yscv_video as video;
pub mod prelude {
pub use yscv_tensor::{DType, Device, Tensor, TensorError};
pub use yscv_autograd::{Graph, NodeId};
pub use yscv_model::{
Compose, DataLoader, DataLoaderConfig, InferencePipeline, ModelLayer, SequentialModel,
Trainer, TrainerConfig, Transform,
};
pub use yscv_model::{
bce_loss, cross_entropy_loss, dice_loss, focal_loss, mse_loss, smooth_l1_loss,
};
pub use yscv_model::{BestModelCheckpoint, EarlyStopping};
pub use yscv_model::{Normalize, PermuteDims, ScaleValues};
pub use yscv_model::{LossKind, OptimizerKind, SupervisedDataset};
pub use yscv_optim::{Adam, LearningRate, Sgd};
pub use crate::imgproc;
pub use yscv_imgproc::{
ImageF32, ImageU8, ImgProcError, imread, imread_gray, imwrite, rgb_to_grayscale,
};
pub use yscv_onnx::{
OnnxError, OnnxModel, load_onnx_model, load_onnx_model_from_file, run_onnx_model,
};
pub use yscv_detect::BoundingBox;
pub use yscv_eval::{accuracy, confusion_matrix, f1_score};
}
#[cfg(test)]
mod tests {
use super::prelude::*;
#[test]
fn smoke_create_tensor() {
let t = Tensor::from_vec(vec![2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
assert_eq!(t.shape(), &[2, 3]);
}
#[test]
fn smoke_from_slice() {
let t = Tensor::from_slice(&[1.0, 2.0, 3.0]);
assert_eq!(t.shape(), &[3]);
assert_eq!(t.data(), &[1.0, 2.0, 3.0]);
}
#[test]
fn smoke_full() {
let t = Tensor::full(vec![2, 3], 7.0).unwrap();
assert_eq!(t.shape(), &[2, 3]);
assert!(t.data().iter().all(|&v| v == 7.0));
}
#[test]
fn smoke_display() {
let t = Tensor::from_slice(&[1.0, 2.0, 3.0]);
let s = format!("{t}");
assert!(s.contains("Tensor("));
assert!(s.contains("[3]"));
}
#[test]
fn smoke_operator_add() {
let a = Tensor::from_slice(&[1.0, 2.0]);
let b = Tensor::from_slice(&[3.0, 4.0]);
let c = &a + &b;
assert_eq!(c.data(), &[4.0, 6.0]);
}
#[test]
fn smoke_operator_sub() {
let a = Tensor::from_slice(&[5.0, 3.0]);
let b = Tensor::from_slice(&[1.0, 1.0]);
let c = &a - &b;
assert_eq!(c.data(), &[4.0, 2.0]);
}
#[test]
fn smoke_operator_mul_scalar() {
let a = Tensor::from_slice(&[2.0, 3.0]);
let b = &a * 10.0;
assert_eq!(b.data(), &[20.0, 30.0]);
}
#[test]
fn smoke_operator_neg() {
let a = Tensor::from_slice(&[1.0, -2.0]);
let b = -&a;
assert_eq!(b.data(), &[-1.0, 2.0]);
}
#[test]
fn smoke_prelude_types_accessible() {
let _: Option<DType> = None;
let _: Option<Device> = None;
let _: Option<ImgProcError> = None;
let _: Option<OnnxError> = None;
let _: Option<OnnxModel> = None;
}
#[test]
fn smoke_build_sequential_model() {
let graph = Graph::new();
let model = SequentialModel::new(&graph);
assert_eq!(model.layers().len(), 0);
}
#[test]
fn smoke_inference_pipeline() {
let graph = Graph::new();
let model = SequentialModel::new(&graph);
let pipeline = InferencePipeline::new(model);
let input = Tensor::from_vec(vec![1, 4], vec![1.0, 2.0, 3.0, 4.0]).unwrap();
let output = pipeline.run(&input).unwrap();
assert_eq!(output.shape(), &[1, 4]);
}
#[test]
fn smoke_prelude_new_imports() {
let mut graph = Graph::new();
let pred_t = Tensor::from_vec(vec![3], vec![0.9, 0.1, 0.0]).unwrap();
let targ_t = Tensor::from_vec(vec![3], vec![1.0, 0.0, 0.0]).unwrap();
let pred_node = graph.constant(pred_t);
let targ_node = graph.constant(targ_t);
let loss_node = mse_loss(&mut graph, pred_node, targ_node).unwrap();
let loss_val = graph.value(loss_node).unwrap().data()[0];
assert!(loss_val >= 0.0);
let preds: Vec<usize> = vec![0, 1, 2, 0];
let labels: Vec<usize> = vec![0, 1, 2, 1];
let acc = accuracy(&preds, &labels).unwrap();
assert!((acc - 0.75).abs() < 1e-5);
let _scale = ScaleValues::new(1.0 / 255.0);
let _norm = Normalize::new(vec![0.5], vec![0.5]);
let _perm = PermuteDims::new(vec![2, 0, 1]);
let _: Option<OptimizerKind> = None;
let _: Option<LossKind> = None;
}
#[test]
fn smoke_compose_transform() {
use yscv_model::{Normalize, ScaleValues};
let compose = Compose::new()
.add(ScaleValues::new(1.0 / 255.0))
.add(Normalize::new(vec![0.5], vec![0.5]));
let input = Tensor::from_vec(vec![2], vec![255.0, 0.0]).unwrap();
let output = compose.apply(&input).unwrap();
assert_eq!(output.shape(), &[2]);
let data = output.data();
assert!((data[0] - 1.0).abs() < 1e-5);
assert!((data[1] - (-1.0)).abs() < 1e-5);
}
}