brain2qwerty 0.0.1

Brain2Qwerty V1/V2 MEG neural decoding inference in Rust (parity-tested vs Python)
Documentation
mod parity_metrics;

use brain2qwerty::model::conv_conformer::ConvConformer;
use brain2qwerty::tensor::load_tensor_bin;
use parity_metrics::compare_slices;

fn refs_dir() -> std::path::PathBuf {
    brain2qwerty::parity_refs_dir()
}

fn skip() -> bool {
    !refs_dir().join("input_neuros.bin").is_file()
        || !brain2qwerty::data_paths::encoder_weights_path().is_file()
}

#[test]
fn test_encoder_vs_python_refs() {
    if skip() {
        eprintln!("SKIP: parity refs / encoder weights not found");
        return;
    }
    let weights = brain2qwerty::data_paths::encoder_weights_path();
    let model = ConvConformer::from_tiny_weights(&weights.to_string_lossy()).unwrap();

    let neuros = load_tensor_bin(&refs_dir().join("input_neuros.bin")).unwrap();
    let chan_pos = load_tensor_bin(&refs_dir().join("input_chan_pos.bin")).unwrap();
    let days = load_tensor_bin(&refs_dir().join("input_days.bin")).unwrap();
    let subject_ids: Vec<usize> = days.data.iter().map(|&x| x as usize).collect();

    let out = model.forward(&neuros, &subject_ids, Some(&chan_pos));

    for name in ["z_enc", "z_final", "c_out", "z_aux"] {
        let path = refs_dir().join(format!("{name}.bin"));
        if !path.is_file() {
            continue;
        }
        let reference = load_tensor_bin(&path).unwrap();
        let actual = match name {
            "z_enc" => &out.z_enc,
            "z_final" => &out.z_final,
            "c_out" => &out.c_out,
            "z_aux" => out.z_aux.as_ref().unwrap(),
            _ => unreachable!(),
        };
        compare_slices(&actual.data, &reference.data).assert_full_parity(name);
    }
}