candding 0.1.0

Pure candle embeddings for Rust with no ONNX: dense, sparse, multi-vector and rerank models today, image models on the roadmap
Documentation
//! Word and token-type embeddings; no position table, as `rotary_emb_fraction` is 1.0 for every checkpoint.

use candle_core::DType;
use candle_core::Module;
use candle_core::Tensor;
use candle_nn::Embedding;
use candle_nn::VarBuilder;
use candle_nn::embedding;

use super::config::NomicBertConfig;
use crate::error::Result;
use crate::layers::layer_norm::LayerNorm;

/// `emb_ln` sits at the root, beside `encoder.`, not under `embeddings.`.
pub struct NomicBertEmbeddings {
  word: Embedding,
  token_type: Embedding,
  emb_ln: LayerNorm,
}

impl NomicBertEmbeddings {
  /// `vb` is the model's root `VarBuilder`.
  pub fn load(config: &NomicBertConfig, vb: VarBuilder) -> Result<Self> {
    let embeddings = vb.pp("embeddings");
    Ok(Self {
      word: embedding(
        config.vocab_size,
        config.n_embd,
        embeddings.pp("word_embeddings"),
      )?,
      token_type: embedding(
        config.type_vocab_size,
        config.n_embd,
        embeddings.pp("token_type_embeddings"),
      )?,
      emb_ln: LayerNorm::load(vb.pp("emb_ln"), config.n_embd, config.layer_norm_epsilon)?,
    })
  }

  pub(super) fn weights_dtype(&self) -> DType {
    self.word.embeddings().dtype()
  }

  pub fn forward(&self, input_ids: &Tensor, token_type_ids: &Tensor) -> Result<Tensor> {
    let summed = (self.word.forward(input_ids)? + self.token_type.forward(token_type_ids)?)?;
    Ok(self.emb_ln.forward(&summed)?)
  }
}