use crate::autograd::OpError;
use crate::models::bert::load::BertLoadError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SetFitError {
ImportConfigMismatch {
field: String,
expected: String,
got: String,
},
ImportIo {
path: String,
reason: String,
},
ImportTensor(BertLoadError),
TokenizerLoad {
reason: String,
},
TokenizerHashMismatch {
expected: String,
got: String,
},
UnsupportedPooling {
got: String,
},
UnsupportedArchitecture {
got: String,
},
UnsupportedActivation {
got: String,
},
BatchInvalid {
reason: String,
},
OversizeInput {
len: usize,
max: usize,
},
VocabOutOfSlice {
canonical_id: u32,
},
NonFiniteTensor {
tensor: String,
position: usize,
},
RemapInvalid {
reason: String,
},
FreezeGroupInvalid {
reason: String,
},
DropoutRng {
reason: String,
},
Op(OpError),
}
impl From<OpError> for SetFitError {
fn from(e: OpError) -> Self {
Self::Op(e)
}
}
impl From<super::dropout_rng::DropoutRngError> for SetFitError {
fn from(e: super::dropout_rng::DropoutRngError) -> Self {
Self::DropoutRng {
reason: e.to_string(),
}
}
}
impl From<BertLoadError> for SetFitError {
fn from(e: BertLoadError) -> Self {
Self::ImportTensor(e)
}
}
impl std::fmt::Display for SetFitError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ImportConfigMismatch {
field,
expected,
got,
} => write!(
f,
"SetFitError::ImportConfigMismatch(field {field}: expected {expected}, got {got})"
),
Self::ImportIo { path, reason } => {
write!(f, "SetFitError::ImportIo({path}: {reason})")
}
Self::ImportTensor(e) => write!(f, "SetFitError::ImportTensor({e})"),
Self::TokenizerLoad { reason } => {
write!(f, "SetFitError::TokenizerLoad({reason})")
}
Self::TokenizerHashMismatch { expected, got } => write!(
f,
"SetFitError::TokenizerHashMismatch(expected {expected}, got {got})"
),
Self::UnsupportedPooling { got } => {
write!(f, "SetFitError::UnsupportedPooling({got})")
}
Self::UnsupportedArchitecture { got } => {
write!(
f,
"SetFitError::UnsupportedArchitecture(architectures = {got}; only BertModel is pinned)"
)
}
Self::UnsupportedActivation { got } => {
write!(
f,
"SetFitError::UnsupportedActivation(hidden_act = \"{got}\" is not the pinned exact-erf \"gelu\")"
)
}
Self::BatchInvalid { reason } => {
write!(f, "SetFitError::BatchInvalid({reason})")
}
Self::OversizeInput { len, max } => write!(
f,
"SetFitError::OversizeInput(length {len} exceeds maximum {max})"
),
Self::VocabOutOfSlice { canonical_id } => write!(
f,
"SetFitError::VocabOutOfSlice(canonical id {canonical_id} is outside the slice closure)"
),
Self::NonFiniteTensor { tensor, position } => write!(
f,
"SetFitError::NonFiniteTensor({tensor} has a non-finite value at flat position {position})"
),
Self::RemapInvalid { reason } => {
write!(f, "SetFitError::RemapInvalid({reason})")
}
Self::FreezeGroupInvalid { reason } => {
write!(f, "SetFitError::FreezeGroupInvalid({reason})")
}
Self::DropoutRng { reason } => {
write!(f, "SetFitError::DropoutRng({reason})")
}
Self::Op(e) => write!(f, "SetFitError::Op({e})"),
}
}
}
impl std::error::Error for SetFitError {}
#[cfg(all(test, feature = "setfit"))]
mod tests {
use super::*;
#[test]
fn setfit_error_op_wraps_and_forwards_the_inner_diagnostic() {
let inner = OpError::OutOfVocabulary {
id: 40_000,
vocab_size: 97,
position: 7,
};
let wrapped: SetFitError = inner.clone().into();
assert_eq!(wrapped, SetFitError::Op(inner.clone()));
let text = wrapped.to_string();
assert!(text.contains(&inner.to_string()), "got {text}");
assert!(text.contains("40000"), "got {text}");
assert!(text.contains("position 7"), "got {text}");
}
#[test]
fn setfit_error_bert_load_error_wraps_and_names_the_tensor() {
let inner = BertLoadError {
tensor: "embeddings.word_embeddings.weight".to_string(),
reason: "tensor not present in APR file".to_string(),
};
let wrapped: SetFitError = inner.clone().into();
assert_eq!(wrapped, SetFitError::ImportTensor(inner));
assert!(
wrapped.to_string().contains("word_embeddings"),
"got {wrapped}"
);
}
#[test]
fn setfit_error_display_names_the_mismatched_field() {
let e = SetFitError::ImportConfigMismatch {
field: "hidden_size".to_string(),
expected: "384".to_string(),
got: "512".to_string(),
};
let text = e.to_string();
assert!(text.contains("hidden_size"), "got {text}");
assert!(text.contains("384"), "got {text}");
assert!(text.contains("512"), "got {text}");
}
#[test]
fn setfit_error_is_a_std_error() {
fn assert_error<E: std::error::Error>(_: &E) {}
assert_error(&SetFitError::BatchInvalid {
reason: "empty text list".to_string(),
});
}
}