use crate::inference::cuda::CudaMath;
use crate::inference::cuda::candidate::{
ConfigPin, ConvKernel, ConvPin, FbankPin, LstmPin, LstmProjection, SegdenseEntry, SincPin,
WideconvAlgorithm, WideconvPin, WideconvProducts, WideconvTensorKernel,
};
use crate::inference::cuda::implementation::BoundaryId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Approval {
DirectFp32,
DirectTf32,
ThreeProductSegmentation,
StagedWinograd,
C64FfmaWinograd,
Fp16Trunk,
}
impl Approval {
pub(crate) const fn description(self) -> &'static str {
match self {
Self::DirectFp32 => "reviewed direct FP32 end-to-end accuracy",
Self::ThreeProductSegmentation => {
"reviewed A100 three-product segmentation end-to-end accuracy"
}
Self::DirectTf32 => "reviewed direct TF32 end-to-end accuracy",
Self::StagedWinograd => "reviewed wtp1 end-to-end accuracy",
Self::Fp16Trunk => {
"FP16 trunk: T4 e1 DER gates pass; A100 a100-e4/pcie-e1 identical RTTMs; 4060 Ti identical RTTMs"
}
Self::C64FfmaWinograd => "reviewed C64 FFMA Winograd end-to-end accuracy",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RuntimePolicy {
Strict,
ExactFp32,
}
impl RuntimePolicy {
pub(crate) const fn allows_exact_fp32(self) -> bool {
matches!(self, Self::ExactFp32)
}
pub(crate) fn approve(
self,
boundary: BoundaryId,
math: CudaMath,
pin: ConfigPin,
) -> Option<Approval> {
Policy::approve(boundary, math, pin).or_else(|| {
if !self.allows_exact_fp32() || math != CudaMath::Tf32 {
return None;
}
Policy::approve(boundary, CudaMath::Fp32, pin)
.filter(|approval| *approval == Approval::DirectFp32)
})
}
}
pub(crate) struct Policy;
impl Policy {
pub(crate) const IDENTITY: &'static str = "end-to-end-algorithms-v6";
pub(crate) fn approve(
boundary: BoundaryId,
math: CudaMath,
pin: ConfigPin,
) -> Option<Approval> {
let approval = match pin {
ConfigPin::Conv(ConvPin::Kernel(kernel)) => match kernel {
ConvKernel::C32
| ConvKernel::C64
| ConvKernel::C64Small
| ConvKernel::C32Stride2
| ConvKernel::C32Stride2Small => Approval::DirectFp32,
ConvKernel::C32Tensor
| ConvKernel::C64Tensor
| ConvKernel::C64TensorSlim
| ConvKernel::C32Stride2Tensor => Approval::DirectTf32,
},
ConfigPin::Wideconv(WideconvPin::Configured(config)) => match config.algorithm {
WideconvAlgorithm::Fp16(_) => Approval::Fp16Trunk,
WideconvAlgorithm::Spatial | WideconvAlgorithm::WideStem => Approval::DirectFp32,
WideconvAlgorithm::TensorCore(
WideconvTensorKernel::Tf32 | WideconvTensorKernel::Tf32Slim,
) => Approval::DirectTf32,
WideconvAlgorithm::Winograd(WideconvProducts::Tf32x1Staged) => {
Approval::StagedWinograd
}
WideconvAlgorithm::Winograd(WideconvProducts::Fp32)
if [
BoundaryId::named("resnet.layer2.0.conv2"),
BoundaryId::named("resnet.layer2.1.conv1"),
BoundaryId::named("resnet.layer2.1.conv2"),
BoundaryId::named("resnet.layer2.2.conv1"),
BoundaryId::named("resnet.layer2.2.conv2"),
BoundaryId::named("resnet.layer2.3.conv1"),
BoundaryId::named("resnet.layer2.3.conv2"),
]
.contains(&boundary) =>
{
Approval::C64FfmaWinograd
}
_ => return None,
},
ConfigPin::Lstm(LstmPin::Projected(LstmProjection::Small | LstmProjection::Large))
| ConfigPin::Fbank(FbankPin::FftMelAccurate) => Approval::DirectFp32,
ConfigPin::Sinc(SincPin::ConvAbsPool) if math == CudaMath::Fp32 => Approval::DirectFp32,
ConfigPin::Segdense(pin) => match pin.entry() {
SegdenseEntry::Conv1B32X3 | SegdenseEntry::Conv2B32X3 => {
Approval::ThreeProductSegmentation
}
SegdenseEntry::Conv1B1
| SegdenseEntry::Conv1B32
| SegdenseEntry::Conv2B1
| SegdenseEntry::Conv2B32
| SegdenseEntry::Linear0B1
| SegdenseEntry::Linear0B32
| SegdenseEntry::Linear1B1
| SegdenseEntry::Linear1B32
| SegdenseEntry::ClassifierB1
| SegdenseEntry::ClassifierB32
| SegdenseEntry::EmbedB1
| SegdenseEntry::EmbedB32 => Approval::DirectFp32,
SegdenseEntry::EmbedB32Tf32
| SegdenseEntry::EmbedB32Tf32K2
| SegdenseEntry::EmbedB32Tf32E64 => Approval::DirectTf32,
_ => return None,
},
_ => return None,
};
match (math, approval) {
(_, Approval::DirectFp32) | (CudaMath::Fp32, Approval::ThreeProductSegmentation) => {
Some(approval)
}
(CudaMath::Tf32, Approval::ThreeProductSegmentation) => None,
(CudaMath::Tf32, _) => Some(approval),
_ => None,
}
}
}