use std::collections::HashMap;
use candle_nn::VarBuilder;
use super::*;
use crate::models::jina_bert::AlibiSlopeVariant;
use crate::models::jina_bert::JinaBertConfig;
use crate::models::jina_bert::JinaBertModel;
#[test]
fn the_query_path_weighs_uniformly_where_the_passage_path_does_not() {
let config = JinaBertConfig {
vocab_size: 3,
hidden_size: 2,
num_hidden_layers: 0,
num_attention_heads: 1,
intermediate_size: 2,
type_vocab_size: 2,
layer_norm_eps: 1e-12,
max_position_embeddings: 16,
position_embedding_type: "alibi".to_string(),
feed_forward_type: "geglu".to_string(),
};
let tensors = HashMap::from([
(
"embeddings.word_embeddings.weight".to_string(),
Tensor::from_vec(vec![0f32, 0., 1.0, 0., 0., 0.], (3, 2), &Device::Cpu).unwrap(),
),
(
"embeddings.token_type_embeddings.weight".to_string(),
Tensor::from_vec(vec![0f32, 0., 0., 0.], (2, 2), &Device::Cpu).unwrap(),
),
(
"embeddings.LayerNorm.weight".to_string(),
Tensor::from_vec(vec![1f32, 1.], 2, &Device::Cpu).unwrap(),
),
(
"embeddings.LayerNorm.bias".to_string(),
Tensor::from_vec(vec![0f32, 0.], 2, &Device::Cpu).unwrap(),
),
]);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
let encoder = JinaBertModel::load(config, vb, AlibiSlopeVariant::Canonical).unwrap();
let matrix = Tensor::from_vec(
vec![
0f32, 0., 0., 0., 0., 0., 0., 0., 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0,
],
(2, 2, 4),
&Device::Cpu,
)
.unwrap();
let model = MiniCoilSparse::new(
Box::new(encoder),
matrix,
vocab(&["cat"]),
stopwords(&[]),
token_text(&["[CLS]", "cat", "[SEP]"]),
)
.unwrap();
let input_ids = Tensor::from_vec(vec![0u32, 1, 2], (1, 3), &Device::Cpu).unwrap();
let attention_mask = Tensor::from_vec(vec![1u32, 1, 1], (1, 3), &Device::Cpu).unwrap();
let token_type_ids = input_ids.zeros_like().unwrap();
let input = EncoderInput {
input_ids: &input_ids,
attention_mask: &attention_mask,
token_type_ids: &token_type_ids,
lengths: &[3],
};
let passage = model.forward(&input).unwrap();
let query = model.forward_query(&input).unwrap();
let tf: f32 = 1.0 * (1.2 + 1.0) / (1.0 + 1.2 * (1.0 - 0.75 + 0.75 * 1.0 / 150.0));
assert!(
(tf - 1.0).abs() > 1e-3,
"tf must not coincidentally be 1.0: {tf}"
);
let expected_indices: Vec<u32> = (0..4).map(|c| index::dense_index(1, c)).collect();
assert_eq!(passage[0].indices, expected_indices);
assert_eq!(query[0].indices, expected_indices);
for (&p, &q) in passage[0].values.iter().zip(&query[0].values) {
assert!(
(q - 0.5).abs() < 1e-5,
"the query path's own weight must be the bare normalized value: {q}"
);
assert!((p - q * tf).abs() < 1e-5, "{p} vs {q} * {tf}");
}
}