use candle_core::Module;
use candle_core::Result;
use candle_core::Tensor;
use serde::Deserialize;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Activation {
Gelu,
GeluNew,
GeluPytorchTanh,
Relu,
Silu,
}
impl Module for Activation {
fn forward(&self, xs: &Tensor) -> Result<Tensor> {
match self {
Activation::Gelu => xs.gelu_erf(),
Activation::GeluNew | Activation::GeluPytorchTanh => xs.gelu(),
Activation::Relu => xs.relu(),
Activation::Silu => xs.silu(),
}
}
}
#[cfg(test)]
mod tests {
use candle_core::Device;
use super::*;
#[test]
fn deserializes_hf_names() {
assert_eq!(
serde_json::from_str::<Activation>("\"gelu\"").unwrap(),
Activation::Gelu
);
assert_eq!(
serde_json::from_str::<Activation>("\"gelu_new\"").unwrap(),
Activation::GeluNew
);
assert_eq!(
serde_json::from_str::<Activation>("\"gelu_pytorch_tanh\"").unwrap(),
Activation::GeluPytorchTanh
);
}
#[test]
fn erf_and_tanh_gelu_differ_slightly() {
let xs = Tensor::new(&[1f32], &Device::Cpu).unwrap();
let erf = Activation::Gelu
.forward(&xs)
.unwrap()
.to_vec1::<f32>()
.unwrap()[0];
let tanh = Activation::GeluNew
.forward(&xs)
.unwrap()
.to_vec1::<f32>()
.unwrap()[0];
assert!((erf - 0.841345).abs() < 1e-5, "{erf}");
assert!((tanh - 0.841192).abs() < 1e-5, "{tanh}");
}
}