Add full-range zero-point CompInt8 SQNBit tests; harden AVX2 M=1 kernels#29886
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
…=1 SQNBit kernels
|
I ran this PR's tests plus an independent verification harness on the configurations this thread has not been able to reach. Machine is an Arrow Lake (AVX2 + AVX-VNNI, no AVX-512), which natively executes both AVX2 dispatch tables: Results, all at head with this PR applied:
So I do not think there is a kernel bug here, and I can offer a concrete candidate for where #29853's numbers came from. The packed buffer produced by On the changes themselves, three notes:
The |
Description
Adds regression coverage for asymmetric (zero-point) 4-bit
CompInt8SQNBit GEMM and fixes two latent defects in the AVX2M=1kernels.Tests (
test_sqnbitgemm.cpp)TestFullRangeZeroPointCompInt8+SQNBitGemmFullRangeZeroPointShortExecuteTest(180 tests across BlkLen 16/32/64/128/256). Builds explicit quantized B, scales, and zero points spanning the full 0..15 range (deterministic LCG), packs viaMlasQNBitGemmPackQuantBData, and comparesMlasQNBitGemmBatchagainst an exact double-precision integer reference.M=1code paths: the 4-column block loop (Q4Int8GemmM1C4*) and its 1–3 column remainder (Q4Int8GemmM1C1*), even/oddBlockCountK, partial trailing K block, plus a fewM>1rows for cross-check.CloseEnough— see Motivation.Kernel hardening
SQ4BitGemmM1Kernel_CompInt8_avx2had silently-emptyif (BlkLen == 16) { }branches in both the zero-point and non-zero-point arms, leavingCuninitialized. Replaced with an explicit precondition:MlasQ4Int8GemmM1KernelBlkLen32Avx2/MlasQ4Int8GemmKernelBlkLen64Avx2performedQuantBZeroPoint + multipleCols * StrideQuantBZeroPointon the remainder-column path even whenQuantBZeroPoint == nullptr(UB, UBSan-visible). Now guarded.Motivation and Context
The linked issue reports ~46% error from
SQ4BitGemmM1Kernel_CompInt8_avx2for asymmetric 4-bit weights on AVX2-only hosts, reproduced under Intel SDE-hsw.The numeric defect did not reproduce on native AVX2 hardware. Verification ran on an AMD EPYC 7763 (
avx2, noavx512f, noavx_vnni— the exactMlasSQNBitGemmDispatchAvx2/vnni=falsepath), with the suspect kernel confirmed to dispatch via temporary instrumentation:M=1asymmetric CompInt8 (N1..132 × 17Kvalues × 5 BlkLens), including the reportedM=1, N=96, K=256, BlkLen=32— passHand audit of the named suspects also came up clean:
get_zpnibble selection and strides are consistent;_mm256_maddubs_epi16(|b|, sign(a,b))cannot saturate (|b| ≤ 15,|a| ≤ 127); and_mm256_sign_epi8would only mis-negatea = -128, whichQuantizeARow_CompInt8_avx2cannot produce (scale = maxAbs/127). Note thataccumulate_mul_sum_avx2/load_and_mul_sum_s8_quads_with_zp_avx2are reachable only from dead code (SQ4BitGemmM1Kernel_BlkLen32_CompInt8_Impl2, hardcodedHasZeroPoint = false).Forcing extreme zero points does produce failures, but they are not a kernel bug: the
M>1/AVX-512 path applies zero points through theABlockSum · QuantBBlkSumcorrection (QuantBBlkSum = -scale_b * zp), which cancels catastrophically in fp32 whenzpis far from the data's natural value. Evidence:zp=0(no correction term) → 0 failures,zp=10→ 828 failures, and failures also appear underCompFp32, which shares no AVX2 kernel. TheM=1path subtracts the zero point inline and is numerically better, so it is deliberately left in place rather than rerouted through block sums.What the issue did expose is a real coverage gap:
MlasQuantizeBlockwiseon the random test inputs always derives zero points near 8, so the full 0..15 range — and therefore the asymmetric dequantization — was effectively unverified. The new tests close that gap and were validated by fault injection into the AVX2M=1zero-point kernel (wrong nibble select → 25 failures; hardcodedzp=8→ 25 failures).Intel SDE was unavailable in this environment. If the reporter can share the failing caller, it is worth checking whether the kernel was invoked directly with unpacked B or un-rearranged scales rather than through
MlasQNBitGemmBatch, which overwritesQuantBScale/PackedQuantBData/QuantBBlkSumfrom the packed workspace.