@@ -209,7 +209,7 @@ def copy_grouped_storage_metadata(dst: GroupedTensor, src: GroupedTensor) -> Non
209209 dst .nvfp4_e4m3_max = src .nvfp4_e4m3_max
210210 dst .scale_inv_dtype = src ._scale_inv_dtype
211211
212- def make_wrapper_like (src : GroupedTensor , requires_grad : bool ) -> GroupedTensor :
212+ def make_wrapper_like (src : GroupedTensor ) -> GroupedTensor :
213213 """Create a wrapper of the same type and tensor metadata as src."""
214214 out = torch .Tensor ._make_wrapper_subclass (
215215 type (src ),
@@ -218,7 +218,9 @@ def make_wrapper_like(src: GroupedTensor, requires_grad: bool) -> GroupedTensor:
218218 storage_offset = src .storage_offset (),
219219 dtype = src .dtype ,
220220 layout = src .layout ,
221- requires_grad = requires_grad ,
221+ # Autograd attaches the output's differentiable-view metadata after
222+ # __torch_dispatch__ returns.
223+ requires_grad = False ,
222224 device = src .device ,
223225 )
224226 copy_grouped_storage_metadata (out , src )
@@ -229,9 +231,18 @@ def make_wrapper_like(src: GroupedTensor, requires_grad: bool) -> GroupedTensor:
229231 src = args [0 ]
230232 if not isinstance (src , GroupedTensor ):
231233 raise TypeError (f"Expected GroupedTensor, got { type (src ).__name__ } " )
232- if func == torch .ops .aten .detach .default :
233- return make_wrapper_like (src , requires_grad = False )
234- return make_wrapper_like (src , requires_grad = src .requires_grad )
234+ return make_wrapper_like (src )
235+
236+ # The wrapper has no allocation of its own. Propagate CUDA allocator
237+ # stream tracking to every tensor that backs the grouped representation.
238+ if func == torch .ops .aten .record_stream .default :
239+ src , stream = args
240+ if not isinstance (src , GroupedTensor ):
241+ raise TypeError (f"Expected GroupedTensor, got { type (src ).__name__ } " )
242+ for tensor in src .get_data_tensors ():
243+ if tensor is not None and tensor .is_cuda :
244+ tensor .record_stream (stream )
245+ return None
235246
236247 # Parameter construction may invoke aten.expand on tensor subclasses.
237248 # Handle this explicitly so grouped parameters can be created safely.
@@ -246,7 +257,7 @@ def make_wrapper_like(src: GroupedTensor, requires_grad: bool) -> GroupedTensor:
246257 src_shape [i ] if dim == - 1 else dim for i , dim in enumerate (expanded_shape )
247258 )
248259 if normalized_shape == src_shape :
249- return make_wrapper_like (src , requires_grad = src . requires_grad )
260+ return make_wrapper_like (src )
250261 return super ().__torch_dispatch__ (func , types , args , kwargs )
251262
252263 # DDP and mcore use expand_as(self) to build a dummy autograd node and
@@ -259,7 +270,7 @@ def make_wrapper_like(src: GroupedTensor, requires_grad: bool) -> GroupedTensor:
259270 if other is src :
260271 return _GroupedIdentityFunc .apply (src )
261272 if tuple (other .shape ) == tuple (src .shape ):
262- return make_wrapper_like (src , requires_grad = src . requires_grad )
273+ return make_wrapper_like (src )
263274 return super ().__torch_dispatch__ (func , types , args , kwargs )
264275
265276 # Distributed optimizer flattens detached parameters via
@@ -270,6 +281,11 @@ def make_wrapper_like(src: GroupedTensor, requires_grad: bool) -> GroupedTensor:
270281 if not isinstance (src , GroupedTensor ):
271282 raise TypeError (f"Expected GroupedTensor, got { type (src ).__name__ } " )
272283 target_shape = tuple (args [1 ])
284+ # Autograd Functions that return an input unchanged create a
285+ # shape-preserving view to track the output alias. Preserve the
286+ # grouped layout and share its backing buffers in that case.
287+ if target_shape == tuple (src .shape ):
288+ return make_wrapper_like (src )
273289 if target_shape in ((- 1 ,), (src .numel (),)):
274290 if src .rowwise_data is not None :
275291 return src .rowwise_data .view (- 1 )
@@ -358,12 +374,7 @@ def maybe_update_inplace(arg, new_arg, schema_arg):
358374 new_kwargs = tree_map (maybe_unwrap , kwargs )
359375 return super ().__torch_dispatch__ (func , types , new_args , new_kwargs )
360376
361- @classmethod
362- def __torch_function__ (cls , func , types , args = (), kwargs = None ):
363- if kwargs is None :
364- kwargs = {}
365- # Do not force GroupedTensor on outputs.
366- return torch ._C ._disabled_torch_function_impl (func , types , args , kwargs )
377+ __torch_function__ = torch ._C ._disabled_torch_function_impl
367378
368379 def expand_as (self , other : torch .Tensor ) -> torch .Tensor :
369380 # pylint: disable=missing-function-docstring
0 commit comments