use candle_core::Tensor;
use candle_nn::VarBuilder;
use super::attention::JinaBertAttention;
use super::config::JinaBertConfig;
use super::mlp::JinaBertMlp;
use super::variant::Variant;
use crate::error::Result;
use crate::layers::layer_norm::LayerNorm;
use crate::layers::mask::AttentionMask;
pub struct JinaBertLayer {
attention: JinaBertAttention,
mlp: JinaBertMlp,
norms: Option<(LayerNorm, LayerNorm)>,
}
impl JinaBertLayer {
pub fn load(config: &JinaBertConfig, variant: Variant, vb: VarBuilder) -> Result<Self> {
let norms = match variant.split_norms {
true => Some((
LayerNorm::load(
vb.pp("layer_norm_1"),
config.hidden_size,
config.layer_norm_eps,
)?,
LayerNorm::load(
vb.pp("layer_norm_2"),
config.hidden_size,
config.layer_norm_eps,
)?,
)),
false => None,
};
Ok(Self {
attention: JinaBertAttention::load(config, variant, vb.pp("attention"))?,
mlp: JinaBertMlp::load(config, variant.split_norms, vb)?,
norms,
})
}
pub fn forward(&self, hidden: &Tensor, mask: &AttentionMask) -> Result<Tensor> {
let attended = self.attention.forward(hidden, mask)?;
let Some((first, second)) = &self.norms else {
return self.mlp.forward(&attended);
};
let residual = first.forward(&(hidden + &attended)?)?;
let projected = self.mlp.forward(&residual)?;
Ok(second.forward(&(residual + projected)?)?)
}
}