Skip to content

Commit beb9b64

Browse files
Etienne PotThe dataclass_array Authors
authored andcommitted
Fix vmap for pytorch dataclass array
PiperOrigin-RevId: 861731648
1 parent a21b89b commit beb9b64

2 files changed

Lines changed: 27 additions & 8 deletions

File tree

dataclass_array/array_dataclass.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import dataclasses
2020
import functools
21+
import sys
2122
import typing
2223
from typing import Any, Callable, ClassVar, Generic, Iterator, Optional, Set, Tuple, Type, TypeVar, Union
2324

@@ -1120,14 +1121,7 @@ def full_shape(self) -> DcOrArrayT:
11201121
@functools.cached_property
11211122
def inner_shape(self) -> Shape:
11221123
"""Returns the the static shape resolved for the current value."""
1123-
# torch.func.vmap calls `tree_unflatten([0] * num_leaves)` internally,
1124-
# messing up shape inference.
1125-
if (
1126-
enp.lazy.has_torch
1127-
and isinstance(self.value, int)
1128-
and self.value == 0
1129-
):
1130-
return ()
1124+
11311125
if not self.inner_shape_non_static:
11321126
return ()
11331127
static_shape = self.full_shape[-len(self.inner_shape_non_static) :]
@@ -1167,6 +1161,14 @@ def is_value_missing(self) -> bool:
11671161
elif enp.array_spec.is_fake_array(self.value):
11681162
# `etree.spec_like`, Flax summary, ShapeDtypeStruct, ... compatibility
11691163
return True
1164+
# torch.func.vmap calls `tree_unflatten([0] * num_leaves)` internally.
1165+
elif (
1166+
enp.lazy.has_torch
1167+
and isinstance(self.value, int)
1168+
and self.value == 0
1169+
and _is_called_inside_torch_vmap()
1170+
):
1171+
return True
11701172
return False
11711173

11721174
@property
@@ -1194,6 +1196,22 @@ def broadcast_to(self, shape: Shape) -> DcOrArrayT:
11941196
return self.xnp.broadcast_to(self.value, final_shape)
11951197

11961198

1199+
def _is_called_inside_torch_vmap() -> bool:
1200+
"""Returns `True` if the current call is inside a `torch.func.vmap`."""
1201+
frame = sys._getframe(1) # pylint: disable=protected-access
1202+
1203+
while frame:
1204+
code = frame.f_code
1205+
if (
1206+
code.co_name == '_broadcast_to_and_flatten'
1207+
and code.co_filename.endswith('torch/utils/_pytree.py')
1208+
):
1209+
return True
1210+
frame = frame.f_back
1211+
1212+
return False
1213+
1214+
11971215
def _make_field_metadata(
11981216
field: dataclasses.Field[Any],
11991217
hints: dict[str, TypeAlias],

dataclass_array/array_dataclass_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ def _assert_common(p: dca.DataclassArray, shape: Shape, xnp: enp.NpModule):
262262
@pytest.mark.parametrize(
263263
'x, y, shape',
264264
[
265+
(0, 0, ()),
265266
(1, 2, ()),
266267
([1, 2], [3, 4], (2,)),
267268
([[1], [2]], [[3], [4]], (2, 1)),

0 commit comments

Comments
 (0)