#[derive(Debug, Clone)]
pub struct MultimodalInput {
pub patch_embeddings: Vec<f32>,
pub raw_patches: usize,
pub visual_tokens: usize,
pub d_model: usize,
pub text_tokens: Vec<u32>,
}
impl MultimodalInput {
pub fn validate(&self) -> Result<(), crate::vision::VisionError> {
if self.d_model == 0 {
return Err(crate::vision::VisionError::InvalidConfig(
"d_model must be > 0".into(),
));
}
let expected_len = self.visual_tokens * self.d_model;
if self.patch_embeddings.len() != expected_len {
return Err(crate::vision::VisionError::ShapeMismatch {
expected: expected_len,
actual: self.patch_embeddings.len(),
context: "patch_embeddings length must equal visual_tokens * d_model".into(),
});
}
if self.visual_tokens == 0 {
return Err(crate::vision::VisionError::InvalidConfig(
"visual_tokens must be > 0".into(),
));
}
Ok(())
}
pub fn total_sequence_len(&self) -> usize {
self.visual_tokens + self.text_tokens.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn multimodal_input_valid() {
let input = MultimodalInput {
patch_embeddings: vec![0.0f32; 196 * 2048],
raw_patches: 784,
visual_tokens: 196,
d_model: 2048,
text_tokens: vec![1, 2, 3],
};
input.validate().expect("valid input");
assert_eq!(input.total_sequence_len(), 199); }
#[test]
fn multimodal_input_wrong_embed_len() {
let input = MultimodalInput {
patch_embeddings: vec![0.0f32; 100], raw_patches: 784,
visual_tokens: 196,
d_model: 2048,
text_tokens: vec![],
};
assert!(input.validate().is_err());
}
#[test]
fn multimodal_input_zero_d_model() {
let input = MultimodalInput {
patch_embeddings: vec![],
raw_patches: 784,
visual_tokens: 196,
d_model: 0,
text_tokens: vec![],
};
assert!(input.validate().is_err());
}
#[test]
fn multimodal_input_zero_visual_tokens() {
let input = MultimodalInput {
patch_embeddings: vec![],
raw_patches: 0,
visual_tokens: 0,
d_model: 2048,
text_tokens: vec![1, 2],
};
assert!(input.validate().is_err());
}
#[test]
fn total_sequence_len() {
let input = MultimodalInput {
patch_embeddings: vec![0.0f32; 196 * 512],
raw_patches: 784,
visual_tokens: 196,
d_model: 512,
text_tokens: vec![10, 20, 30, 40],
};
assert_eq!(input.total_sequence_len(), 200);
}
}