use candle_core::DType;
use candle_core::Device;
use crate::error::CanddingError;
use crate::error::Result;
use crate::registry::Backend;
use crate::registry::BackendSupport;
use crate::registry::DtypeBackendSupport;
use crate::registry::Support;
pub(crate) fn reject_unsupported_dtype(
model: &str,
dtype: DType,
dtype_backends: DtypeBackendSupport,
device: &Device,
) -> Result<()> {
refuse_on(model, dtype, dtype_backends.row(dtype), Backend::of(device))
}
fn refuse_on(model: &str, dtype: DType, row: BackendSupport, backend: Backend) -> Result<()> {
let unsupported = |support: Support| support == Support::Unsupported;
if unsupported(row.cpu) && unsupported(row.metal) && unsupported(row.cuda) {
return Err(CanddingError::UnsupportedDtype {
model: model.to_string(),
dtype,
});
}
if unsupported(row.get(backend)) {
return Err(CanddingError::UnsupportedOnDevice {
model: model.to_string(),
backend,
dtype,
});
}
Ok(())
}
pub(crate) fn resolve_dtype(
model: &str,
requested: Option<DType>,
default: DType,
device: &Device,
) -> Result<DType> {
let dtype = match requested {
Some(DType::BF16) if device.is_cpu() => {
return Err(CanddingError::UnsupportedOnDevice {
model: model.to_string(),
backend: Backend::Cpu,
dtype: DType::BF16,
});
}
Some(dtype) => dtype,
None if default == DType::BF16 && device.is_cpu() => {
tracing::warn!(
model,
"default dtype bf16 has no cpu matmul in candle; loading f32 instead"
);
DType::F32
}
None => default,
};
if dtype == DType::F16 && device.is_cpu() {
tracing::warn!(
model,
"f16 on cpu runs through candle's software f16 matmul, which accumulates in f16: slow and less precise than f32"
);
}
Ok(dtype)
}
#[cfg(test)]
mod tests;