glowrs 0.4.1

SentenceTransformers for candle-rs
Documentation
use candle_core::Tensor;
use serde::Deserialize;
use std::process::ExitCode;

use glowrs::model::utils::normalize_l2;
use glowrs::{PoolingStrategy, Result};

#[derive(Deserialize)]
struct EmbeddingsExample {
    sentence: String,
    embedding: Vec<f32>,
}

#[derive(Deserialize)]
struct EmbeddingsFixture {
    model: String,
    examples: Vec<EmbeddingsExample>,
}

#[derive(Deserialize)]
struct Examples {
    fixtures: Vec<EmbeddingsFixture>,
}

#[test]
fn test_similarity_sentence_transformers() -> Result<ExitCode> {
    use approx::assert_relative_eq;
    let examples: Examples =
        serde_json::from_str(include_str!("./fixtures/embeddings/examples.json"))?;
    let device = glowrs::Device::Cpu;
    for fixture in examples.fixtures {
        let encoder = glowrs::SentenceTransformer::from_repo_string(&fixture.model, &device)?;
        println!("Loaded model: {}", &fixture.model);
        for example in fixture.examples {
            let embedding =
                encoder.encode_batch(vec![example.sentence], false, PoolingStrategy::Mean)?;
            let embedding = normalize_l2(&embedding)?;

            let expected_dim = example.embedding.len();
            let expected = Tensor::from_vec(example.embedding, (1, expected_dim), &device)?;
            let expected = normalize_l2(&expected)?;

            assert_eq!(embedding.dims(), expected.dims());

            let sim = embedding.matmul(&expected.t()?)?.squeeze(1)?;

            let sim = sim.to_vec1::<f32>()?;
            let sim = sim.first().expect("Expected a value");
            assert_relative_eq!(*sim, 1.0, epsilon = 1e-3);
        }
        println!("Passed all examples for model: {}", &fixture.model)
    }

    Ok(ExitCode::SUCCESS)
}