[blas][cublas] Support int8 inputs with float output in gemm_batch - #761
Open
zjin-lcf wants to merge 2 commits into
Open
[blas][cublas] Support int8 inputs with float output in gemm_batch#761zjin-lcf wants to merge 2 commits into
zjin-lcf wants to merge 2 commits into
Conversation
cuBLAS reaches this combination through cublasGemmStridedBatchedEx and cublasGemmBatchedEx, which already accept the datatypes the existing launchers forward, so the column-major buffer, USM strided and USM group entry points only needed routing to the implementation instead of throwing unimplemented. The int32 output combination stays unimplemented because cuBLAS produces it only under CUBLAS_COMPUTE_32I, which takes int32 alpha and beta, whereas oneMath specifies float scalars. A float output accumulated from int8 inputs is rounded at the magnitude of the terms summed rather than at the magnitude of the output entry, so an entry whose sum cancels cannot meet any relative bound. The shared checker takes an optional absolute tolerance, defaulted to zero so that existing callers are unaffected, and the int8-to-float gemm_batch tests pass eps times k * 128 * 128, an upper bound on the accumulated magnitude sum|a*b|. Int8Int8SinglePrecisionErrorModel covers that path with fixed data whose leading rows and columns cancel exactly. Co-authored-by: Cursor <cursoragent@cursor.com>
…del bound An entry whose terms and stored C value are all zero gives a zero model bound, which the reported usage ratio would divide by. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Enables the
(int8, int8, float, float)gemm_batchcombination on the cuBLAS backend for the column-major layout, in all three entry points: buffer strided, USM strided, and USM group.No new implementation code was required.
cublasGemmStridedBatchedExandcublasGemmBatchedExalready accept the datatypes that the existing launchers forward, so this combination only needed to be routed togemm_batch_implinstead of to the macro that throwsunimplemented.(int8, int8, int32, float)remains unimplemented, and the reason is now recorded in a comment next to it: cuBLAS produces an int32 output only underCUBLAS_COMPUTE_32I, which requires int32alphaandbeta, whereas oneMath specifies float scalars for this combination. Row-major remains unimplemented as before.Test tolerance
Enabling the type combination alone makes the existing
gemm_batchtests fail on a handful of output entries, and the cause is the tolerance model rather than the backend.A float output accumulated from int8 inputs is rounded at the magnitude of the terms being summed,
|alpha| * sum|a*b|, which for int8 data runs orders of magnitude above the output entries themselves. Where the products mostly cancel, the entry is far smaller than the terms that produced it, and no relative bound can cover it: this is ordinary cancellation, not a backend defect. Verified against an exactint64reference, the largest observed discrepancy is well inside what single precision permits for an accumulation of that size.The shared checker therefore takes an optional absolute tolerance:
check_equalacceptsabs_bound, defaulted to0.0and threaded throughcheck_equal_matrixandcheck_almost_equal_matrix. With the default,abs_boundcannot loosen anything, so all existing callers behave exactly as before. The integral overload accepts and ignores it, since an integer result must still match exactly.gemm_batchtests computeeps * |alpha| * k * 128 * 128underif constexpr, so only the int8-to-float instantiation is affected. Since every int8 magnitude is below 128,k * 128 * 128is an upper bound onsum|a*b|. The relative bound stays at10 * k * eps.The constant in this tolerance is calibrated from measurements rather than derived, so it is a scale-based bound supported by evidence. For what it is worth, it sits far below the deterministic
gamma_k * sum|a*b|worst case, and the entries that rely on it use only a few percent of it.Regression test
Int8Int8SinglePrecisionErrorModelcovers this path deterministically. Test sizes and data come from an in-test generator rather thanstd::rand(), so it does not depend on the order the tests run in, and the expected result is accumulated exactly in integers, so it does not depend on the reference BLAS either. The leading rows of A and columns of B are built from triples whose products are5x,-3xand-2x: their exact dot product is zero while the terms summed stay large, and no ratio is a power of two, so rounding does not cancel along with the terms. Each entry is checked against the relative and absolute bounds, and against the accumulation error model the absolute bound is calibrated from.On the machine below the test reports 122 entries missing the relative bound, 120 of them the constructed cancelling ones, using 18% of the absolute tolerance. Shrinking that tolerance by 1000x makes the test fail, so the assertion is doing work rather than passing vacuously.
One caveat worth flagging for reviewers: shapes are not interchangeable in this test, because a backend may accumulate a given shape exactly, in which case no tolerance is needed and nothing exercises this one. The test prints how many entries relied on the absolute bound so that this stays visible.
Fixes #506
Checklist
All Submissions
Built with the DPC++ compiler and the cuBLAS backend, run on an NVIDIA A100-SXM4-40GB.
gemm_batchtests, compile-time and run-time dispatch:The skips are the row-major and other unimplemented cuBLAS combinations, unchanged by this PR.
Wider BLAS suite, both dispatch modes:
Complex double level 1 tests are excluded because they crash identically on this setup with and without these changes, in an untouched build of
developas well, so the failure predates this PR and is unrelated to it.Because the suite does not seed
std::rand(), test sizes depend on execution order, so the filtered and wider runs above exercise two different draws of sizes and data.New features
gemm_batchtests already cover this type combination and now run against the cuBLAS backend rather than skipping;Int8Int8SinglePrecisionErrorModelwas added for the tolerance itself.Bug fixes
Made with Cursor