use candle_core::DType;
use candle_core::Tensor;
use candle_nn::Linear;
use candle_nn::Module;
use candle_nn::VarBuilder;
use super::RerankModel;
use crate::error::CanddingError;
use crate::error::Result;
use crate::models::Encoder;
use crate::models::EncoderInput;
use crate::models::xlm_roberta;
use crate::models::xlm_roberta_flash;
use crate::models::xlm_roberta_flash::PositionScheme;
use crate::pooling;
use crate::pooling::Pooling;
use crate::rerank::RerankScore;
use crate::rerank::ScoreActivation;
pub struct RobertaClassificationRerank {
encoder: Box<dyn Encoder>,
dense: Linear,
out_proj: Linear,
score_activation: ScoreActivation,
}
impl RobertaClassificationRerank {
pub fn load(
model_type: &str,
config_json: &str,
vb: VarBuilder,
score_activation: ScoreActivation,
position_scheme: Option<PositionScheme>,
) -> Result<Self> {
let encoder: Box<dyn Encoder> = match model_type {
"xlm-roberta" => {
let config: xlm_roberta::XlmRobertaConfig = serde_json::from_str(config_json)?;
Box::new(xlm_roberta::XlmRobertaModel::load(
config,
vb.pp("roberta"),
)?)
}
xlm_roberta_flash::ARCHITECTURE => {
let config: xlm_roberta_flash::XlmRobertaFlashConfig = serde_json::from_str(config_json)?;
Box::new(xlm_roberta_flash::XlmRobertaFlashModel::load(
config,
vb.clone(),
position_scheme,
)?)
}
other => {
return Err(CanddingError::UnsupportedArchitecture(other.to_string()));
}
};
let hidden = encoder.hidden_size();
let head_vb = vb.pp("classifier");
let dense_vb = head_vb.pp("dense");
let dense = Linear::new(
dense_vb.get((hidden, hidden), "weight")?,
Some(dense_vb.get(hidden, "bias")?),
);
let out_proj_vb = head_vb.pp("out_proj");
let out_proj = Linear::new(
out_proj_vb.get((1, hidden), "weight")?,
Some(out_proj_vb.get(1, "bias")?),
);
Ok(Self {
encoder,
dense,
out_proj,
score_activation,
})
}
}
impl RerankModel for RobertaClassificationRerank {
fn forward(&self, input: &EncoderInput) -> Result<Vec<RerankScore>> {
let hidden = self.encoder.forward(input)?;
let cls =
pooling::pool(Pooling::Cls, &hidden, input.attention_mask, input.lengths)?.contiguous()?;
let projected = self.dense.forward(&cls)?.tanh()?;
let logits: Vec<f32> = raw_logits(&self.out_proj.forward(&projected)?)?;
Ok(
logits
.into_iter()
.map(|raw| RerankScore::new(self.score_activation.apply(raw)))
.collect(),
)
}
fn max_position_embeddings(&self) -> usize {
self.encoder.max_position_embeddings()
}
fn weights_dtype(&self) -> DType {
self.encoder.weights_dtype()
}
}
fn raw_logits(logits: &Tensor) -> Result<Vec<f32>> {
Ok(logits.squeeze(1)?.to_dtype(DType::F32)?.to_vec1::<f32>()?)
}
#[cfg(test)]
mod tests;