use crate::tensor::Tensor;
use crate::v1::config::V1Config;
use crate::v1::encoder::SimpleConvTimeAgg;
use crate::v1::transformer::SentenceTransformer;
use crate::weights::{get, load_safetensors, param_to_tensor, WeightStore};
pub struct Brain2QwertyV1 {
pub config: V1Config,
pub encoder: SimpleConvTimeAgg,
pub transformer: SentenceTransformer,
pub linear_w: Tensor,
pub linear_b: Tensor,
}
impl Brain2QwertyV1 {
pub fn from_config_and_weights(cfg: V1Config, weights_path: &str) -> anyhow::Result<Self> {
let mut store = load_safetensors(weights_path)?;
Self::from_config_and_store(cfg, &mut store)
}
pub fn from_tiny_weights(weights_path: &str) -> anyhow::Result<Self> {
Self::from_config_and_weights(V1Config::tiny(), weights_path)
}
pub fn from_config_and_store(cfg: V1Config, store: &mut WeightStore) -> anyhow::Result<Self> {
let hidden = cfg.brain_model_config.encoder_config.hidden;
let encoder =
SimpleConvTimeAgg::from_config_and_weights(&cfg.brain_model_config, store, "")?;
let transformer = SentenceTransformer::from_config_and_weights(
&cfg.transformer_config,
hidden,
store,
"transformer.",
)?;
let linear_w = param_to_tensor(get(store, "linear.weight")?);
let linear_b = param_to_tensor(get(store, "linear.bias")?);
Ok(Self {
config: cfg,
encoder,
transformer,
linear_w,
linear_b,
})
}
pub fn encode_keystrokes(
&self,
neuros: &Tensor,
subject_ids: &[usize],
chan_pos: Option<&Tensor>,
) -> Tensor {
self.encoder.forward(neuros, subject_ids, chan_pos)
}
pub fn refine_sentence(&self, embeds: &Tensor, mask: &[bool]) -> Tensor {
self.transformer.forward(embeds, mask)
}
pub fn classify(&self, hidden: &Tensor) -> Tensor {
let n = hidden.shape[0];
let d = hidden.shape[1];
let c = self.linear_w.shape[0];
let btd = hidden.reshape(&[1, n, d]);
btd.linear(&self.linear_w, Some(&self.linear_b))
.reshape(&[n, c])
}
pub fn forward_sentence(
&self,
neuros: &Tensor,
subject_ids: &[usize],
chan_pos: Option<&Tensor>,
) -> Tensor {
let n = neuros.shape[0];
let embeds = self.encode_keystrokes(neuros, subject_ids, chan_pos);
let seq = embeds.reshape(&[1, n, embeds.shape[1]]);
let mask = vec![true; n];
let refined = self.refine_sentence(&seq, &mask);
self.classify(&refined.reshape(&[n, refined.shape[2]]))
}
}