mirror of
https://github.com/pytorch/pytorch.git
synced 2026-10-28 18:56:51 +08:00
## Human Note Add e5m3fnu some subtelty and leaned closer to e8m0 to match our current unsighed behavior but room for a lil debate ## Agent Report # Report: torch.float8_e5m3fnu (UE5M3) shell dtype ## Result `torch.float8_e5m3fnu` works as a shell dtype on CPU and CUDA: `ScalarType::Float8_e5m3fnu` (enum value 47, appended after `BComplex32`), Python dtype, abbreviation `f8e5m3fnu`, storage and serialization, casts to and from float32/float16/bfloat16 (and the other types `copy_` dispatches), `empty`/`zeros`/`full`/`fill_`, `view(uint8)`, cross-device copy, indexing/`index_select`/`cat`, printing, `.item()`/`tolist()`/`torch.tensor(..., dtype=)`, and `torch.finfo`. It has no arithmetic kernels, no type promotion (raises, like the other float8 types), no DLPack support (raises `BufferError`), and no `index_put` (matches e8m0). ## Format and cast semantics (confirmed by Driss) - Decode: E5 (bias 15) M3, no sign bit, subnormals (min 2^-17), `0xF8..0xFE` finite (65536..114688), `0xFF` the only NaN. 1.0 = `0x78`. - Encode (fp32 → e5m3fnu): round |x| to nearest, ties to even. **The sign is ignored, as in e8m0's encoder** (-1 → `0x78`; this also matches Rubin `cvt`). **Finite overflow and ±inf saturate to 114688** (matches e4m3fn after #178817). NaN → NaN; -0.0 → 0. - Hardware/CuTe scale producers round toward +inf (`cvt.rp`); generic `.to()` keeps RNE like the other float8 types. - Name: `float8_e5m3fnu` follows the suffix convention in #146414 (f = no inf, n = non-IEEE NaN, u = unsigned), like `float8_e8m0fnu`. ## Changes - New `torch/headeronly/util/Float8_e5m3fnu.h` (type, encode/decode, `numeric_limits`) + `c10/util/Float8_e5m3fnu.{h,cpp}` shim. - Enum/macro lists: `torch/headeronly/core/ScalarType.h` (`AT_FORALL_SCALAR_TYPES_WITH_COMPLEX`, `..._AND_QINTS`, `AT_FORALL_FLOAT8_TYPES`), `torch/headeronly/core/Dispatch_v2.h` (`AT_FLOAT8_TYPES`, `AT_ALL_SCALAR_TYPES_WITH_COMPLEX`), `c10/core/ScalarType.{h,cpp}` (`isFloat8Type`, `isSignedType`, names). - Kernels/plumbing following e8m0: `headeronly/util/TypeCast.h`, `OpMathType.h`, `ScalarOps.cpp`, `TensorCompare.cpp`, `cpu/FillKernel.cpp`, `cuda/Copy.cu`, `cuda/jit_utils.h`, `DLConvertor.cpp` (explicit unsupported), `XPUGuardImpl.h`, `python_scalars.h`. - Python/codegen: `torch/_tensor_str.py`, `torch/storage.py`, `tools/pyi/gen_pyi.py`, `torchgen`, docs table, `torch/header_only_apis.txt`. - Tests: `test/quantization/core/experimental/test_floatx.py` (added to the generic float8 lists + new `TestFloat8E5M3FNU`), `test/test_torch.py` dtype inventory pins, `test/cpp/aoti_abi_check/*` counts/lists + a `Float8_e5m3fnu` unit test. ## Validation - Rebuilt with `TORCH_CUDA_ARCH_LIST=10.3a` (GB300). - `pytest test/quantization/core/experimental/test_floatx.py` + the two `test_torch.py` dtype pins: 152 passed (after the sign-ignoring rebuild), CPU + CUDA. Includes an exhaustive decode check of all 256 codes against a LUT built from the format definition, and an encode check from fp32/fp16/bf16 (every code, every midpoint/tie, their fp32 neighbors, subnormal/zero tie, overflow, inf, negatives, -0, NaN) against an independent float64 nearest-code search. - Standalone g++ check of the header encoder/decoder vs the brute-force reference: 0 mismatches. - `pytest test_type_info.py test_dlpack.py test_type_promotion.py test_serialization.py test_torch.py -k "dtype or float8 or finfo or promot or storage or dlpack"`: 2412 passed after updating the two dtype inventory tests. - Not run: C++ `aoti_abi_check` tests (`BUILD_TEST=0` locally), lintrunner (not initialized; formatted with ruff 0.14.4 and manual clang-format-style alignment). ## Deferred Stable ABI / AOTI shim dtype getters, `torch/_export` serde schema (needs a schema version bump), inductor dtype maps, `_scaled_mm` / `F.scaled_mm` UE5M3 scale-format dispatch, NCCL dtype allowlists, ONNX. ## Open questions None on semantics. The internal paste (px/p/dZMZZ) is still unread. <details> <summary>Agent Worklog</summary> # Worklog: torch.float8_e5m3fnu (UE5M3) shell dtype Base: `origin/main` `f23af85b68f`. No STACK_CONTEXT.md → conventional PR flow. ## Touch list (from `git grep -i float8_e8m0fnu` + #147466 + float4_e2m1fn_x2) ### In scope (shell dtype) - New `torch/headeronly/util/Float8_e5m3fnu.h` (struct, encode/decode, `numeric_limits`), c10 shims `c10/util/Float8_e5m3fnu{.h,-inl.h,.cpp}`. - `torch/headeronly/core/ScalarType.h`: include; append `Float8_e5m3fnu /* 47 */` after `BComplex32 /* 46 */`; `AT_FORALL_SCALAR_TYPES_WITH_COMPLEX` (Scalar ctor, `data_ptr<T>`); `AT_FORALL_FLOAT8_TYPES`. - `torch/headeronly/core/Dispatch_v2.h`: `AT_FLOAT8_TYPES`, `AT_ALL_SCALAR_TYPES_WITH_COMPLEX`. Through `AT_FLOAT8_TYPES` this gives copy (CPU), cat, index/index_put, fill (CUDA), where/eq, scalar ops, finfo (TypeInfo.cpp), factories. - `torch/headeronly/util/TypeCast.h` complex<Half>/complex<BFloat16> inter-type casts; `c10/util/TypeCast.h` include. - `c10/core/ScalarType.h` (include, `isFloat8Type`, `isSignedType`), `c10/core/ScalarType.cpp` (Python name, abbreviation `f8e5m3fnu`). Promotion rejected via `isFloat8Type`. - `aten/src/ATen/OpMathType.h`, `ScalarOps.cpp`, `native/TensorCompare.cpp` (`is_fp8_type_without_inf`), `native/cpu/FillKernel.cpp`, `native/cuda/Copy.cu`, `native/cuda/jit_utils.h`. - `c10/xpu/impl/XPUGuardImpl.h` capability bit (mirrors e8m0). - `torch/csrc/utils/python_scalars.h` (`.item()`, `tolist`, `torch.tensor`). - Python: `torch/_tensor_str.py` (printing via float), `torch/storage.py` (`_new_dtypes`, serialization), `tools/pyi/gen_pyi.py`, `torchgen/api/types/types.py`, `torchgen/model.py`, `torch/_inductor/codegen/cpp_utils.py` / `torch/_inductor/utils.py` triton dtype map (u8 fallback), `docs/source/tensor_attributes.md`, `torch/header_only_apis.txt`. ### Deferred / follow-up (not needed for a shell dtype; list in PR) - DLPack: no `kDLFloat8_e5m3fnu` code in DLPack spec → unsupported (same as many others). - Stable ABI / AOTI shims (`torch_dtype_*`, `aoti_torch_dtype_*`, `stableivalue_conversions.h`), versioned API; e8m0 added those later. - `torch/_export/serde` schema enum (needs schema version bump), `torch/nativert/graph/TensorMeta.cpp`. - `_scaled_mm` / `F.scaled_mm` UE5M3 scale-format dispatch (cuBLASLt/CUTLASS), `_meta_registrations`, inductor lowerings, NCCL dtype allowlists, ONNX. ## Design questions (need Driss's decision; defaults chosen so work can proceed) Format: unsigned, E5 (bias 15) M3, subnormals, no inf, 0xFF = NaN; 0xF8..0xFE finite (65536..114688). Decode is unambiguous. 1. **Rounding (fp32 → e5m3fnu)**: default RNE, like every other float8 `.to()` and e8m0. Hardware scale producers use round-toward-+inf (`cvt.rp`); that belongs in quantization helpers, not generic casting. 2. **Overflow (|x| > 114688)**: options are saturate to 114688 or NaN. Default: **saturate** finite values, matching e4m3fn after #178817 (`9deaf8dfd75`, finite overflow → max). `+inf` → also saturate (e4m3fn does the same). NaN → 0xFF. - RNE detail: 118784 (midpoint 114688/122880) ties to 114688 (even mantissa) either way. 3. **Negative inputs**: options are NaN, |x| (what e8m0 does today, since its encoder drops the sign bit, and what Rubin `cvt` does), or 0. Default: **NaN** for x < 0 (including -inf); -0.0 → +0 (0x00). Rationale: silently dropping the sign in a generic cast hides bugs; a scale producer can call `.abs()`. 4. **Name**: `torch.float8_e5m3fnu` (consistent with `float8_e8m0fnu` and the `fnu` suffix; matches CuTe `FloatNV8E5M3FNU`). Abbreviation `f8e5m3fnu`. 5. **Scope**: shell dtype only; `_scaled_mm` UE5M3 dispatch is a follow-up. Open: internal paste https://www.internalfb.com/intern/px/p/dZMZZ unread; may change 2/3. ## Log - 2026-10-16: built touch list, wrote plan. - 2026-10-16: implemented the in-scope touch list (see `git diff --stat`). Encoder/decoder validated standalone with g++ against a brute-force LUT reference (all 256 codes, every midpoint and its fp32 neighbors, specials): 0 mismatches (`pytorch/agent_space/enc.cpp`). - Tests: added `float8_e5m3fnu` to `FLOAT8_DTYPES`/`CUDA_FLOAT8_DTYPES` in `test/quantization/core/experimental/test_floatx.py` (generic zeros/special-numbers/promotion/empty/print/finfo/cat/save-load) plus `TestFloat8E5M3FNU` (exhaustive decode, encode from fp32/fp16/bf16 vs independent LUT search, shell ops, finfo, promotion/DLPack errors). C++ ABI tests (`test/cpp/aoti_abi_check`) counts/lists updated; not built locally (`BUILD_TEST=0`). - Build pitfall: session env had `TORCH_CUDA_ARCH_LIST=10.0a`; GB300 is sm_103 and the prior build was `sm_103a`. Killed my build, set `TORCH_CUDA_ARCH_LIST:STRING=10.3a` in `build/CMakeCache.txt`, removed `build/nccl*`, rebuilt with `TORCH_CUDA_ARCH_LIST=10.3a`. - 2026-10-16: rebuild OK (sm_103a, 16 min). `test/quantization/core/experimental/test_floatx.py`: 150 passed (CPU + CUDA GB300). First run failed only because the test used `index_put`, which is intentionally not enabled for e8m0/e5m3fnu (accumulate concern, #113663); replaced with `index_select`. - Broad check (`test_type_info.py test_dlpack.py test_type_promotion.py test_serialization.py test_torch.py -k "dtype or float8 or finfo or promot or storage or dlpack"`): 2410 passed; 2 failures were `test_torch.py` dtype inventory pins (`test_dtype_abbr`, `test_get_all_dtypes`), updated → pass. - Waiting on Driss for design decisions 2 (overflow) and 3 (negatives); both live in `fp8e5m3fnu_from_fp32_value` and the reference in `_e5m3fnu_encode_reference`. - 2026-10-16: Driss decided: (1) saturate on overflow OK, (2) negatives follow e8m0 (sign ignored → encode |x|; -inf saturates), (3) RNE OK, (4) name OK if it follows the #146414 suffix convention (it does: f/n/u). Changed the encoder and the test reference; standalone check 0 mismatches; rebuilt (13 min); test_floatx + dtype pins 152 passed CPU+CUDA. Spot check: [-1, -3, -2e5, -inf, -0, nan] → [0x78, 0x84, 0xFE, 0xFE, 0x00, 0xFF] on CPU and CUDA. </details> --- *This PR was generated by [ptq](https://github.com/drisspg/pt_job_queue) with human review.* Pull Request resolved: https://github.com/pytorch/pytorch/pull/201269 Approved by: https://github.com/vkuzo, https://github.com/slayton58