use super::partition::Stage;
use crate::source::{Param, ParamSource};
use rlx_runtime::{CompileOptions, CompiledGraph, Device, Session};
use std::collections::HashMap;
#[derive(Clone, Debug)]
pub struct NamedTensor {
pub name: String,
pub shape: Vec<usize>,
pub data: Vec<f32>,
}
impl NamedTensor {
pub fn new(name: impl Into<String>, shape: Vec<usize>, data: Vec<f32>) -> Self {
Self {
name: name.into(),
shape,
data,
}
}
}
pub struct StageRunner {
pub stage: Stage,
compiled: CompiledGraph,
}
impl StageRunner {
pub fn compile(
stage: Stage,
source: &mut dyn ParamSource,
device: Device,
opts: &CompileOptions,
) -> Self {
let mut compiled = Session::new(device).compile_with(stage.graph.clone(), opts);
for p in &stage.params {
match source.get(p) {
Some(Param::F32(d)) => compiled.set_param(p, &d),
Some(Param::Typed(bytes, dtype)) => compiled.set_param_typed(p, &bytes, dtype),
None => {}
}
}
Self { stage, compiled }
}
pub fn input_names(&self) -> &[String] {
&self.stage.inputs
}
pub fn run(&mut self, pool: &HashMap<String, NamedTensor>) -> Vec<NamedTensor> {
let feed: Vec<(&str, &[f32])> = self
.stage
.inputs
.iter()
.map(|n| {
let t = pool.get(n).unwrap_or_else(|| {
panic!("stage {} missing input tensor `{n}`", self.stage.index)
});
(n.as_str(), t.data.as_slice())
})
.collect();
let outs = self.compiled.run(&feed);
self.stage
.outputs
.iter()
.cloned()
.zip(self.stage.output_shapes.iter().cloned())
.zip(outs)
.map(|((name, shape), data)| NamedTensor { name, shape, data })
.collect()
}
}
pub fn run_pipeline_local(
stages: Vec<Stage>,
source: &mut dyn ParamSource,
inputs: Vec<NamedTensor>,
device: Device,
opts: &CompileOptions,
) -> Vec<NamedTensor> {
let mut pool: HashMap<String, NamedTensor> =
inputs.into_iter().map(|t| (t.name.clone(), t)).collect();
let mut last = Vec::new();
for stage in stages {
let mut runner = StageRunner::compile(stage, source, device, opts);
let outs = runner.run(&pool);
for t in &outs {
pool.insert(t.name.clone(), t.clone());
}
last = outs;
}
last
}