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
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::XlmRobertaConfig;
use crate::error::Result;
use crate::layers::layer_norm::LayerNorm;

pub struct XlmRobertaEmbeddings {
  word: Embedding,
  position: Embedding,
  token_type: Embedding,
  layer_norm: LayerNorm,
  pad: u32,
}

impl XlmRobertaEmbeddings {
  pub fn load(config: &XlmRobertaConfig, vb: VarBuilder) -> Result<Self> {
    Ok(Self {
      word: embedding(
        config.bert.vocab_size,
        config.bert.hidden_size,
        vb.pp("word_embeddings"),
      )?,
      position: embedding(
        config.bert.max_position_embeddings,
        config.bert.hidden_size,
        vb.pp("position_embeddings"),
      )?,
      token_type: embedding(
        config.bert.type_vocab_size,
        config.bert.hidden_size,
        vb.pp("token_type_embeddings"),
      )?,
      layer_norm: LayerNorm::load(
        vb.pp("LayerNorm"),
        config.bert.hidden_size,
        config.bert.layer_norm_eps,
      )?,
      pad: config.pad_token_id as u32,
    })
  }

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

  /// Token types first, then positions, in transformers' order; the one-row token-type table is not zero.
  pub fn forward(&self, input_ids: &Tensor, token_type_ids: &Tensor) -> Result<Tensor> {
    let positions = position_ids(input_ids, self.pad)?;
    let summed = (self.word.forward(input_ids)? + self.token_type.forward(token_type_ids)?)?;
    let summed = (summed + self.position.forward(&positions)?)?;
    Ok(self.layer_norm.forward(&summed)?)
  }
}

/// transformers' `create_position_ids_from_input_ids`: non-pad ids count up from `pad + 1`, pad ids read `pad`.
/// A literal `<pad>` in the text is a pad id too, so later tokens shift one row down, as in the reference.
pub fn position_ids(input_ids: &Tensor, pad: u32) -> Result<Tensor> {
  let rows = input_ids.to_vec2::<u32>()?;
  let (batch, seq) = input_ids.dims2()?;
  let mut ids = Vec::with_capacity(batch * seq);
  for row in &rows {
    let mut numbered = pad;
    ids.extend(row.iter().map(|&id| {
      if id == pad {
        return pad;
      }
      numbered += 1;
      numbered
    }));
  }
  Ok(Tensor::from_vec(ids, (batch, seq), input_ids.device())?)
}