use std::collections::HashMap;
use super::*;
fn conventions(keeps_cls_row: bool, projection_out: usize) -> MultiVectorConventions {
MultiVectorConventions {
keeps_cls_row,
projection_in: 4,
projection_out,
projection_bias: false,
normalize: true,
attends_to_mask_tokens: false,
position_scheme: None,
}
}
fn tensor_map(hidden_size: usize, out_features: usize) -> HashMap<String, Tensor> {
let mut tensors = HashMap::new();
tensors.insert(
"linear.weight".to_string(),
Tensor::zeros((out_features, hidden_size), DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.word_embeddings.weight".to_string(),
Tensor::zeros((64, hidden_size), DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.position_embeddings.weight".to_string(),
Tensor::zeros((32, hidden_size), DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.token_type_embeddings.weight".to_string(),
Tensor::zeros((2, hidden_size), DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.LayerNorm.weight".to_string(),
Tensor::ones(hidden_size, DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.LayerNorm.bias".to_string(),
Tensor::zeros(hidden_size, DType::F32, &Device::Cpu).unwrap(),
);
tensors
}
#[test]
fn load_reads_the_real_root_linear_weight_and_its_shape() {
let tensors = tensor_map(4, 3);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
let model =
StanfordColbert::load(tiny_config(4), vb, HashSet::new(), conventions(true, 3)).unwrap();
assert_eq!(model.dim(), 3);
}
#[test]
fn a_projection_out_that_disagrees_with_the_real_tensor_shape_is_refused() {
let tensors = tensor_map(4, 3);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
match StanfordColbert::load(tiny_config(4), vb, HashSet::new(), conventions(true, 5)) {
Ok(_) => panic!("a projection_out that disagrees with the real tensor shape must be refused"),
Err(err) => assert!(
matches!(err, crate::error::CanddingError::Candle(_)),
"{err}"
),
}
}
#[test]
fn a_missing_root_linear_weight_is_refused() {
let mut tensors = tensor_map(4, 3);
tensors.remove("linear.weight");
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
match StanfordColbert::load(tiny_config(4), vb, HashSet::new(), conventions(true, 3)) {
Ok(_) => panic!("a missing root linear.weight must be refused"),
Err(err) => assert!(
matches!(err, crate::error::CanddingError::Candle(_)),
"{err}"
),
}
}
#[test]
fn load_carries_keeps_cls_row_and_normalize_onto_the_struct() {
let tensors = tensor_map(4, 3);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
let mut wanted = conventions(false, 3);
wanted.normalize = false;
let model = StanfordColbert::load(tiny_config(4), vb, HashSet::new(), wanted).unwrap();
assert!(
!model.keeps_cls_row,
"keeps_cls_row must carry through load"
);
assert!(!model.normalize, "normalize must carry through load");
}
#[test]
fn projection_bias_gates_whether_linear_bias_is_read() {
let tensors = tensor_map(4, 3);
let vb = VarBuilder::from_tensors(tensors.clone(), DType::F32, &Device::Cpu);
assert!(
StanfordColbert::load(tiny_config(4), vb, HashSet::new(), conventions(true, 3)).is_ok(),
"projection_bias:false must not try to read a linear.bias that is not there"
);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
let mut wants_bias = conventions(true, 3);
wants_bias.projection_bias = true;
match StanfordColbert::load(tiny_config(4), vb, HashSet::new(), wants_bias) {
Ok(_) => panic!("projection_bias:true must fail when linear.bias is not published"),
Err(err) => assert!(
matches!(err, crate::error::CanddingError::Candle(_)),
"{err}"
),
}
}