#[cfg(test)]
mod tests {
use crate::deit::config::DeiTConfig;
use crate::deit::model::{DeiTModel, DeiTPatchEmbedding};
use crate::deit::tasks::DeiTForImageClassification;
use scirs2_core::ndarray::Array4;
use trustformers_core::traits::Config;
fn mini_config() -> DeiTConfig {
DeiTConfig {
image_size: 32,
patch_size: 8,
num_channels: 3,
hidden_size: 64,
num_hidden_layers: 2,
num_attention_heads: 4,
intermediate_size: 256,
hidden_dropout_prob: 0.0,
attention_probs_dropout_prob: 0.0,
num_labels: 10,
qkv_bias: true,
layer_norm_eps: 1e-6,
use_distillation_token: true,
model_type: "deit".to_string(),
}
}
#[test]
fn test_deit_config_tiny() {
let config = DeiTConfig::deit_tiny_patch16_224();
assert_eq!(config.image_size, 224);
assert_eq!(config.patch_size, 16);
assert_eq!(config.hidden_size, 192);
assert_eq!(config.num_attention_heads, 3);
assert_eq!(config.num_hidden_layers, 12);
assert_eq!(config.intermediate_size, 768);
assert!(config.use_distillation_token);
assert_eq!(config.num_patches(), 196); assert_eq!(config.seq_length(), 198); config.validate().expect("tiny config should be valid");
}
#[test]
fn test_deit_config_base() {
let config = DeiTConfig::deit_base_patch16_224();
assert_eq!(config.hidden_size, 768);
assert_eq!(config.num_attention_heads, 12);
assert_eq!(config.intermediate_size, 3072);
assert_eq!(config.num_patches_per_side(), 14);
assert_eq!(config.num_patches(), 196);
assert_eq!(config.seq_length(), 198);
config.validate().expect("base config should be valid");
}
#[test]
fn test_deit_config_base_384() {
let config = DeiTConfig::deit_base_patch16_384();
assert_eq!(config.image_size, 384);
assert_eq!(config.num_patches(), 576); assert_eq!(config.seq_length(), 578); config.validate().expect("base-384 config should be valid");
}
#[test]
fn test_deit_config_small() {
let config = DeiTConfig::deit_small_patch16_224();
assert_eq!(config.hidden_size, 384);
assert_eq!(config.num_attention_heads, 6);
config.validate().expect("small config should be valid");
}
#[test]
fn test_deit_config_without_distillation_token() {
let config = DeiTConfig {
use_distillation_token: false,
..DeiTConfig::deit_tiny_patch16_224()
};
assert_eq!(config.seq_length(), 197); config.validate().expect("config without distillation should be valid");
}
#[test]
fn test_deit_config_invalid_hidden_size() {
let config = DeiTConfig {
hidden_size: 100, num_attention_heads: 3,
..DeiTConfig::deit_tiny_patch16_224()
};
assert!(config.validate().is_err());
}
#[test]
fn test_deit_config_invalid_image_size() {
let config = DeiTConfig {
image_size: 225, ..DeiTConfig::deit_tiny_patch16_224()
};
assert!(config.validate().is_err());
}
#[test]
fn test_deit_patch_embedding() {
let config = mini_config();
let patch_emb = DeiTPatchEmbedding::new(&config);
let image = Array4::<f32>::zeros((1, 32, 32, 3));
let result = patch_emb.forward(&image).expect("patch embedding should succeed");
assert_eq!(result.shape(), &[1, 16, 64]);
}
#[test]
fn test_deit_patch_embedding_batch() {
let config = mini_config();
let patch_emb = DeiTPatchEmbedding::new(&config);
let image = Array4::<f32>::zeros((3, 32, 32, 3));
let result = patch_emb.forward(&image).expect("batch patch embedding should succeed");
assert_eq!(result.shape(), &[3, 16, 64]);
}
#[test]
fn test_deit_patch_embedding_wrong_channels() {
let config = mini_config();
let patch_emb = DeiTPatchEmbedding::new(&config);
let image = Array4::<f32>::zeros((1, 32, 32, 1)); assert!(patch_emb.forward(&image).is_err());
}
#[test]
fn test_deit_model_shapes() {
let config = mini_config();
let model = DeiTModel::new(config).expect("model construction should succeed");
let images = Array4::<f32>::zeros((1, 32, 32, 3));
let output = model.forward(&images).expect("forward should succeed");
assert_eq!(output.shape(), &[1, 18, 64]);
}
#[test]
fn test_deit_model_cls_output() {
let config = mini_config();
let model = DeiTModel::new(config).expect("model construction should succeed");
let images = Array4::<f32>::zeros((2, 32, 32, 3));
let cls = model.get_cls_output(&images).expect("cls output should succeed");
assert_eq!(cls.shape(), &[2, 64]);
}
#[test]
fn test_deit_distillation_token() {
let config = mini_config();
let model = DeiTModel::new(config).expect("model construction should succeed");
let images = Array4::<f32>::zeros((2, 32, 32, 3));
let dist = model
.get_distillation_output(&images)
.expect("distillation output should succeed");
assert_eq!(dist.shape(), &[2, 64]);
}
#[test]
fn test_deit_distillation_token_absent() {
let config = DeiTConfig {
use_distillation_token: false,
..mini_config()
};
let model = DeiTModel::new(config).expect("model construction should succeed");
let images = Array4::<f32>::zeros((1, 32, 32, 3));
assert!(model.get_distillation_output(&images).is_err());
}
#[test]
fn test_deit_classification_head() {
let config = mini_config();
let model =
DeiTForImageClassification::new(config).expect("model construction should succeed");
let images = Array4::<f32>::zeros((2, 32, 32, 3));
let logits = model.forward(&images).expect("classification forward should succeed");
assert_eq!(logits.shape(), &[2, 10]);
}
#[test]
fn test_deit_cls_only_head() {
let config = mini_config();
let model =
DeiTForImageClassification::new(config).expect("model construction should succeed");
let images = Array4::<f32>::zeros((1, 32, 32, 3));
let logits = model.forward_cls_only(&images).expect("cls-only forward should succeed");
assert_eq!(logits.shape(), &[1, 10]);
}
#[test]
fn test_deit_weight_loading_structure() {
let config = mini_config();
let model =
DeiTForImageClassification::new(config).expect("model construction should succeed");
let weight_map = model.weight_map();
assert!(weight_map
.contains_key("deit.embeddings.patch_embeddings.projection.weight"));
assert!(weight_map.contains_key("deit.embeddings.cls_token"));
assert!(weight_map.contains_key("deit.embeddings.distillation_token"));
assert!(weight_map.contains_key("deit.embeddings.position_embeddings"));
assert!(weight_map.contains_key("deit.layernorm.weight"));
assert!(weight_map.contains_key("classifier.weight"));
assert!(weight_map.contains_key("dist_head.weight"));
let layer_keys: Vec<_> = weight_map
.keys()
.filter(|k| k.starts_with("deit.encoder.layer."))
.collect();
assert_eq!(layer_keys.len(), 2 * 7); }
}