use candle_core::Module;
use candle_core::Tensor;
use candle_nn::Linear;
use candle_nn::VarBuilder;
use candle_nn::linear;
use super::config::MPNetConfig;
use crate::error::Result;
use crate::layers::attention::scaled_dot_product;
use crate::layers::layer_norm::LayerNorm;
use crate::layers::mask::AttentionMask;
pub struct MPNetAttention {
q: Linear,
k: Linear,
v: Linear,
o: Linear,
layer_norm: LayerNorm,
num_heads: usize,
head_dim: usize,
}
impl MPNetAttention {
pub fn load(config: &MPNetConfig, vb: VarBuilder) -> Result<Self> {
let hidden = config.hidden_size;
Ok(Self {
q: linear(hidden, hidden, vb.pp("attn.q"))?,
k: linear(hidden, hidden, vb.pp("attn.k"))?,
v: linear(hidden, hidden, vb.pp("attn.v"))?,
o: linear(hidden, hidden, vb.pp("attn.o"))?,
layer_norm: LayerNorm::load(vb.pp("LayerNorm"), hidden, config.layer_norm_eps)?,
num_heads: config.num_attention_heads,
head_dim: config.head_dim(),
})
}
pub fn forward(&self, hidden: &Tensor, mask: &AttentionMask) -> Result<Tensor> {
let (batch, seq, _) = hidden.dims3()?;
let split = |xs: Tensor| -> Result<Tensor> {
Ok(
xs.reshape((batch, seq, self.num_heads, self.head_dim))?
.transpose(1, 2)?
.contiguous()?,
)
};
let q = split(self.q.forward(hidden)?)?;
let k = split(self.k.forward(hidden)?)?;
let v = split(self.v.forward(hidden)?)?;
let scale = 1.0 / (self.head_dim as f64).sqrt();
let context = scaled_dot_product(&q, &k, &v, mask, scale)?
.transpose(1, 2)?
.reshape((batch, seq, self.num_heads * self.head_dim))?;
let projected = self.o.forward(&context)?;
Ok(self.layer_norm.forward(&(projected + hidden)?)?)
}
}