Skip to content

Commit aa5247f

Browse files
committed
Use masked_fill_ for boolean-mask scalar assignments
Replace boolean-mask index assignments of the form ``tensor[mask] = scalar`` with ``Tensor.masked_fill_`` across camera/depth observation processing, the linear interpolation utility, the Shadow Hand feature extractor, the drone navigation observations, and the TacSL visuotactile renderer. ``masked_fill_`` performs the fill in a single fused kernel and avoids the ``nonzero``-based advanced-indexing path (and its device sync), which makes these GPU tensor operations more performant while preserving behavior.
1 parent 8b01020 commit aa5247f

10 files changed

Lines changed: 32 additions & 12 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Changed
2+
^^^^^^^
3+
4+
* Changed boolean-mask scalar assignments to use :meth:`torch.Tensor.masked_fill_`
5+
in :class:`~isaaclab.utils.interpolation.LinearInterpolation` and the camera
6+
image observation in :mod:`isaaclab.envs.mdp.observations` to avoid the
7+
``nonzero``-based advanced-indexing path and improve performance.

source/isaaclab/isaaclab/envs/mdp/observations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ def image(
425425
mean_tensor = torch.mean(images, dim=(1, 2), keepdim=True)
426426
images -= mean_tensor
427427
elif "distance_to" in data_type or "depth" in data_type:
428-
images[images == float("inf")] = 0
428+
images.masked_fill_(images == float("inf"), 0)
429429
elif "normals" in data_type:
430430
images = (images + 1.0) * 0.5
431431

source/isaaclab/isaaclab/utils/interpolation/linear_interpolation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def compute(self, q: torch.Tensor) -> torch.Tensor:
7575
# compute the weight as: (q_i - x_lb) / (x_ub - x_lb)
7676
weight = (q_1d - self._x[lower_bound]) / (self._x[upper_bound] - self._x[lower_bound])
7777
# If a point is out of bounds assign weight 0.0
78-
weight[upper_bound == lower_bound] = 0.0
78+
weight.masked_fill_(upper_bound == lower_bound, 0.0)
7979

8080
# Perform linear interpolation
8181
fq = self._y[lower_bound] + weight * (self._y[upper_bound] - self._y[lower_bound])
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Changed
2+
^^^^^^^
3+
4+
* Changed boolean-mask scalar assignments to use :meth:`torch.Tensor.masked_fill_`
5+
in the TacSL visuotactile renderer to avoid the ``nonzero``-based
6+
advanced-indexing path and improve performance.

source/isaaclab_contrib/isaaclab_contrib/sensors/tacsl_sensor/visuotactile_render.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def render(self, height_map: torch.Tensor) -> torch.Tensor:
175175
Rendered image tensor. Shape is (N, H, W, 3).
176176
"""
177177
height_map = height_map.clone()
178-
height_map[torch.abs(height_map) < 1e-6] = 0 # remove minor artifact
178+
height_map.masked_fill_(torch.abs(height_map) < 1e-6, 0) # remove minor artifact
179179
height_map = height_map * -1000.0
180180
height_map /= self.cfg.mm_per_pixel
181181

@@ -251,7 +251,7 @@ def _generate_normals(self, img: torch.Tensor) -> tuple[torch.Tensor, torch.Tens
251251
grad_mag_orig = torch.sqrt(dzdx**2 + dzdy**2)
252252
grad_mag = torch.arctan(grad_mag_orig) # seems that arctan is used as a squashing function
253253
grad_dir = torch.arctan2(dzdx, dzdy)
254-
grad_dir[grad_mag_orig == 0] = 0
254+
grad_dir.masked_fill_(grad_mag_orig == 0, 0)
255255

256256
# handle edges
257257
grad_mag = torch.nn.functional.pad(grad_mag[:, 1:-1, 1:-1], pad=(1, 1, 1, 1))
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Changed
2+
^^^^^^^
3+
4+
* Changed boolean-mask scalar assignments to use :meth:`torch.Tensor.masked_fill_`
5+
in the Shadow Hand feature extractor, the Cartpole camera environments, and the
6+
drone navigation observations to avoid the ``nonzero``-based advanced-indexing
7+
path and improve performance.

source/isaaclab_tasks/isaaclab_tasks/contrib/cartpole_showcase/cartpole_camera/cartpole_camera_env.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def _get_observations(self) -> dict:
5252
camera_data -= mean_tensor
5353
elif "depth" in self.cfg.tiled_camera.data_types:
5454
camera_data = self._tiled_camera.data.output[data_type]
55-
camera_data[camera_data == float("inf")] = 0
55+
camera_data.masked_fill_(camera_data == float("inf"), 0)
5656

5757
# fundamental spaces
5858
# - Box

source/isaaclab_tasks/isaaclab_tasks/contrib/drone_arl/mdp/observations.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ def __call__(self, env: ManagerBasedEnv, sensor_cfg: SceneEntityCfg, data_type:
196196

197197
if self.normalize:
198198
if self.data_type == "distance_to_image_plane":
199-
images[images == float("inf")] = 10.0
200-
images[images == -float("inf")] = 10.0
201-
images[images > 10.0] = 10.0
199+
images.masked_fill_(images == float("inf"), 10.0)
200+
images.masked_fill_(images == -float("inf"), 10.0)
201+
images.masked_fill_(images > 10.0, 10.0)
202202
images = images / 10.0
203-
images[images < 0.02] = -1.0
203+
images.masked_fill_(images < 0.02, -1.0)
204204
else:
205205
raise ValueError(f"Image data type: {self.data_type} not supported")
206206

source/isaaclab_tasks/isaaclab_tasks/core/cartpole/cartpole_direct_camera_env.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def _get_observations(self) -> dict:
113113
camera_data -= mean_tensor
114114
elif "depth" in self.cfg.tiled_camera.data_types:
115115
camera_data = self._tiled_camera.data.output[data_type]
116-
camera_data[camera_data == float("inf")] = 0
116+
camera_data.masked_fill_(camera_data == float("inf"), 0)
117117
elif "semantic_segmentation" in self.cfg.tiled_camera.data_types:
118118
camera_data = self._tiled_camera.data.output[data_type]
119119

source/isaaclab_tasks/isaaclab_tasks/core/shadow_hand/feature_extractor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def _preprocess_images(self, camera_output: dict[str, torch.Tensor]) -> torch.Te
231231
if dt == "rgb":
232232
img = img / 255.0
233233
elif dt == "depth":
234-
img[img == float("inf")] = 0
234+
img.masked_fill_(img == float("inf"), 0)
235235
img /= 5.0
236236
max_val = img.max()
237237
if max_val > 0:
@@ -262,7 +262,7 @@ def _save_images(self, camera_output: dict[str, torch.Tensor]):
262262
img = camera_output[dt].float()
263263
if dt == "depth":
264264
img = img.clone()
265-
img[img == float("inf")] = 0
265+
img.masked_fill_(img == float("inf"), 0)
266266
max_val = img.max()
267267
if max_val > 0:
268268
img = img / max_val

0 commit comments

Comments
 (0)