Skip to content

Commit ab31989

Browse files
committed
fix(tests): use dtype-aware assert_finite in gemm_epilogue parity test
to_vec::<f64>() is a raw byte reinterpret, not a numeric conversion. Calling it on F32 tensors produces garbage values that appear non-finite, causing false failures on platforms where byte layout differs (e.g. Windows). Replace the three inline finiteness loops with a dtype-aware assert_finite helper that reads each tensor in its native type before widening to f64.
1 parent 5e3ae62 commit ab31989

1 file changed

Lines changed: 54 additions & 19 deletions

File tree

tests/backend_parity/gemm_epilogue.rs

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,55 @@ fn test_gemm_bias_activation_bwd_batched_3d_parity() {
467467
}
468468
}
469469

470+
// ============================================================================
471+
// Helpers
472+
// ============================================================================
473+
474+
/// Assert all elements of a tensor are finite, reading as the correct native dtype.
475+
fn assert_finite<R: numr::runtime::Runtime>(
476+
tensor: &numr::tensor::Tensor<R>,
477+
dtype: numr::dtype::DType,
478+
label: &str,
479+
) {
480+
use numr::dtype::DType;
481+
macro_rules! check {
482+
($T:ty) => {
483+
for (i, val) in tensor.to_vec::<$T>().iter().enumerate() {
484+
let v = *val as f64;
485+
assert!(
486+
v.is_finite(),
487+
"non-finite {label} [{dtype:?}] at index {i}: {v}"
488+
);
489+
}
490+
};
491+
}
492+
match dtype {
493+
DType::F64 => check!(f64),
494+
DType::F32 => check!(f32),
495+
#[cfg(feature = "f16")]
496+
DType::F16 => {
497+
for (i, val) in tensor.to_vec::<half::f16>().iter().enumerate() {
498+
let v = f32::from(*val) as f64;
499+
assert!(
500+
v.is_finite(),
501+
"non-finite {label} [{dtype:?}] at index {i}: {v}"
502+
);
503+
}
504+
}
505+
#[cfg(feature = "f16")]
506+
DType::BF16 => {
507+
for (i, val) in tensor.to_vec::<half::bf16>().iter().enumerate() {
508+
let v = f32::from(*val) as f64;
509+
assert!(
510+
v.is_finite(),
511+
"non-finite {label} [{dtype:?}] at index {i}: {v}"
512+
);
513+
}
514+
}
515+
_ => {} // integer/bool dtypes are always "finite"
516+
}
517+
}
518+
470519
// ============================================================================
471520
// matmul_bias_activation_bwd: negative values / edge cases
472521
// ============================================================================
@@ -496,25 +545,11 @@ fn test_gemm_bias_activation_bwd_negative_values_parity() {
496545
.matmul_bias_activation_bwd(&grad_t, &a_t, &b_t, &bias_t, activation)
497546
.unwrap();
498547

499-
// Verify finiteness on CPU reference
500-
for val in cpu_da.to_vec::<f64>().iter() {
501-
assert!(
502-
val.is_finite(),
503-
"non-finite d_a for {activation:?} [{dtype:?}]"
504-
);
505-
}
506-
for val in cpu_db.to_vec::<f64>().iter() {
507-
assert!(
508-
val.is_finite(),
509-
"non-finite d_b for {activation:?} [{dtype:?}]"
510-
);
511-
}
512-
for val in cpu_dbias.to_vec::<f64>().iter() {
513-
assert!(
514-
val.is_finite(),
515-
"non-finite d_bias for {activation:?} [{dtype:?}]"
516-
);
517-
}
548+
// Verify finiteness on CPU reference (must read as native dtype,
549+
// not f64, because to_vec is a raw byte copy with no conversion)
550+
assert_finite(&cpu_da, dtype, &format!("d_a for {activation:?}"));
551+
assert_finite(&cpu_db, dtype, &format!("d_b for {activation:?}"));
552+
assert_finite(&cpu_dbias, dtype, &format!("d_bias for {activation:?}"));
518553

519554
#[cfg(feature = "cuda")]
520555
if is_dtype_supported("cuda", dtype) {

0 commit comments

Comments
 (0)