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::GteNewConfig;
use crate::error::Result;
use crate::layers::layer_norm::LayerNorm;
pub struct GteNewEmbeddings {
word: Embedding,
token_type: Option<Embedding>,
norm: LayerNorm,
}
impl GteNewEmbeddings {
pub fn load(config: &GteNewConfig, vb: VarBuilder) -> Result<Self> {
let embeddings = vb.pp("embeddings");
let token_type = if config.has_token_types() {
Some(embedding(
config.type_vocab_size,
config.hidden_size,
embeddings.pp("token_type_embeddings"),
)?)
} else {
None
};
Ok(Self {
word: embedding(
config.vocab_size,
config.hidden_size,
embeddings.pp("word_embeddings"),
)?,
token_type,
norm: LayerNorm::load(
embeddings.pp("LayerNorm"),
config.hidden_size,
config.layer_norm_eps,
)?,
})
}
pub(super) fn weights_dtype(&self) -> DType {
self.word.embeddings().dtype()
}
pub fn forward(&self, input_ids: &Tensor) -> Result<Tensor> {
let mut embeddings = self.word.forward(input_ids)?;
if let Some(token_type) = &self.token_type {
let row0 = token_type.embeddings().narrow(0, 0, 1)?;
embeddings = embeddings.broadcast_add(&row0)?;
}
Ok(self.norm.forward(&embeddings)?)
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use candle_core::DType;
use candle_core::Device;
use candle_nn::VarBuilder;
use super::*;
fn config(type_vocab_size: usize) -> GteNewConfig {
GteNewConfig {
hidden_size: 4,
num_hidden_layers: 1,
num_attention_heads: 1,
intermediate_size: 4,
vocab_size: 10,
type_vocab_size,
hidden_act: "gelu".to_string(),
layer_norm_type: "layer_norm".to_string(),
layer_norm_eps: 1e-12,
position_embedding_type: "rope".to_string(),
rope_theta: 10_000.0,
rope_scaling: None,
max_position_embeddings: 32,
pack_qkv: true,
unpad_inputs: false,
use_memory_efficient_attention: false,
}
}
fn word_and_norm_tensors(hidden: usize, vocab: usize) -> HashMap<String, Tensor> {
let mut tensors = HashMap::new();
tensors.insert(
"embeddings.word_embeddings.weight".to_string(),
Tensor::zeros((vocab, hidden), DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.LayerNorm.weight".to_string(),
Tensor::ones(hidden, DType::F32, &Device::Cpu).unwrap(),
);
tensors.insert(
"embeddings.LayerNorm.bias".to_string(),
Tensor::zeros(hidden, DType::F32, &Device::Cpu).unwrap(),
);
tensors
}
#[test]
fn a_zero_type_vocab_size_loads_without_a_token_type_tensor() {
let tensors = word_and_norm_tensors(4, 10);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
assert!(GteNewEmbeddings::load(&config(0), vb).is_ok());
}
#[test]
fn a_positive_type_vocab_size_fails_to_load_without_a_token_type_tensor() {
let tensors = word_and_norm_tensors(4, 10);
let vb = VarBuilder::from_tensors(tensors, DType::F32, &Device::Cpu);
assert!(GteNewEmbeddings::load(&config(1), vb).is_err());
}
}