mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-09-18 16:36:43 +00:00
Start ML Coordinator.
ML Coordinator needs to be able to load and unload models, which means verifying and creating any necessary transfer buffers and other data structures. First draft just keeps track of model references. ML Coordinator needs to be able to execute models. Actual execution is abstracted away from ExecutiveInterface. Deletes fake_executive and moves to this file in the test section, as this is currently the only user. Change-Id: Ib2de5bc5761ccffe244e0bc0a02c6d2805cc00c6 GitOrigin-RevId: dc4de0085b36094ec6ac10c3a7f4fe0c8dff1627
This commit is contained in:
committed by
Sam Leffler
parent
1c107b73e5
commit
90e9cb95f9
@@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
"fake-executive",
|
||||
"ml-common"
|
||||
"ml-common",
|
||||
"ml-coordinator",
|
||||
]
|
||||
|
@@ -1,44 +0,0 @@
|
||||
use ml_common as ml;
|
||||
use ml_common::ExecutiveInterface;
|
||||
|
||||
pub struct FakeExecutive {
|
||||
output_memory: [u8; 512],
|
||||
fake_error: Option<ml::ExecutionError>,
|
||||
}
|
||||
|
||||
impl ml::ExecutiveInterface for FakeExecutive {
|
||||
fn run_model(&self, _model: &ml::Model) -> Result<&[u8], ml::ExecutionError> {
|
||||
match self.fake_error {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(&self.output_memory),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_ok() {
|
||||
let exec = FakeExecutive {
|
||||
output_memory: [0xAD; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
|
||||
let res = exec.run_model(&model);
|
||||
assert!(res.is_ok());
|
||||
assert_eq!(res.unwrap()[0], 0xAD)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn return_err() {
|
||||
let exec = FakeExecutive {
|
||||
output_memory: [0; 512],
|
||||
fake_error: Some(ml::ExecutionError::CoreReset),
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
|
||||
assert!(exec.run_model(&model).is_err());
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
// TODO(jesionowski): What are the actual errors we may encounter?
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ExecutionError {
|
||||
ModelNotLoaded,
|
||||
InvalidInstruction,
|
||||
InvalidFetch,
|
||||
CoreReset
|
||||
CoreReset,
|
||||
}
|
||||
|
||||
// The abstraction layer over the "hardware" of running an execution.
|
||||
@@ -12,6 +13,15 @@ pub trait ExecutiveInterface {
|
||||
fn run_model(&self, model: &Model) -> Result<&[u8], ExecutionError>;
|
||||
}
|
||||
|
||||
// Options for execution that may be set by the application.
|
||||
pub struct ModelOptions {
|
||||
pub rate: u32,
|
||||
}
|
||||
|
||||
// Immutable model attributes.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Model {
|
||||
pub output_activations_len: usize,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MAX_MODELS: u32 = 10;
|
||||
|
@@ -1,8 +1,9 @@
|
||||
[package]
|
||||
name = "fake-executive"
|
||||
name = "ml-coordinator"
|
||||
version = "0.1.0"
|
||||
authors = ["Adam Jesionowski <jesionowski@google.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
ml-common = { path = "../ml-common" }
|
||||
ml-common = { path = "../ml-common" }
|
||||
arrayvec = "0.5.2"
|
161
apps/system/components/MlCoordinator/ml-coordinator/src/lib.rs
Normal file
161
apps/system/components/MlCoordinator/ml-coordinator/src/lib.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
#![no_std]
|
||||
use arrayvec::ArrayVec;
|
||||
use ml_common as ml;
|
||||
use ml_common::ExecutiveInterface;
|
||||
|
||||
pub struct MlCoordinator<'a> {
|
||||
executive: &'a dyn ExecutiveInterface,
|
||||
// Application owns the model struct.
|
||||
// ML Coordinator owns a reference to the model.
|
||||
models: ArrayVec<[&'a ml::Model; 10]>,
|
||||
}
|
||||
|
||||
impl<'a> MlCoordinator<'a> {
|
||||
// Create a new ML Coordinator instance.
|
||||
fn new(executive: &'a dyn ExecutiveInterface) -> MlCoordinator<'a> {
|
||||
let mut models = ArrayVec::<[&ml::Model; 10]>::new();
|
||||
|
||||
MlCoordinator {
|
||||
executive: executive,
|
||||
models: models,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the index of the model if it has already been loaded.
|
||||
fn has_model(&self, model: &'a ml::Model) -> Option<usize> {
|
||||
self.models.iter().position(|&x| model == x)
|
||||
}
|
||||
|
||||
// Load the passed model. Returns true if the model was loaded
|
||||
// successfully, and false if there is no room or the model was already loaded.
|
||||
// This function will eventually perform validation of the model, create transfer buffers, etc.
|
||||
#[must_use]
|
||||
fn load(&mut self, model: &'a ml::Model) -> bool {
|
||||
if self.models.is_full() || self.has_model(model).is_some() {
|
||||
return false;
|
||||
}
|
||||
self.models.push(model);
|
||||
true
|
||||
}
|
||||
|
||||
// Unload the passed model. Returns true if the model was unloaded successfully,
|
||||
// false if the model was not loaded in the first place.
|
||||
fn unload(&mut self, model: &'a ml::Model) -> bool {
|
||||
let res = self.has_model(model);
|
||||
if let Some(idx) = res {
|
||||
self.models.remove(idx);
|
||||
}
|
||||
res.is_some()
|
||||
}
|
||||
|
||||
// Execute the passed model.
|
||||
fn execute(&self, model: &'a ml::Model) -> Result<&'a [u8], ml::ExecutionError> {
|
||||
self.has_model(model).ok_or(ml::ExecutionError::ModelNotLoaded)?;
|
||||
self.executive.run_model(model)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
struct FakeExecutive {
|
||||
output_memory: [u8; 512],
|
||||
fake_error: Option<ml::ExecutionError>,
|
||||
}
|
||||
|
||||
impl ExecutiveInterface for FakeExecutive {
|
||||
fn run_model(&self, _model: &ml::Model) -> Result<&[u8], ml::ExecutionError> {
|
||||
match self.fake_error {
|
||||
Some(err) => Err(err),
|
||||
None => Ok(&self.output_memory),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_unload() {
|
||||
let exec = tests::FakeExecutive {
|
||||
output_memory: [0x00; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
let mut ml_coord = MlCoordinator::new(&exec);
|
||||
assert!(ml_coord.load(&model));
|
||||
assert!(ml_coord.unload(&model));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unload_noload() {
|
||||
let exec = tests::FakeExecutive {
|
||||
output_memory: [0x00; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
let mut ml_coord = MlCoordinator::new(&exec);
|
||||
assert_eq!(ml_coord.unload(&model), false);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_unload_twice() {
|
||||
let exec = tests::FakeExecutive {
|
||||
output_memory: [0x00; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
let mut ml_coord = MlCoordinator::new(&exec);
|
||||
assert!(ml_coord.load(&model));
|
||||
assert!(ml_coord.unload(&model));
|
||||
assert_eq!(ml_coord.unload(&model), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_twice() {
|
||||
let exec = tests::FakeExecutive {
|
||||
output_memory: [0x00; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
let mut ml_coord = MlCoordinator::new(&exec);
|
||||
assert!(ml_coord.load(&model));
|
||||
assert_eq!(ml_coord.load(&model), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute_noload() {
|
||||
let exec = tests::FakeExecutive {
|
||||
output_memory: [0x00; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
let mut ml_coord = MlCoordinator::new(&exec);
|
||||
assert!(ml_coord.execute(&model).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute() {
|
||||
let exec = tests::FakeExecutive {
|
||||
output_memory: [0xAD; 512],
|
||||
fake_error: None,
|
||||
};
|
||||
let model = ml::Model {
|
||||
output_activations_len: 512,
|
||||
};
|
||||
let mut ml_coord = MlCoordinator::new(&exec);
|
||||
assert!(ml_coord.load(&model));
|
||||
|
||||
let res = ml_coord.execute(&model);
|
||||
assert_eq!(res.unwrap()[0], 0xAD)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user