Skip to content

Commit 6092da9

Browse files
authored
Less verbose meta tensor print (#5658)
### Description We've had feedback that with MetaTensors, `x.__repr__` is overly verbose. This is used frequently when debugging with an IDE for example. The problem is accentuated with e.g., `x.max()`. Here, a single value is hidden by over 50 lines of text. Example: ```python import monai.transforms as mt loader = mt.LoadImage(image_only=True) x = loader(x) print(x.max().__repr__()) ``` <details> <summary>Output</summary> ``` tensor(2906.1714) Metadata sizeof_hdr: 348 extents: 0 session_error: 0 dim_info: 0 dim: [ 3 161 338 61 1 1 1 1] intent_p1: 0.0 intent_p2: 0.0 intent_p3: 0.0 intent_code: 0 datatype: 16 bitpix: 32 slice_start: 0 pixdim: [1. 1. 1. 2.000296 0. 0. 0. 0. ] vox_offset: 0.0 scl_slope: nan scl_inter: nan slice_end: 0 slice_code: 0 xyzt_units: 2 cal_max: 0.0 cal_min: 0.0 slice_duration: 0.0 toffset: 0.0 glmax: 0 glmin: 0 qform_code: 1 sform_code: 0 quatern_b: -0.4889228641986847 quatern_c: 0.5108369588851929 quatern_d: -0.4703003466129303 qoffset_x: -77.69402313232422 qoffset_y: 218.0015411376953 qoffset_z: -808.5780029296875 srow_x: [0. 0. 0. 0.] srow_y: [0. 0. 0. 0.] srow_z: [0. 0. 0. 0.] affine: tensor([[ 3.5726e-02, -2.8526e-03, 1.9990e+00, -7.7694e+01], [-9.9619e-01, 7.9544e-02, 7.1691e-02, 2.1800e+02], [-7.9595e-02, -9.9683e-01, 1.3722e-07, -8.0858e+02], [ 0.0000e+00, 0.0000e+00, 0.0000e+00, 1.0000e+00]], dtype=torch.float64) original_affine: [[ 3.57263708e-02 -2.85262855e-03 1.99901100e+00 -7.76940231e+01] [-9.96186848e-01 7.95440337e-02 7.16907652e-02 2.18001541e+02] [-7.95951681e-02 -9.96827272e-01 1.37223043e-07 -8.08578003e+02] [ 0.00000000e+00 0.00000000e+00 0.00000000e+00 1.00000000e+00]] as_closest_canonical: False spatial_shape: [161 338 61] space: RAS original_channel_dim: no_channel filename_or_obj: /Users/rich/Downloads/sub-verse004_ct.nii.gz Applied operations [] Is batch?: False ``` </details> I'm proposing that the `__repr__` and `__str__` match that of `torch.Tensor`. If users want meta data they can use `x.print_verbose()` or `print(x.meta)`. ### Types of changes <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Non-breaking change (fix or new feature that would not break existing functionality). - [x] Breaking change (fix or new feature that would cause existing functionality to change). - [x] New tests added to cover the changes. - [x] In-line docstrings updated. - [x] Documentation updated, tested `make html` command in the `docs/` folder. Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com>
1 parent 16b13a4 commit 6092da9

2 files changed

Lines changed: 16 additions & 10 deletions

File tree

monai/data/meta_tensor.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,6 @@ def __torch_function__(cls, func, types, args=(), kwargs=None) -> Any:
269269
# if `out` has been used as argument, metadata is not copied, nothing to do.
270270
# if "out" in kwargs:
271271
# return ret
272-
# we might have 1 or multiple outputs. Might be MetaTensor, might be something
273-
# else (e.g., `__repr__` returns a string).
274-
# Convert to list (if necessary), process, and at end remove list if one was added.
275272
if _not_requiring_metadata(ret):
276273
return ret
277274
if _get_named_tuple_like_type(func) is not None and isinstance(ret, _get_named_tuple_like_type(func)):
@@ -281,6 +278,9 @@ def __torch_function__(cls, func, types, args=(), kwargs=None) -> Any:
281278
ret[idx].meta = out_items[idx].meta
282279
ret[idx].applied_operations = out_items[idx].applied_operations
283280
return ret
281+
# we might have 1 or multiple outputs. Might be MetaTensor, might be something
282+
# else (e.g., `__repr__` returns a string).
283+
# Convert to list (if necessary), process, and at end remove list if one was added.
284284
if not isinstance(ret, Sequence):
285285
ret = [ret]
286286
unpack = True
@@ -532,17 +532,22 @@ def ensure_torch_and_prune_meta(
532532
# return the `MetaTensor`
533533
return MetaTensor(img, meta=meta)
534534

535-
def __repr__(self, *, tensor_contents=None):
535+
def __repr__(self):
536536
"""
537-
Prints out a long representation of the MetaTensor object with metadata as well as content data.
538-
539-
Args:
540-
tensor_contents: currently unused
537+
Prints a representation of the tensor identical to ``torch.Tensor.__repr__``.
538+
Use ``print_verbose`` for associated metadata.
541539
"""
542-
return self.as_tensor().__repr__() + super().__repr__()
540+
return self.as_tensor().__repr__()
543541

544542
def __str__(self):
545543
"""
546-
Prints a simpler representation of the tensor identical to torch.Tensor.__str__.
544+
Prints a representation of the tensor identical to ``torch.Tensor.__str__``.
545+
Use ``print_verbose`` for associated metadata.
547546
"""
548547
return str(self.as_tensor())
548+
549+
def print_verbose(self) -> None:
550+
"""Verbose print with meta data."""
551+
print(self)
552+
if self.meta is not None:
553+
print(self.meta.__repr__())

tests/test_meta_tensor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ def test_decollate(self, dtype):
423423
def test_str(self):
424424
t = MetaTensor([1.0], affine=torch.tensor(1), meta={"fname": "filename"})
425425
self.assertEqual(str(t), "tensor([1.])")
426+
self.assertEqual(t.__repr__(), "tensor([1.])")
426427

427428
def test_shape(self):
428429
s = MetaTensor([1])

0 commit comments

Comments
 (0)