[PyTorch][torch.compile] Add TensorProto mechanism#3153
Conversation
Greptile SummaryThis PR introduces
Confidence Score: 5/5Safe to merge. Core allocation and flatten/unflatten paths are exercised by comprehensive CPU smoke tests including fullgraph compile checks. Structural parity tests validate that Python-allocated tensors match C++ make_empty in buffer layout and kernel output. The only outstanding items are a private PyTorch API import and implicit stride forwarding via **kwargs, both non-blocking style issues. The fake forward/backward impls are intentionally incomplete and cannot be called incorrectly in the current state. transformer_engine/pytorch/dynamo/tensor_proto.py (private API import) and transformer_engine/pytorch/quantized_tensor.py (tensor_unflatten stride forwarding) are worth a second look before the follow-up custom-op registration PR lands. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User as User / torch.compile
participant TP as TensorProto
participant Q as Quantizer
participant SR as _STORAGE_REGISTRY
participant S as QuantizedTensorStorage
User->>TP: TensorProto(shape, dtype, quantizer)
TP->>Q: copy() quantizer
User->>TP: create_tensor()
TP->>Q: create_metadata(shape, dtype)
Q-->>TP: "ctx {cls: qualname, nontensor_kwargs}"
TP->>Q: alloc_tensors(shape, device)
Q->>Q: _describe_buffers(shape)
Q-->>TP: "{attr: torch.empty(...)}"
TP->>TP: inner_names() ordered attr list
TP->>SR: _STORAGE_REGISTRY[ctx[cls]]
SR-->>TP: storage_cls
TP->>S: storage_cls.__tensor_unflatten__(inner, ctx, shape, stride)
S-->>User: QuantizedTensor / QuantizedTensorStorage
User->>S: __tensor_flatten__()
S->>S: _FLATTEN_TENSOR_BUFFERS present attrs
S->>S: _flatten_nontensor_kwargs() via get_metadata()
S-->>User: (names, ctx)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User as User / torch.compile
participant TP as TensorProto
participant Q as Quantizer
participant SR as _STORAGE_REGISTRY
participant S as QuantizedTensorStorage
User->>TP: TensorProto(shape, dtype, quantizer)
TP->>Q: copy() quantizer
User->>TP: create_tensor()
TP->>Q: create_metadata(shape, dtype)
Q-->>TP: "ctx {cls: qualname, nontensor_kwargs}"
TP->>Q: alloc_tensors(shape, device)
Q->>Q: _describe_buffers(shape)
Q-->>TP: "{attr: torch.empty(...)}"
TP->>TP: inner_names() ordered attr list
TP->>SR: _STORAGE_REGISTRY[ctx[cls]]
SR-->>TP: storage_cls
TP->>S: storage_cls.__tensor_unflatten__(inner, ctx, shape, stride)
S-->>User: QuantizedTensor / QuantizedTensorStorage
User->>S: __tensor_flatten__()
S->>S: _FLATTEN_TENSOR_BUFFERS present attrs
S->>S: _flatten_nontensor_kwargs() via get_metadata()
S-->>User: (names, ctx)
Reviews (13): Last reviewed commit: "Merge branch 'main' of https://github.co..." | Re-trigger Greptile |
9e78a6c to
50c11cd
Compare
Squashed PR #8 (tensor_proto_mechanism) onto the rebased base. Adds TensorProto (pure-Python, torch.compile-traceable quantized-tensor allocation via Quantizer.alloc_tensors + storage __tensor_flatten__/__tensor_unflatten__), Linear fake fwd/bwd impls for the custom-op path, and tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
The cached FP8 weight is the same tensor returned as new_weight_workspace (cache miss) or passed in as weight_workspace (cache hit). A custom op may not return a tensor that aliases an input or another return, so mark those slots and reconstruct wt_save in _linear_setup_ctx instead of saving it twice. Mirrored in the fake impl so the saved-slot layout matches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
NVFP4Quantizer._describe_buffers grouped each amax right after its scale (per-usage), diverging from NVFP4TensorStorage._FLATTEN_TENSOR_BUFFERS (amax buffers last). The order is functionally irrelevant (buffers are consumed by name in alloc_tensors and reordered in TensorProto.inner_names), but aligning it makes describe/flatten agree and fixes test_to_tensor_proto_quantized[nvfp4]. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
…upport - TensorProto.inner_names now raises if the quantizer describes buffer(s) absent from the storage's _FLATTEN_TENSOR_BUFFERS, instead of silently appending them. - Gate the nvfp4 proto-quantizer param on nvfp4_available so it skips on hardware without NVFP4 support rather than failing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
…escribe_buffers Access NVFP4Quantizer @staticmethods (convert_shape_for_fp4, get_columnwise_shape) via the class instead of the instance. Under torch.compile, instance access of a @staticmethod on a value-opaque object crashes Dynamo guard generation with "'function' object has no attribute '__func__'" (pytorch/pytorch#182741). Temporary workaround until the PyTorch-side fix lands. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
ff48e52 to
e36cf6d
Compare
The union is intentional: fields may carry bare QuantizedTensorStorage objects (internal-quantizer optimization), and the annotation is introspected in the follow-up custom-op PR to build the op schema with flatten/unflatten slots. Also note the size()/.shape asymmetry and how TensorProto handles it. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Make .shape valid on bare storages (derived from size()), so Tensor, QuantizedTensor, bare storage and TensorProto all expose the same attribute. Wrapper subclasses defer to the native TensorBase.shape. Simplifies the shape fallback in to_tensor_proto. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: build the same quantized tensor via make_empty (C++, tex.create_empty_quantized_tensor) and via the Python primitives (_describe_buffers + create_metadata + alloc_tensors + __tensor_unflatten__) and check structural parity (class, buffer set, per-buffer shape/dtype/device, flatten context) and functional parity (the real quantize kernel writes bit-identical results into both, dequantize matches), across quantizer families x rowwise/columnwise x wrapper/internal. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: the change stands on its own as a correctness fix; drop the detailed (and imprecise) fake-impl/cudagraph justification. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: wt_save is known non-None past the first branch, so 'X is not None and wt_save is X' reduces to 'wt_save is X'. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: replace the local _contiguous_stride helper with the torch one (stable at this path since v1.13); it also matches the ATen contiguous-stride convention for zero-size dims and handles SymInts. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: a silent no-op diverges from the real object's behavior (plain torch.Tensor has no update_usage), which is exactly the class of fake/real mismatches the proto is meant to avoid. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: after the QuantizedTensorStorage.shape property the storage and plain-tensor paths differed only in getattr fallbacks (dtype/_dtype, _quantizer), which work uniformly for all input kinds; drop the isinstance branch and the local import it needed. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Address review: the saved_weight slot is unconditionally aliased to the weight parameter in forward, so it is never None in backward. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
…to tensor_proto_mechanism
| # machine-read when the args bag becomes a torch.compile custom op (follow-up | ||
| # PR): such fields get flatten/unflatten slots so a bare storage can cross the |
There was a problem hiding this comment.
Note: We will update this comment as part of the custom op PR.
Description
This PR introduces
TensorProto— a data-free prototype of a tensor (or quantized tensor) that captures everything needed to reason about and rebuild a tensor without holding any storage: its logicalshape/dtypeand, for quantized tensors, the value-opaquequantizerdefining the layout.The key property is that
TensorProto.create_tensor()materializes a quantized tensor purely in Python (viaQuantizer.alloc_tensors+ the storage's__tensor_unflatten__), so it traces undertorch.compile(fullgraph=True)with no graph break — unlikemake_empty, which goes through the opaque C++tex.create_empty_quantized_tensor. This is the foundation for writingtorch.librarycustom-op fake implementations of quantized ops.This builds on the value-opaque quantizer work (so a
TensorProtois itself safe to treat as a compile-time constant).Type of change
Changes
dynamo.py: AddTensorProtodataclass (shape,dtype,quantizer,requires_grad,device) withis_quantized,inner_names(),create_metadata()andcreate_tensor(), plus ato_tensor_proto()helper that builds a proto from a plaintorch.Tensoror aQuantizedTensorStorage/QuantizedTensor.quantized_tensor.py:__tensor_flatten__/__tensor_unflatten__) toQuantizedTensorStorage, driven by a per-class_FLATTEN_TENSOR_BUFFERSdeclaration of(attribute_name, constructor_kwarg)pairs._STORAGE_REGISTRY(populated via__init_subclass__) so__tensor_unflatten__can resolve a concrete storage/wrapper class from its qualname inside an FX graph.Quantizer:alloc_tensors,create_metadata, and the opt-in overrides_describe_buffers,_storage_scalars,_resolve_storage_cls.Float8CurrentScalingQuantizer,MXFP8QuantizerandFloat8BlockQuantizer._FLATTEN_TENSOR_BUFFERSforFloat8TensorStorage,MXFP8TensorStorageandFloat8BlockwiseQTensorStorage.ops/basic/basic_linear.py: Add allocation-free_functional_forward_fake/_functional_backward_fakethat operate onTensorProtoand return output/gradient protos, as a basis for custom-op fake impls (single-device only; TP/SP shape effects not yet modeled).tests/pytorch/test_tensor_proto.py(CPU smoke tests for_describe_buffers/alloc_tensors/create_metadata, flatten round-trip, andto_tensor_proto) andtorch.compilefullgraph tests intest_torch_compile.py.Checklist: