We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
datapoints cannot be deepcopied
```py
from torchvision.prototype import features
from copy import copy, deepcopy
import torch

image = features.Image(torch.rand(3, 16, 16))
image_copy = copy(image)  # works
image_deepcopy = deepcopy(image)  # fails
```

```
RuntimeError: The default implementation of __deepcopy__() for non-wrapper subclasses only works for subclass types 
that implement new_empty() and for which that function returns another instance of the same subclass. 
You should either properly implement new_empty() for your subclass or override __deepcopy__() if it is intended 
behavior for new_empty() to return an instance of a different type.
```

The error message is giving us two options:

1. Override [`new_empty`](https://pytorch.org/docs/stable/generated/torch.Tensor.new_empty.html): according to the error message, this is preferred since we want to return an instance of the same type. Some of our features have internal guards for the shape like 

    https://github.com/pytorch/vision/blob/b4b246a52ebbe29bff9099c6fbabff0b82d7edd3/torchvision/prototype/features/_image.py#L49-L50

    and the plan is to expand this to all features, since the transformations rely on a certain shape. However, you can call `new_empty(size)` with an arbitrary size and the default implementation of `__deepcopy__` does so with an [empty list `[]`](https://github.com/pytorch/pytorch/blob/432c508e71111f9d5382322e0e6b1bc1c66bf0ec/torch/_tensor.py#L181). Later on, [the correct shape of the copied tensor is set](https://github.com/pytorch/pytorch/blob/432c508e71111f9d5382322e0e6b1bc1c66bf0ec/torch/_tensor.py#L191-L193), but we still need to be able to create the tensor with an incorrect shape. We could left-pad the `size` with zeros to get to the correct number of dimensions in case it is needed.

2. Override `__deepcopy__`: Maybe I'm to naive here, but a deepcopy should just be a `.clone()` of the tensor as well as a deepcopy of attributes where it is needed, e.g. `Label.categories`. Not sure if there is a downside, but that seems easier than 1. while achieving the same goal.

cc @bjuncek

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `torchvision/datapoints/_datapoint.py`
Content:
```
1 from __future__ import annotations
2 
3 from types import ModuleType
4 from typing import Any, Callable, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union
5 
6 import PIL.Image
7 import torch
8 from torch._C import DisableTorchFunctionSubclass
9 from torch.types import _device, _dtype, _size
10 from torchvision.transforms import InterpolationMode
11 
12 
13 D = TypeVar("D", bound="Datapoint")
14 _FillType = Union[int, float, Sequence[int], Sequence[float], None]
15 _FillTypeJIT = Optional[List[float]]
16 
17 
18 class Datapoint(torch.Tensor):
19     __F: Optional[ModuleType] = None
20 
21     @staticmethod
22     def _to_tensor(
23         data: Any,
24         dtype: Optional[torch.dtype] = None,
25         device: Optional[Union[torch.device, str, int]] = None,
26         requires_grad: Optional[bool] = None,
27     ) -> torch.Tensor:
28         if requires_grad is None:
29             requires_grad = data.requires_grad if isinstance(data, torch.Tensor) else False
30         return torch.as_tensor(data, dtype=dtype, device=device).requires_grad_(requires_grad)
31 
32     @classmethod
33     def wrap_like(cls: Type[D], other: D, tensor: torch.Tensor) -> D:
34         raise NotImplementedError
35 
36     _NO_WRAPPING_EXCEPTIONS = {
37         torch.Tensor.clone: lambda cls, input, output: cls.wrap_like(input, output),
38         torch.Tensor.to: lambda cls, input, output: cls.wrap_like(input, output),
39         # We don't need to wrap the output of `Tensor.requires_grad_`, since it is an inplace operation and thus
40         # retains the type automatically
41         torch.Tensor.requires_grad_: lambda cls, input, output: output,
42     }
43 
44     @classmethod
45     def __torch_function__(
46         cls,
47         func: Callable[..., torch.Tensor],
48         types: Tuple[Type[torch.Tensor], ...],
49         args: Sequence[Any] = (),
50         kwargs: Optional[Mapping[str, Any]] = None,
51     ) -> torch.Tensor:
52         """For general information about how the __torch_function__ protocol works,
53         see https://pytorch.org/docs/stable/notes/extending.html#extending-torch
54 
55         TL;DR: Every time a PyTorch operator is called, it goes through the inputs and looks for the
56         ``__torch_function__`` method. If one is found, it is invoked with the operator as ``func`` as well as the
57         ``args`` and ``kwargs`` of the original call.
58 
59         The default behavior of :class:`~torch.Tensor`'s is to retain a custom tensor type. For the :class:`Datapoint`
60         use case, this has two downsides:
61 
62         1. Since some :class:`Datapoint`'s require metadata to be constructed, the default wrapping, i.e.
63            ``return cls(func(*args, **kwargs))``, will fail for them.
64         2. For most operations, there is no way of knowing if the input type is still valid for the output.
65 
66         For these reasons, the automatic output wrapping is turned off for most operators. The only exceptions are
67         listed in :attr:`Datapoint._NO_WRAPPING_EXCEPTIONS`
68         """
69         # Since super().__torch_function__ has no hook to prevent the coercing of the output into the input type, we
70         # need to reimplement the functionality.
71 
72         if not all(issubclass(cls, t) for t in types):
73             return NotImplemented
74 
75         with DisableTorchFunctionSubclass():
76             output = func(*args, **kwargs or dict())
77 
78             wrapper = cls._NO_WRAPPING_EXCEPTIONS.get(func)
79             # Apart from `func` needing to be an exception, we also require the primary operand, i.e. `args[0]`, to be
80             # an instance of the class that `__torch_function__` was invoked on. The __torch_function__ protocol will
81             # invoke this method on *all* types involved in the computation by walking the MRO upwards. For example,
82             # `torch.Tensor(...).to(datapoints.Image(...))` will invoke `datapoints.Image.__torch_function__` with
83             # `args = (torch.Tensor(), datapoints.Image())` first. Without this guard, the original `torch.Tensor` would
84             # be wrapped into a `datapoints.Image`.
85             if wrapper and isinstance(args[0], cls):
86                 return wrapper(cls, args[0], output)
87 
88             # Inplace `func`'s, canonically identified with a trailing underscore in their name like `.add_(...)`,
89             # will retain the input type. Thus, we need to unwrap here.
90             if isinstance(output, cls):
91                 return output.as_subclass(torch.Tensor)
92 
93             return output
94 
95     def _make_repr(self, **kwargs: Any) -> str:
96         # This is a poor man's implementation of the proposal in https://github.com/pytorch/pytorch/issues/76532.
97         # If that ever gets implemented, remove this in favor of the solution on the `torch.Tensor` class.
98         extra_repr = ", ".join(f"{key}={value}" for key, value in kwargs.items())
99         return f"{super().__repr__()[:-1]}, {extra_repr})"
100 
101     @property
102     def _F(self) -> ModuleType:
103         # This implements a lazy import of the functional to get around the cyclic import. This import is deferred
104         # until the first time we need reference to the functional module and it's shared across all instances of
105         # the class. This approach avoids the DataLoader issue described at
106         # https://github.com/pytorch/vision/pull/6476#discussion_r953588621
107         if Datapoint.__F is None:
108             from ..transforms.v2 import functional
109 
110             Datapoint.__F = functional
111         return Datapoint.__F
112 
113     # Add properties for common attributes like shape, dtype, device, ndim etc
114     # this way we return the result without passing into __torch_function__
115     @property
116     def shape(self) -> _size:  # type: ignore[override]
117         with DisableTorchFunctionSubclass():
118             return super().shape
119 
120     @property
121     def ndim(self) -> int:  # type: ignore[override]
122         with DisableTorchFunctionSubclass():
123             return super().ndim
124 
125     @property
126     def device(self, *args: Any, **kwargs: Any) -> _device:  # type: ignore[override]
127         with DisableTorchFunctionSubclass():
128             return super().device
129 
130     @property
131     def dtype(self) -> _dtype:  # type: ignore[override]
132         with DisableTorchFunctionSubclass():
133             return super().dtype
134 
135     def horizontal_flip(self) -> Datapoint:
136         return self
137 
138     def vertical_flip(self) -> Datapoint:
139         return self
140 
141     # TODO: We have to ignore override mypy error as there is torch.Tensor built-in deprecated op: Tensor.resize
142     # https://github.com/pytorch/pytorch/blob/e8727994eb7cdb2ab642749d6549bc497563aa06/torch/_tensor.py#L588-L593
143     def resize(  # type: ignore[override]
144         self,
145         size: List[int],
146         interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,
147         max_size: Optional[int] = None,
148         antialias: Optional[Union[str, bool]] = "warn",
149     ) -> Datapoint:
150         return self
151 
152     def crop(self, top: int, left: int, height: int, width: int) -> Datapoint:
153         return self
154 
155     def center_crop(self, output_size: List[int]) -> Datapoint:
156         return self
157 
158     def resized_crop(
159         self,
160         top: int,
161         left: int,
162         height: int,
163         width: int,
164         size: List[int],
165         interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,
166         antialias: Optional[Union[str, bool]] = "warn",
167     ) -> Datapoint:
168         return self
169 
170     def pad(
171         self,
172         padding: List[int],
173         fill: Optional[Union[int, float, List[float]]] = None,
174         padding_mode: str = "constant",
175     ) -> Datapoint:
176         return self
177 
178     def rotate(
179         self,
180         angle: float,
181         interpolation: Union[InterpolationMode, int] = InterpolationMode.NEAREST,
182         expand: bool = False,
183         center: Optional[List[float]] = None,
184         fill: _FillTypeJIT = None,
185     ) -> Datapoint:
186         return self
187 
188     def affine(
189         self,
190         angle: Union[int, float],
191         translate: List[float],
192         scale: float,
193         shear: List[float],
194         interpolation: Union[InterpolationMode, int] = InterpolationMode.NEAREST,
195         fill: _FillTypeJIT = None,
196         center: Optional[List[float]] = None,
197     ) -> Datapoint:
198         return self
199 
200     def perspective(
201         self,
202         startpoints: Optional[List[List[int]]],
203         endpoints: Optional[List[List[int]]],
204         interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,
205         fill: _FillTypeJIT = None,
206         coefficients: Optional[List[float]] = None,
207     ) -> Datapoint:
208         return self
209 
210     def elastic(
211         self,
212         displacement: torch.Tensor,
213         interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,
214         fill: _FillTypeJIT = None,
215     ) -> Datapoint:
216         return self
217 
218     def rgb_to_grayscale(self, num_output_channels: int = 1) -> Datapoint:
219         return self
220 
221     def adjust_brightness(self, brightness_factor: float) -> Datapoint:
222         return self
223 
224     def adjust_saturation(self, saturation_factor: float) -> Datapoint:
225         return self
226 
227     def adjust_contrast(self, contrast_factor: float) -> Datapoint:
228         return self
229 
230     def adjust_sharpness(self, sharpness_factor: float) -> Datapoint:
231         return self
232 
233     def adjust_hue(self, hue_factor: float) -> Datapoint:
234         return self
235 
236     def adjust_gamma(self, gamma: float, gain: float = 1) -> Datapoint:
237         return self
238 
239     def posterize(self, bits: int) -> Datapoint:
240         return self
241 
242     def solarize(self, threshold: float) -> Datapoint:
243         return self
244 
245     def autocontrast(self) -> Datapoint:
246         return self
247 
248     def equalize(self) -> Datapoint:
249         return self
250 
251     def invert(self) -> Datapoint:
252         return self
253 
254     def gaussian_blur(self, kernel_size: List[int], sigma: Optional[List[float]] = None) -> Datapoint:
255         return self
256 
257 
258 _InputType = Union[torch.Tensor, PIL.Image.Image, Datapoint]
259 _InputTypeJIT = torch.Tensor
260
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/torchvision/datapoints/_datapoint.py b/torchvision/datapoints/_datapoint.py
--- a/torchvision/datapoints/_datapoint.py
+++ b/torchvision/datapoints/_datapoint.py
@@ -1,7 +1,7 @@
 from __future__ import annotations
 
 from types import ModuleType
-from typing import Any, Callable, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union
+from typing import Any, Callable, Dict, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union
 
 import PIL.Image
 import torch
@@ -36,6 +36,7 @@
     _NO_WRAPPING_EXCEPTIONS = {
         torch.Tensor.clone: lambda cls, input, output: cls.wrap_like(input, output),
         torch.Tensor.to: lambda cls, input, output: cls.wrap_like(input, output),
+        torch.Tensor.detach: lambda cls, input, output: cls.wrap_like(input, output),
         # We don't need to wrap the output of `Tensor.requires_grad_`, since it is an inplace operation and thus
         # retains the type automatically
         torch.Tensor.requires_grad_: lambda cls, input, output: output,
@@ -132,6 +133,15 @@
         with DisableTorchFunctionSubclass():
             return super().dtype
 
+    def __deepcopy__(self: D, memo: Dict[int, Any]) -> D:
+        # We need to detach first, since a plain `Tensor.clone` will be part of the computation graph, which does
+        # *not* happen for `deepcopy(Tensor)`. A side-effect from detaching is that the `Tensor.requires_grad`
+        # attribute is cleared, so we need to refill it before we return.
+        # Note: We don't explicitly handle deep-copying of the metadata here. The only metadata we currently have is
+        # `BoundingBox.format` and `BoundingBox.spatial_size`, which are immutable and thus implicitly deep-copied by
+        # `BoundingBox.clone()`.
+        return self.detach().clone().requires_grad_(self.requires_grad)  # type: ignore[return-value]
+
     def horizontal_flip(self) -> Datapoint:
         return self

{"golden_diff": "diff --git a/torchvision/datapoints/_datapoint.py b/torchvision/datapoints/_datapoint.py\n--- a/torchvision/datapoints/_datapoint.py\n+++ b/torchvision/datapoints/_datapoint.py\n@@ -1,7 +1,7 @@\n from __future__ import annotations\n \n from types import ModuleType\n-from typing import Any, Callable, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union\n+from typing import Any, Callable, Dict, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union\n \n import PIL.Image\n import torch\n@@ -36,6 +36,7 @@\n     _NO_WRAPPING_EXCEPTIONS = {\n         torch.Tensor.clone: lambda cls, input, output: cls.wrap_like(input, output),\n         torch.Tensor.to: lambda cls, input, output: cls.wrap_like(input, output),\n+        torch.Tensor.detach: lambda cls, input, output: cls.wrap_like(input, output),\n         # We don't need to wrap the output of `Tensor.requires_grad_`, since it is an inplace operation and thus\n         # retains the type automatically\n         torch.Tensor.requires_grad_: lambda cls, input, output: output,\n@@ -132,6 +133,15 @@\n         with DisableTorchFunctionSubclass():\n             return super().dtype\n \n+    def __deepcopy__(self: D, memo: Dict[int, Any]) -> D:\n+        # We need to detach first, since a plain `Tensor.clone` will be part of the computation graph, which does\n+        # *not* happen for `deepcopy(Tensor)`. A side-effect from detaching is that the `Tensor.requires_grad`\n+        # attribute is cleared, so we need to refill it before we return.\n+        # Note: We don't explicitly handle deep-copying of the metadata here. The only metadata we currently have is\n+        # `BoundingBox.format` and `BoundingBox.spatial_size`, which are immutable and thus implicitly deep-copied by\n+        # `BoundingBox.clone()`.\n+        return self.detach().clone().requires_grad_(self.requires_grad)  # type: ignore[return-value]\n+\n     def horizontal_flip(self) -> Datapoint:\n         return self\n", "issue": "datapoints cannot be deepcopied\n```py\r\nfrom torchvision.prototype import features\r\nfrom copy import copy, deepcopy\r\nimport torch\r\n\r\nimage = features.Image(torch.rand(3, 16, 16))\r\nimage_copy = copy(image)  # works\r\nimage_deepcopy = deepcopy(image)  # fails\r\n```\r\n\r\n```\r\nRuntimeError: The default implementation of __deepcopy__() for non-wrapper subclasses only works for subclass types \r\nthat implement new_empty() and for which that function returns another instance of the same subclass. \r\nYou should either properly implement new_empty() for your subclass or override __deepcopy__() if it is intended \r\nbehavior for new_empty() to return an instance of a different type.\r\n```\r\n\r\nThe error message is giving us two options:\r\n\r\n1. Override [`new_empty`](https://pytorch.org/docs/stable/generated/torch.Tensor.new_empty.html): according to the error message, this is preferred since we want to return an instance of the same type. Some of our features have internal guards for the shape like \r\n\r\n    https://github.com/pytorch/vision/blob/b4b246a52ebbe29bff9099c6fbabff0b82d7edd3/torchvision/prototype/features/_image.py#L49-L50\r\n\r\n    and the plan is to expand this to all features, since the transformations rely on a certain shape. However, you can call `new_empty(size)` with an arbitrary size and the default implementation of `__deepcopy__` does so with an [empty list `[]`](https://github.com/pytorch/pytorch/blob/432c508e71111f9d5382322e0e6b1bc1c66bf0ec/torch/_tensor.py#L181). Later on, [the correct shape of the copied tensor is set](https://github.com/pytorch/pytorch/blob/432c508e71111f9d5382322e0e6b1bc1c66bf0ec/torch/_tensor.py#L191-L193), but we still need to be able to create the tensor with an incorrect shape. We could left-pad the `size` with zeros to get to the correct number of dimensions in case it is needed.\r\n\r\n2. Override `__deepcopy__`: Maybe I'm to naive here, but a deepcopy should just be a `.clone()` of the tensor as well as a deepcopy of attributes where it is needed, e.g. `Label.categories`. Not sure if there is a downside, but that seems easier than 1. while achieving the same goal.\n\ncc @bjuncek\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom types import ModuleType\nfrom typing import Any, Callable, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union\n\nimport PIL.Image\nimport torch\nfrom torch._C import DisableTorchFunctionSubclass\nfrom torch.types import _device, _dtype, _size\nfrom torchvision.transforms import InterpolationMode\n\n\nD = TypeVar(\"D\", bound=\"Datapoint\")\n_FillType = Union[int, float, Sequence[int], Sequence[float], None]\n_FillTypeJIT = Optional[List[float]]\n\n\nclass Datapoint(torch.Tensor):\n    __F: Optional[ModuleType] = None\n\n    @staticmethod\n    def _to_tensor(\n        data: Any,\n        dtype: Optional[torch.dtype] = None,\n        device: Optional[Union[torch.device, str, int]] = None,\n        requires_grad: Optional[bool] = None,\n    ) -> torch.Tensor:\n        if requires_grad is None:\n            requires_grad = data.requires_grad if isinstance(data, torch.Tensor) else False\n        return torch.as_tensor(data, dtype=dtype, device=device).requires_grad_(requires_grad)\n\n    @classmethod\n    def wrap_like(cls: Type[D], other: D, tensor: torch.Tensor) -> D:\n        raise NotImplementedError\n\n    _NO_WRAPPING_EXCEPTIONS = {\n        torch.Tensor.clone: lambda cls, input, output: cls.wrap_like(input, output),\n        torch.Tensor.to: lambda cls, input, output: cls.wrap_like(input, output),\n        # We don't need to wrap the output of `Tensor.requires_grad_`, since it is an inplace operation and thus\n        # retains the type automatically\n        torch.Tensor.requires_grad_: lambda cls, input, output: output,\n    }\n\n    @classmethod\n    def __torch_function__(\n        cls,\n        func: Callable[..., torch.Tensor],\n        types: Tuple[Type[torch.Tensor], ...],\n        args: Sequence[Any] = (),\n        kwargs: Optional[Mapping[str, Any]] = None,\n    ) -> torch.Tensor:\n        \"\"\"For general information about how the __torch_function__ protocol works,\n        see https://pytorch.org/docs/stable/notes/extending.html#extending-torch\n\n        TL;DR: Every time a PyTorch operator is called, it goes through the inputs and looks for the\n        ``__torch_function__`` method. If one is found, it is invoked with the operator as ``func`` as well as the\n        ``args`` and ``kwargs`` of the original call.\n\n        The default behavior of :class:`~torch.Tensor`'s is to retain a custom tensor type. For the :class:`Datapoint`\n        use case, this has two downsides:\n\n        1. Since some :class:`Datapoint`'s require metadata to be constructed, the default wrapping, i.e.\n           ``return cls(func(*args, **kwargs))``, will fail for them.\n        2. For most operations, there is no way of knowing if the input type is still valid for the output.\n\n        For these reasons, the automatic output wrapping is turned off for most operators. The only exceptions are\n        listed in :attr:`Datapoint._NO_WRAPPING_EXCEPTIONS`\n        \"\"\"\n        # Since super().__torch_function__ has no hook to prevent the coercing of the output into the input type, we\n        # need to reimplement the functionality.\n\n        if not all(issubclass(cls, t) for t in types):\n            return NotImplemented\n\n        with DisableTorchFunctionSubclass():\n            output = func(*args, **kwargs or dict())\n\n            wrapper = cls._NO_WRAPPING_EXCEPTIONS.get(func)\n            # Apart from `func` needing to be an exception, we also require the primary operand, i.e. `args[0]`, to be\n            # an instance of the class that `__torch_function__` was invoked on. The __torch_function__ protocol will\n            # invoke this method on *all* types involved in the computation by walking the MRO upwards. For example,\n            # `torch.Tensor(...).to(datapoints.Image(...))` will invoke `datapoints.Image.__torch_function__` with\n            # `args = (torch.Tensor(), datapoints.Image())` first. Without this guard, the original `torch.Tensor` would\n            # be wrapped into a `datapoints.Image`.\n            if wrapper and isinstance(args[0], cls):\n                return wrapper(cls, args[0], output)\n\n            # Inplace `func`'s, canonically identified with a trailing underscore in their name like `.add_(...)`,\n            # will retain the input type. Thus, we need to unwrap here.\n            if isinstance(output, cls):\n                return output.as_subclass(torch.Tensor)\n\n            return output\n\n    def _make_repr(self, **kwargs: Any) -> str:\n        # This is a poor man's implementation of the proposal in https://github.com/pytorch/pytorch/issues/76532.\n        # If that ever gets implemented, remove this in favor of the solution on the `torch.Tensor` class.\n        extra_repr = \", \".join(f\"{key}={value}\" for key, value in kwargs.items())\n        return f\"{super().__repr__()[:-1]}, {extra_repr})\"\n\n    @property\n    def _F(self) -> ModuleType:\n        # This implements a lazy import of the functional to get around the cyclic import. This import is deferred\n        # until the first time we need reference to the functional module and it's shared across all instances of\n        # the class. This approach avoids the DataLoader issue described at\n        # https://github.com/pytorch/vision/pull/6476#discussion_r953588621\n        if Datapoint.__F is None:\n            from ..transforms.v2 import functional\n\n            Datapoint.__F = functional\n        return Datapoint.__F\n\n    # Add properties for common attributes like shape, dtype, device, ndim etc\n    # this way we return the result without passing into __torch_function__\n    @property\n    def shape(self) -> _size:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().shape\n\n    @property\n    def ndim(self) -> int:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().ndim\n\n    @property\n    def device(self, *args: Any, **kwargs: Any) -> _device:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().device\n\n    @property\n    def dtype(self) -> _dtype:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().dtype\n\n    def horizontal_flip(self) -> Datapoint:\n        return self\n\n    def vertical_flip(self) -> Datapoint:\n        return self\n\n    # TODO: We have to ignore override mypy error as there is torch.Tensor built-in deprecated op: Tensor.resize\n    # https://github.com/pytorch/pytorch/blob/e8727994eb7cdb2ab642749d6549bc497563aa06/torch/_tensor.py#L588-L593\n    def resize(  # type: ignore[override]\n        self,\n        size: List[int],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        max_size: Optional[int] = None,\n        antialias: Optional[Union[str, bool]] = \"warn\",\n    ) -> Datapoint:\n        return self\n\n    def crop(self, top: int, left: int, height: int, width: int) -> Datapoint:\n        return self\n\n    def center_crop(self, output_size: List[int]) -> Datapoint:\n        return self\n\n    def resized_crop(\n        self,\n        top: int,\n        left: int,\n        height: int,\n        width: int,\n        size: List[int],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        antialias: Optional[Union[str, bool]] = \"warn\",\n    ) -> Datapoint:\n        return self\n\n    def pad(\n        self,\n        padding: List[int],\n        fill: Optional[Union[int, float, List[float]]] = None,\n        padding_mode: str = \"constant\",\n    ) -> Datapoint:\n        return self\n\n    def rotate(\n        self,\n        angle: float,\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.NEAREST,\n        expand: bool = False,\n        center: Optional[List[float]] = None,\n        fill: _FillTypeJIT = None,\n    ) -> Datapoint:\n        return self\n\n    def affine(\n        self,\n        angle: Union[int, float],\n        translate: List[float],\n        scale: float,\n        shear: List[float],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.NEAREST,\n        fill: _FillTypeJIT = None,\n        center: Optional[List[float]] = None,\n    ) -> Datapoint:\n        return self\n\n    def perspective(\n        self,\n        startpoints: Optional[List[List[int]]],\n        endpoints: Optional[List[List[int]]],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        fill: _FillTypeJIT = None,\n        coefficients: Optional[List[float]] = None,\n    ) -> Datapoint:\n        return self\n\n    def elastic(\n        self,\n        displacement: torch.Tensor,\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        fill: _FillTypeJIT = None,\n    ) -> Datapoint:\n        return self\n\n    def rgb_to_grayscale(self, num_output_channels: int = 1) -> Datapoint:\n        return self\n\n    def adjust_brightness(self, brightness_factor: float) -> Datapoint:\n        return self\n\n    def adjust_saturation(self, saturation_factor: float) -> Datapoint:\n        return self\n\n    def adjust_contrast(self, contrast_factor: float) -> Datapoint:\n        return self\n\n    def adjust_sharpness(self, sharpness_factor: float) -> Datapoint:\n        return self\n\n    def adjust_hue(self, hue_factor: float) -> Datapoint:\n        return self\n\n    def adjust_gamma(self, gamma: float, gain: float = 1) -> Datapoint:\n        return self\n\n    def posterize(self, bits: int) -> Datapoint:\n        return self\n\n    def solarize(self, threshold: float) -> Datapoint:\n        return self\n\n    def autocontrast(self) -> Datapoint:\n        return self\n\n    def equalize(self) -> Datapoint:\n        return self\n\n    def invert(self) -> Datapoint:\n        return self\n\n    def gaussian_blur(self, kernel_size: List[int], sigma: Optional[List[float]] = None) -> Datapoint:\n        return self\n\n\n_InputType = Union[torch.Tensor, PIL.Image.Image, Datapoint]\n_InputTypeJIT = torch.Tensor\n", "path": "torchvision/datapoints/_datapoint.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom types import ModuleType\nfrom typing import Any, Callable, Dict, List, Mapping, Optional, Sequence, Tuple, Type, TypeVar, Union\n\nimport PIL.Image\nimport torch\nfrom torch._C import DisableTorchFunctionSubclass\nfrom torch.types import _device, _dtype, _size\nfrom torchvision.transforms import InterpolationMode\n\n\nD = TypeVar(\"D\", bound=\"Datapoint\")\n_FillType = Union[int, float, Sequence[int], Sequence[float], None]\n_FillTypeJIT = Optional[List[float]]\n\n\nclass Datapoint(torch.Tensor):\n    __F: Optional[ModuleType] = None\n\n    @staticmethod\n    def _to_tensor(\n        data: Any,\n        dtype: Optional[torch.dtype] = None,\n        device: Optional[Union[torch.device, str, int]] = None,\n        requires_grad: Optional[bool] = None,\n    ) -> torch.Tensor:\n        if requires_grad is None:\n            requires_grad = data.requires_grad if isinstance(data, torch.Tensor) else False\n        return torch.as_tensor(data, dtype=dtype, device=device).requires_grad_(requires_grad)\n\n    @classmethod\n    def wrap_like(cls: Type[D], other: D, tensor: torch.Tensor) -> D:\n        raise NotImplementedError\n\n    _NO_WRAPPING_EXCEPTIONS = {\n        torch.Tensor.clone: lambda cls, input, output: cls.wrap_like(input, output),\n        torch.Tensor.to: lambda cls, input, output: cls.wrap_like(input, output),\n        torch.Tensor.detach: lambda cls, input, output: cls.wrap_like(input, output),\n        # We don't need to wrap the output of `Tensor.requires_grad_`, since it is an inplace operation and thus\n        # retains the type automatically\n        torch.Tensor.requires_grad_: lambda cls, input, output: output,\n    }\n\n    @classmethod\n    def __torch_function__(\n        cls,\n        func: Callable[..., torch.Tensor],\n        types: Tuple[Type[torch.Tensor], ...],\n        args: Sequence[Any] = (),\n        kwargs: Optional[Mapping[str, Any]] = None,\n    ) -> torch.Tensor:\n        \"\"\"For general information about how the __torch_function__ protocol works,\n        see https://pytorch.org/docs/stable/notes/extending.html#extending-torch\n\n        TL;DR: Every time a PyTorch operator is called, it goes through the inputs and looks for the\n        ``__torch_function__`` method. If one is found, it is invoked with the operator as ``func`` as well as the\n        ``args`` and ``kwargs`` of the original call.\n\n        The default behavior of :class:`~torch.Tensor`'s is to retain a custom tensor type. For the :class:`Datapoint`\n        use case, this has two downsides:\n\n        1. Since some :class:`Datapoint`'s require metadata to be constructed, the default wrapping, i.e.\n           ``return cls(func(*args, **kwargs))``, will fail for them.\n        2. For most operations, there is no way of knowing if the input type is still valid for the output.\n\n        For these reasons, the automatic output wrapping is turned off for most operators. The only exceptions are\n        listed in :attr:`Datapoint._NO_WRAPPING_EXCEPTIONS`\n        \"\"\"\n        # Since super().__torch_function__ has no hook to prevent the coercing of the output into the input type, we\n        # need to reimplement the functionality.\n\n        if not all(issubclass(cls, t) for t in types):\n            return NotImplemented\n\n        with DisableTorchFunctionSubclass():\n            output = func(*args, **kwargs or dict())\n\n            wrapper = cls._NO_WRAPPING_EXCEPTIONS.get(func)\n            # Apart from `func` needing to be an exception, we also require the primary operand, i.e. `args[0]`, to be\n            # an instance of the class that `__torch_function__` was invoked on. The __torch_function__ protocol will\n            # invoke this method on *all* types involved in the computation by walking the MRO upwards. For example,\n            # `torch.Tensor(...).to(datapoints.Image(...))` will invoke `datapoints.Image.__torch_function__` with\n            # `args = (torch.Tensor(), datapoints.Image())` first. Without this guard, the original `torch.Tensor` would\n            # be wrapped into a `datapoints.Image`.\n            if wrapper and isinstance(args[0], cls):\n                return wrapper(cls, args[0], output)\n\n            # Inplace `func`'s, canonically identified with a trailing underscore in their name like `.add_(...)`,\n            # will retain the input type. Thus, we need to unwrap here.\n            if isinstance(output, cls):\n                return output.as_subclass(torch.Tensor)\n\n            return output\n\n    def _make_repr(self, **kwargs: Any) -> str:\n        # This is a poor man's implementation of the proposal in https://github.com/pytorch/pytorch/issues/76532.\n        # If that ever gets implemented, remove this in favor of the solution on the `torch.Tensor` class.\n        extra_repr = \", \".join(f\"{key}={value}\" for key, value in kwargs.items())\n        return f\"{super().__repr__()[:-1]}, {extra_repr})\"\n\n    @property\n    def _F(self) -> ModuleType:\n        # This implements a lazy import of the functional to get around the cyclic import. This import is deferred\n        # until the first time we need reference to the functional module and it's shared across all instances of\n        # the class. This approach avoids the DataLoader issue described at\n        # https://github.com/pytorch/vision/pull/6476#discussion_r953588621\n        if Datapoint.__F is None:\n            from ..transforms.v2 import functional\n\n            Datapoint.__F = functional\n        return Datapoint.__F\n\n    # Add properties for common attributes like shape, dtype, device, ndim etc\n    # this way we return the result without passing into __torch_function__\n    @property\n    def shape(self) -> _size:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().shape\n\n    @property\n    def ndim(self) -> int:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().ndim\n\n    @property\n    def device(self, *args: Any, **kwargs: Any) -> _device:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().device\n\n    @property\n    def dtype(self) -> _dtype:  # type: ignore[override]\n        with DisableTorchFunctionSubclass():\n            return super().dtype\n\n    def __deepcopy__(self: D, memo: Dict[int, Any]) -> D:\n        # We need to detach first, since a plain `Tensor.clone` will be part of the computation graph, which does\n        # *not* happen for `deepcopy(Tensor)`. A side-effect from detaching is that the `Tensor.requires_grad`\n        # attribute is cleared, so we need to refill it before we return.\n        # Note: We don't explicitly handle deep-copying of the metadata here. The only metadata we currently have is\n        # `BoundingBox.format` and `BoundingBox.spatial_size`, which are immutable and thus implicitly deep-copied by\n        # `BoundingBox.clone()`.\n        return self.detach().clone().requires_grad_(self.requires_grad)  # type: ignore[return-value]\n\n    def horizontal_flip(self) -> Datapoint:\n        return self\n\n    def vertical_flip(self) -> Datapoint:\n        return self\n\n    # TODO: We have to ignore override mypy error as there is torch.Tensor built-in deprecated op: Tensor.resize\n    # https://github.com/pytorch/pytorch/blob/e8727994eb7cdb2ab642749d6549bc497563aa06/torch/_tensor.py#L588-L593\n    def resize(  # type: ignore[override]\n        self,\n        size: List[int],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        max_size: Optional[int] = None,\n        antialias: Optional[Union[str, bool]] = \"warn\",\n    ) -> Datapoint:\n        return self\n\n    def crop(self, top: int, left: int, height: int, width: int) -> Datapoint:\n        return self\n\n    def center_crop(self, output_size: List[int]) -> Datapoint:\n        return self\n\n    def resized_crop(\n        self,\n        top: int,\n        left: int,\n        height: int,\n        width: int,\n        size: List[int],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        antialias: Optional[Union[str, bool]] = \"warn\",\n    ) -> Datapoint:\n        return self\n\n    def pad(\n        self,\n        padding: List[int],\n        fill: Optional[Union[int, float, List[float]]] = None,\n        padding_mode: str = \"constant\",\n    ) -> Datapoint:\n        return self\n\n    def rotate(\n        self,\n        angle: float,\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.NEAREST,\n        expand: bool = False,\n        center: Optional[List[float]] = None,\n        fill: _FillTypeJIT = None,\n    ) -> Datapoint:\n        return self\n\n    def affine(\n        self,\n        angle: Union[int, float],\n        translate: List[float],\n        scale: float,\n        shear: List[float],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.NEAREST,\n        fill: _FillTypeJIT = None,\n        center: Optional[List[float]] = None,\n    ) -> Datapoint:\n        return self\n\n    def perspective(\n        self,\n        startpoints: Optional[List[List[int]]],\n        endpoints: Optional[List[List[int]]],\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        fill: _FillTypeJIT = None,\n        coefficients: Optional[List[float]] = None,\n    ) -> Datapoint:\n        return self\n\n    def elastic(\n        self,\n        displacement: torch.Tensor,\n        interpolation: Union[InterpolationMode, int] = InterpolationMode.BILINEAR,\n        fill: _FillTypeJIT = None,\n    ) -> Datapoint:\n        return self\n\n    def rgb_to_grayscale(self, num_output_channels: int = 1) -> Datapoint:\n        return self\n\n    def adjust_brightness(self, brightness_factor: float) -> Datapoint:\n        return self\n\n    def adjust_saturation(self, saturation_factor: float) -> Datapoint:\n        return self\n\n    def adjust_contrast(self, contrast_factor: float) -> Datapoint:\n        return self\n\n    def adjust_sharpness(self, sharpness_factor: float) -> Datapoint:\n        return self\n\n    def adjust_hue(self, hue_factor: float) -> Datapoint:\n        return self\n\n    def adjust_gamma(self, gamma: float, gain: float = 1) -> Datapoint:\n        return self\n\n    def posterize(self, bits: int) -> Datapoint:\n        return self\n\n    def solarize(self, threshold: float) -> Datapoint:\n        return self\n\n    def autocontrast(self) -> Datapoint:\n        return self\n\n    def equalize(self) -> Datapoint:\n        return self\n\n    def invert(self) -> Datapoint:\n        return self\n\n    def gaussian_blur(self, kernel_size: List[int], sigma: Optional[List[float]] = None) -> Datapoint:\n        return self\n\n\n_InputType = Union[torch.Tensor, PIL.Image.Image, Datapoint]\n_InputTypeJIT = torch.Tensor\n", "path": "torchvision/datapoints/_datapoint.py"}]}