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::Module;
use candle_core::Tensor;
use candle_nn::Linear;
use candle_nn::VarBuilder;
use candle_nn::linear;

use super::attention::BertAttention;
use super::config::BertConfig;
use crate::error::Result;
use crate::layers::activation::Activation;
use crate::layers::layer_norm::LayerNorm;
use crate::layers::mask::AttentionMask;

pub struct BertLayer {
  attention: BertAttention,
  intermediate: Linear,
  activation: Activation,
  output: Linear,
  layer_norm: LayerNorm,
}

impl BertLayer {
  pub fn load(config: &BertConfig, vb: VarBuilder) -> Result<Self> {
    Ok(Self {
      attention: BertAttention::load(config, vb.pp("attention"))?,
      intermediate: linear(
        config.hidden_size,
        config.intermediate_size,
        vb.pp("intermediate.dense"),
      )?,
      activation: config.hidden_act,
      output: linear(
        config.intermediate_size,
        config.hidden_size,
        vb.pp("output.dense"),
      )?,
      layer_norm: LayerNorm::load(
        vb.pp("output.LayerNorm"),
        config.hidden_size,
        config.layer_norm_eps,
      )?,
    })
  }

  /// The feed-forward half, shared by both forwards.
  fn finish(&self, attended: Tensor) -> Result<Tensor> {
    let inner = self
      .activation
      .forward(&self.intermediate.forward(&attended)?)?;
    let projected = self.output.forward(&inner)?;
    Ok(self.layer_norm.forward(&(projected + attended)?)?)
  }

  pub fn forward(&self, hidden: &Tensor, mask: &AttentionMask) -> Result<Tensor> {
    let attended = self.attention.forward(hidden, mask)?;
    self.finish(attended)
  }

  /// `forward` plus the attention weights; only the layer whose weights are wanted calls it.
  pub fn forward_with_weights(
    &self,
    hidden: &Tensor,
    mask: &AttentionMask,
  ) -> Result<(Tensor, Tensor)> {
    let (attended, weights) = self.attention.forward_with_weights(hidden, mask)?;
    Ok((self.finish(attended)?, weights))
  }
}