use serde::Deserialize;
use super::bias::NUM_BUCKETS;
use crate::error::CanddingError;
use crate::error::Result;
use crate::layers::activation::Activation;
pub(super) const PADDING_IDX: u32 = 1;
pub(super) const POSITION_OFFSET: u32 = PADDING_IDX + 1;
#[derive(Clone, Debug, Deserialize)]
pub struct MPNetConfig {
pub vocab_size: usize,
pub hidden_size: usize,
pub num_hidden_layers: usize,
pub num_attention_heads: usize,
pub intermediate_size: usize,
#[serde(default = "default_act")]
pub hidden_act: Activation,
pub max_position_embeddings: usize,
#[serde(default = "default_eps")]
pub layer_norm_eps: f64,
#[serde(default = "default_num_buckets")]
pub relative_attention_num_buckets: usize,
#[serde(default = "default_pad_token_id")]
pub pad_token_id: usize,
}
fn default_act() -> Activation {
Activation::Gelu
}
fn default_eps() -> f64 {
1e-12
}
fn default_num_buckets() -> usize {
NUM_BUCKETS
}
fn default_pad_token_id() -> usize {
PADDING_IDX as usize
}
impl MPNetConfig {
pub fn head_dim(&self) -> usize {
self.hidden_size / self.num_attention_heads
}
pub fn sequence_limit(&self) -> usize {
self
.max_position_embeddings
.saturating_sub(POSITION_OFFSET as usize)
}
pub fn ensure_supported(&self) -> Result<()> {
if self.relative_attention_num_buckets != NUM_BUCKETS {
return Err(CanddingError::UnsupportedArchitecture(format!(
"mpnet with {} relative attention buckets",
self.relative_attention_num_buckets
)));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::CanddingError;
use crate::layers::activation::Activation;
const ALL_MPNET_BASE_V2: &str = r#"{
"architectures": ["MPNetForMaskedLM"],
"attention_probs_dropout_prob": 0.1,
"bos_token_id": 0,
"eos_token_id": 2,
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"layer_norm_eps": 1e-05,
"max_position_embeddings": 514,
"model_type": "mpnet",
"num_attention_heads": 12,
"num_hidden_layers": 12,
"pad_token_id": 1,
"relative_attention_num_buckets": 32,
"transformers_version": "4.8.2",
"vocab_size": 30527
}"#;
#[test]
fn reads_the_published_config() {
let config: MPNetConfig = serde_json::from_str(ALL_MPNET_BASE_V2).unwrap();
assert_eq!(config.vocab_size, 30527);
assert_eq!(config.hidden_size, 768);
assert_eq!(config.num_hidden_layers, 12);
assert_eq!(config.num_attention_heads, 12);
assert_eq!(config.intermediate_size, 3072);
assert_eq!(config.hidden_act, Activation::Gelu);
assert_eq!(config.max_position_embeddings, 514);
assert_eq!(config.layer_norm_eps, 1e-5);
assert_eq!(config.relative_attention_num_buckets, 32);
assert_eq!(config.head_dim(), 64);
}
#[test]
fn the_sequence_limit_drops_the_position_offset() {
let config: MPNetConfig = serde_json::from_str(ALL_MPNET_BASE_V2).unwrap();
assert_eq!(config.sequence_limit(), 512);
assert_eq!(600usize.min(config.sequence_limit()), 512);
assert_eq!(200usize.min(config.sequence_limit()), 200);
}
#[test]
fn the_pad_token_id_agrees_with_the_literal_the_numbering_uses() {
let config: MPNetConfig = serde_json::from_str(ALL_MPNET_BASE_V2).unwrap();
assert_eq!(config.pad_token_id as u32, PADDING_IDX);
assert_eq!(POSITION_OFFSET, PADDING_IDX + 1);
}
#[test]
fn a_token_type_field_is_ignored_rather_than_honoured() {
assert!(!ALL_MPNET_BASE_V2.contains("type_vocab_size"));
let with_field = ALL_MPNET_BASE_V2.replace(
"\"vocab_size\": 30527",
"\"type_vocab_size\": 2,\n \"vocab_size\": 30527",
);
let config: MPNetConfig = serde_json::from_str(&with_field).unwrap();
assert_eq!(config.vocab_size, 30527);
}
#[test]
fn the_optional_fields_default_to_the_reference_config_values() {
let stripped = ALL_MPNET_BASE_V2
.replace("\"hidden_act\": \"gelu\",", "")
.replace("\"layer_norm_eps\": 1e-05,", "")
.replace("\"pad_token_id\": 1,", "")
.replace("\"relative_attention_num_buckets\": 32,", "");
let config: MPNetConfig = serde_json::from_str(&stripped).unwrap();
assert_eq!(config.hidden_act, Activation::Gelu);
assert_eq!(config.layer_norm_eps, 1e-12);
assert_eq!(config.relative_attention_num_buckets, 32);
assert_eq!(config.pad_token_id, 1);
}
#[test]
fn only_thirty_two_buckets_are_supported() {
let supported: MPNetConfig = serde_json::from_str(ALL_MPNET_BASE_V2).unwrap();
supported.ensure_supported().unwrap();
let wide: MPNetConfig = serde_json::from_str(&ALL_MPNET_BASE_V2.replace(
"\"relative_attention_num_buckets\": 32",
"\"relative_attention_num_buckets\": 64",
))
.unwrap();
let err = wide.ensure_supported().unwrap_err();
assert!(
matches!(err, CanddingError::UnsupportedArchitecture(ref m) if m.contains("64")),
"{err}"
);
}
}