Skip to content

Commit e91a431

Browse files
Toni-SMkellyguo11
andauthored
Replaces TensorDict with native dictionary (isaac-sim#1348)
# Description Remove TensorDict usage from Isaac Lab ## Type of change - Breaking change... for those ones using TensorDict specific API such as `camera.data.output.to_dict()` or `camera.data.output.sorted_keys` ## Screenshots Before ![Screenshot from 2024-10-30 12-45-06](https://github.com/user-attachments/assets/2dc0e827-3e12-4ae9-849e-e9f75c718157) After ![Screenshot from 2024-10-30 16-04-35](https://github.com/user-attachments/assets/715b6cb0-9f87-4938-8dbd-5c56203cb90e) ## Checklist - [x] I have run the [`pre-commit` checks](https://pre-commit.com/) with `./isaaclab.sh --format` - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] I have updated the changelog and the corresponding version in the extension's `config/extension.toml` file - [x] I have added my name to the `CONTRIBUTORS.md` or my name already exists there <!-- As you go through the checklist above, you can mark something as done by putting an x character in it For example, - [x] I have done this task - [ ] I have not done this task --> --------- Co-authored-by: Kelly Guo <[email protected]>
1 parent ba46ee5 commit e91a431

File tree

11 files changed

+47
-46
lines changed

11 files changed

+47
-46
lines changed

source/extensions/omni.isaac.lab/config/extension.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
# Note: Semantic Versioning is used: https://semver.org/
4-
version = "0.27.11"
4+
version = "0.27.12"
55

66
# Description
77
title = "Isaac Lab framework for Robot Learning"

source/extensions/omni.isaac.lab/docs/CHANGELOG.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Changelog
22
---------
33

4+
0.27.12 (2024-01-04)
5+
~~~~~~~~~~~~~~~~~~~
6+
7+
Removed
8+
^^^^^^^
9+
10+
* Removed TensorDict usage in favor of Python dictionary in sensors
11+
12+
413
0.27.11 (2024-10-31)
514
~~~~~~~~~~~~~~~~~~~~
615

source/extensions/omni.isaac.lab/omni/isaac/lab/sensors/camera/camera.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import re
1010
import torch
1111
from collections.abc import Sequence
12-
from tensordict import TensorDict
1312
from typing import TYPE_CHECKING, Any, Literal
1413

1514
import carb
@@ -156,7 +155,7 @@ def __str__(self) -> str:
156155
# message for class
157156
return (
158157
f"Camera @ '{self.cfg.prim_path}': \n"
159-
f"\tdata types : {self.data.output.sorted_keys} \n"
158+
f"\tdata types : {list(self.data.output.keys())} \n"
160159
f"\tsemantic filter : {self.cfg.semantic_filter}\n"
161160
f"\tcolorize semantic segm. : {self.cfg.colorize_semantic_segmentation}\n"
162161
f"\tcolorize instance segm. : {self.cfg.colorize_instance_segmentation}\n"
@@ -497,7 +496,7 @@ def _update_buffers_impl(self, env_ids: Sequence[int]):
497496
self._update_poses(env_ids)
498497
# -- read the data from annotator registry
499498
# check if buffer is called for the first time. If so then, allocate the memory
500-
if len(self._data.output.sorted_keys) == 0:
499+
if len(self._data.output) == 0:
501500
# this is the first time buffer is called
502501
# it allocates memory for all the sensors
503502
self._create_annotator_data()
@@ -552,7 +551,7 @@ def _create_buffers(self):
552551
# lazy allocation of data dictionary
553552
# since the size of the output data is not known in advance, we leave it as None
554553
# the memory will be allocated when the buffer() function is called for the first time.
555-
self._data.output = TensorDict({}, batch_size=self._view.count, device=self.device)
554+
self._data.output = {}
556555
self._data.info = [{name: None for name in self.cfg.data_types} for _ in range(self._view.count)]
557556

558557
def _update_intrinsic_matrices(self, env_ids: Sequence[int]):

source/extensions/omni.isaac.lab/omni/isaac/lab/sensors/camera/camera_data.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import torch
77
from dataclasses import dataclass
8-
from tensordict import TensorDict
98
from typing import Any
109

1110
from omni.isaac.lab.utils.math import convert_camera_frame_orientation_convention
@@ -47,7 +46,7 @@ class CameraData:
4746
Shape is (N, 3, 3) where N is the number of sensors.
4847
"""
4948

50-
output: TensorDict = None
49+
output: dict[str, torch.Tensor] = None
5150
"""The retrieved sensor data with sensor types as key.
5251
5352
The format of the data is available in the `Replicator Documentation`_. For semantic-based data,

source/extensions/omni.isaac.lab/omni/isaac/lab/sensors/camera/tiled_camera.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import numpy as np
1010
import torch
1111
from collections.abc import Sequence
12-
from tensordict import TensorDict
1312
from typing import TYPE_CHECKING, Any
1413

1514
import carb
@@ -106,7 +105,7 @@ def __str__(self) -> str:
106105
# message for class
107106
return (
108107
f"Tiled Camera @ '{self.cfg.prim_path}': \n"
109-
f"\tdata types : {self.data.output.sorted_keys} \n"
108+
f"\tdata types : {list(self.data.output.keys())} \n"
110109
f"\tsemantic filter : {self.cfg.semantic_filter}\n"
111110
f"\tcolorize semantic segm. : {self.cfg.colorize_semantic_segmentation}\n"
112111
f"\tcolorize instance segm. : {self.cfg.colorize_instance_segmentation}\n"
@@ -372,7 +371,7 @@ def _create_buffers(self):
372371
(self._view.count, self.cfg.height, self.cfg.width, 1), device=self.device, dtype=torch.int32
373372
).contiguous()
374373

375-
self._data.output = TensorDict(data_dict, batch_size=self._view.count, device=self.device)
374+
self._data.output = data_dict
376375
self._data.info = dict()
377376

378377
def _tiled_image_shape(self) -> tuple[int, int]:

source/extensions/omni.isaac.lab/omni/isaac/lab/sensors/ray_caster/ray_caster_camera.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import torch
99
from collections.abc import Sequence
10-
from tensordict import TensorDict
1110
from typing import TYPE_CHECKING, ClassVar, Literal
1211

1312
import omni.isaac.core.utils.stage as stage_utils
@@ -347,7 +346,7 @@ def _create_buffers(self):
347346
self._data.image_shape = self.image_shape
348347
# -- output data
349348
# create the buffers to store the annotator data.
350-
self._data.output = TensorDict({}, batch_size=self._view.count, device=self.device)
349+
self._data.output = {}
351350
self._data.info = [{name: None for name in self.cfg.data_types}] * self._view.count
352351
for name in self.cfg.data_types:
353352
if name in ["distance_to_image_plane", "distance_to_camera"]:

source/extensions/omni.isaac.lab/test/sensors/test_camera.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def test_camera_init(self):
121121
# update camera
122122
camera.update(self.dt)
123123
# check image data
124-
for im_data in camera.data.output.to_dict().values():
124+
for im_data in camera.data.output.values():
125125
self.assertEqual(im_data.shape, (1, self.camera_cfg.height, self.camera_cfg.width, 1))
126126

127127
def test_camera_init_offset(self):
@@ -228,7 +228,7 @@ def test_multi_camera_init(self):
228228
cam_2.update(self.dt)
229229
# check image data
230230
for cam in [cam_1, cam_2]:
231-
for im_data in cam.data.output.to_dict().values():
231+
for im_data in cam.data.output.values():
232232
self.assertEqual(im_data.shape, (1, self.camera_cfg.height, self.camera_cfg.width, 1))
233233

234234
def test_multi_camera_with_different_resolution(self):
@@ -705,7 +705,7 @@ def test_throughput(self):
705705
with Timer(f"Time taken for writing data with shape {camera.image_shape} "):
706706
# Pack data back into replicator format to save them using its writer
707707
rep_output = {"annotators": {}}
708-
camera_data = convert_dict_to_backend(camera.data.output[0].to_dict(), backend="numpy")
708+
camera_data = convert_dict_to_backend({k: v[0] for k, v in camera.data.output.items()}, backend="numpy")
709709
for key, data, info in zip(camera_data.keys(), camera_data.values(), camera.data.info[0].values()):
710710
if info is not None:
711711
rep_output["annotators"][key] = {"render_product": {"data": data, **info}}

source/extensions/omni.isaac.lab/test/sensors/test_ray_caster_camera.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_camera_init(self):
129129
# update camera
130130
camera.update(self.dt)
131131
# check image data
132-
for im_data in camera.data.output.to_dict().values():
132+
for im_data in camera.data.output.values():
133133
self.assertEqual(
134134
im_data.shape, (1, self.camera_cfg.pattern_cfg.height, self.camera_cfg.pattern_cfg.width, 1)
135135
)
@@ -147,7 +147,7 @@ def test_camera_resolution(self):
147147
self.sim.step()
148148
camera.update(self.dt)
149149
# access image data and compare shapes
150-
for im_data in camera.data.output.to_dict().values():
150+
for im_data in camera.data.output.values():
151151
self.assertTrue(
152152
im_data.shape == (1, self.camera_cfg.pattern_cfg.height, self.camera_cfg.pattern_cfg.width, 1)
153153
)
@@ -289,7 +289,7 @@ def test_multi_camera_init(self):
289289
cam_2.update(self.dt)
290290
# check image data
291291
for cam in [cam_1, cam_2]:
292-
for im_data in cam.data.output.to_dict().values():
292+
for im_data in cam.data.output.values():
293293
self.assertEqual(
294294
im_data.shape, (1, self.camera_cfg.pattern_cfg.height, self.camera_cfg.pattern_cfg.width, 1)
295295
)
@@ -392,7 +392,7 @@ def test_throughput(self):
392392
with Timer(f"Time taken for writing data with shape {camera.image_shape} "):
393393
# Pack data back into replicator format to save them using its writer
394394
rep_output = {"annotators": {}}
395-
camera_data = convert_dict_to_backend(camera.data.output[0].to_dict(), backend="numpy")
395+
camera_data = convert_dict_to_backend({k: v[0] for k, v in camera.data.output.items()}, backend="numpy")
396396
for key, data, info in zip(camera_data.keys(), camera_data.values(), camera.data.info[0].values()):
397397
if info is not None:
398398
rep_output["annotators"][key] = {"render_product": {"data": data, **info}}

source/extensions/omni.isaac.lab/test/sensors/test_tiled_camera.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def test_single_camera_init(self):
111111
# update camera
112112
camera.update(self.dt)
113113
# check image data
114-
for im_type, im_data in camera.data.output.to_dict().items():
114+
for im_type, im_data in camera.data.output.items():
115115
if im_type == "rgb":
116116
self.assertEqual(im_data.shape, (1, self.camera_cfg.height, self.camera_cfg.width, 3))
117117
self.assertGreater((im_data / 255.0).mean().item(), 0.0)
@@ -162,7 +162,7 @@ def test_multi_camera_init(self):
162162
# update camera
163163
camera.update(self.dt)
164164
# check image data
165-
for im_type, im_data in camera.data.output.to_dict().items():
165+
for im_type, im_data in camera.data.output.items():
166166
if im_type == "rgb":
167167
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 3))
168168
for i in range(4):
@@ -347,7 +347,7 @@ def test_rgba_only_camera(self):
347347
# update camera
348348
camera.update(self.dt)
349349
# check image data
350-
for _, im_data in camera.data.output.to_dict().items():
350+
for _, im_data in camera.data.output.items():
351351
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 4))
352352
for i in range(4):
353353
self.assertGreater((im_data[i] / 255.0).mean().item(), 0.0)
@@ -399,7 +399,7 @@ def test_distance_to_camera_only_camera(self):
399399
# update camera
400400
camera.update(self.dt)
401401
# check image data
402-
for _, im_data in camera.data.output.to_dict().items():
402+
for _, im_data in camera.data.output.items():
403403
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 1))
404404
for i in range(4):
405405
self.assertGreater((im_data[i]).mean().item(), 0.0)
@@ -451,7 +451,7 @@ def test_distance_to_image_plane_only_camera(self):
451451
# update camera
452452
camera.update(self.dt)
453453
# check image data
454-
for _, im_data in camera.data.output.to_dict().items():
454+
for _, im_data in camera.data.output.items():
455455
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 1))
456456
for i in range(4):
457457
self.assertGreater((im_data[i]).mean().item(), 0.0)
@@ -503,7 +503,7 @@ def test_normals_only_camera(self):
503503
# update camera
504504
camera.update(self.dt)
505505
# check image data
506-
for _, im_data in camera.data.output.to_dict().items():
506+
for _, im_data in camera.data.output.items():
507507
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 3))
508508
for i in range(4):
509509
self.assertGreater((im_data[i]).mean().item(), 0.0)
@@ -555,7 +555,7 @@ def test_motion_vectors_only_camera(self):
555555
# update camera
556556
camera.update(self.dt)
557557
# check image data
558-
for _, im_data in camera.data.output.to_dict().items():
558+
for _, im_data in camera.data.output.items():
559559
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 2))
560560
for i in range(4):
561561
self.assertGreater((im_data[i]).mean().item(), 0.0)
@@ -607,7 +607,7 @@ def test_semantic_segmentation_colorize_only_camera(self):
607607
# update camera
608608
camera.update(self.dt)
609609
# check image data
610-
for _, im_data in camera.data.output.to_dict().items():
610+
for _, im_data in camera.data.output.items():
611611
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 4))
612612
for i in range(4):
613613
self.assertGreater((im_data[i] / 255.0).mean().item(), 0.0)
@@ -660,7 +660,7 @@ def test_instance_segmentation_fast_colorize_only_camera(self):
660660
# update camera
661661
camera.update(self.dt)
662662
# check image data
663-
for _, im_data in camera.data.output.to_dict().items():
663+
for _, im_data in camera.data.output.items():
664664
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 4))
665665
for i in range(num_cameras):
666666
self.assertGreater((im_data[i] / 255.0).mean().item(), 0.0)
@@ -713,7 +713,7 @@ def test_instance_id_segmentation_fast_colorize_only_camera(self):
713713
# update camera
714714
camera.update(self.dt)
715715
# check image data
716-
for _, im_data in camera.data.output.to_dict().items():
716+
for _, im_data in camera.data.output.items():
717717
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 4))
718718
for i in range(num_cameras):
719719
self.assertGreater((im_data[i] / 255.0).mean().item(), 0.0)
@@ -767,7 +767,7 @@ def test_semantic_segmentation_non_colorize_only_camera(self):
767767
# update camera
768768
camera.update(self.dt)
769769
# check image data
770-
for _, im_data in camera.data.output.to_dict().items():
770+
for _, im_data in camera.data.output.items():
771771
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 1))
772772
for i in range(num_cameras):
773773
self.assertGreater(im_data[i].to(dtype=float).mean().item(), 0.0)
@@ -822,7 +822,7 @@ def test_instance_segmentation_fast_non_colorize_only_camera(self):
822822
# update camera
823823
camera.update(self.dt)
824824
# check image data
825-
for _, im_data in camera.data.output.to_dict().items():
825+
for _, im_data in camera.data.output.items():
826826
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 1))
827827
for i in range(num_cameras):
828828
self.assertGreater(im_data[i].to(dtype=float).mean().item(), 0.0)
@@ -876,7 +876,7 @@ def test_instance_id_segmentation_fast_non_colorize_only_camera(self):
876876
# update camera
877877
camera.update(self.dt)
878878
# check image data
879-
for _, im_data in camera.data.output.to_dict().items():
879+
for _, im_data in camera.data.output.items():
880880
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 1))
881881
for i in range(num_cameras):
882882
self.assertGreater(im_data[i].to(dtype=float).mean().item(), 0.0)
@@ -941,7 +941,7 @@ def test_all_annotators_camera(self):
941941
# update camera
942942
camera.update(self.dt)
943943
# check image data
944-
for data_type, im_data in camera.data.output.to_dict().items():
944+
for data_type, im_data in camera.data.output.items():
945945
if data_type in ["rgb", "normals"]:
946946
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 3))
947947
elif data_type in [
@@ -1039,7 +1039,7 @@ def test_all_annotators_low_resolution_camera(self):
10391039
# update camera
10401040
camera.update(self.dt)
10411041
# check image data
1042-
for data_type, im_data in camera.data.output.to_dict().items():
1042+
for data_type, im_data in camera.data.output.items():
10431043
if data_type in ["rgb", "normals"]:
10441044
self.assertEqual(im_data.shape, (num_cameras, camera_cfg.height, camera_cfg.width, 3))
10451045
elif data_type in [
@@ -1135,7 +1135,7 @@ def test_all_annotators_non_perfect_square_number_camera(self):
11351135
# update camera
11361136
camera.update(self.dt)
11371137
# check image data
1138-
for data_type, im_data in camera.data.output.to_dict().items():
1138+
for data_type, im_data in camera.data.output.items():
11391139
if data_type in ["rgb", "normals"]:
11401140
self.assertEqual(im_data.shape, (num_cameras, self.camera_cfg.height, self.camera_cfg.width, 3))
11411141
elif data_type in [
@@ -1201,7 +1201,7 @@ def test_throughput(self):
12011201
with Timer(f"Time taken for updating camera with shape {camera.image_shape}"):
12021202
camera.update(self.dt)
12031203
# Check image data
1204-
for im_type, im_data in camera.data.output.to_dict().items():
1204+
for im_type, im_data in camera.data.output.items():
12051205
if im_type == "rgb":
12061206
self.assertEqual(im_data.shape, (1, camera_cfg.height, camera_cfg.width, 3))
12071207
self.assertGreater((im_data / 255.0).mean().item(), 0.0)

source/standalone/tutorials/04_sensors/run_ray_caster_camera.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,9 @@ def run_simulator(sim: sim_utils.SimulationContext, scene_entities: dict):
129129
# Extract camera data
130130
camera_index = 0
131131
# note: BasicWriter only supports saving data in numpy format, so we need to convert the data to numpy.
132-
if sim.backend == "torch":
133-
# tensordict allows easy indexing of tensors in the dictionary
134-
single_cam_data = convert_dict_to_backend(camera.data.output[camera_index], backend="numpy")
135-
else:
136-
# for numpy, we need to manually index the data
137-
single_cam_data = dict()
138-
for key, value in camera.data.output.items():
139-
single_cam_data[key] = value[camera_index]
132+
single_cam_data = convert_dict_to_backend(
133+
{k: v[camera_index] for k, v in camera.data.output.items()}, backend="numpy"
134+
)
140135
# Extract the other information
141136
single_cam_info = camera.data.info[camera_index]
142137

0 commit comments

Comments
 (0)