We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Stack overflow when `to_cpu`-family is overridden
### Code
```py
import chainer


class MyNet(chainer.Link):
    def to_cpu(self):
        super(MyNet, self).to_cpu()


net = MyNet()
net.to_cpu()
```

### Result
```
:
  File "/data2/work/w/repos/chainer/chainer/link.py", line 447, in device_resident_accept
    super(Link, self).device_resident_accept(visitor)
  File "/data2/work/w/repos/chainer/chainer/device_resident.py", line 31, in device_resident_accept
    visitor.visit_device_resident(self)
  File "/data2/work/w/repos/chainer/chainer/device_resident.py", line 240, in visit_device_resident
    to_method(**kwargs)
  File "/home/niboshi/t/a.py", line 6, in to_cpu
    super(MyNet, self).to_cpu()
  File "/data2/work/w/repos/chainer/chainer/device_resident.py", line 67, in to_cpu
    self.__to_device(visitor)
  File "/data2/work/w/repos/chainer/chainer/device_resident.py", line 139, in __to_device
    self.device_resident_accept(to_device_visitor)
  File "/data2/work/w/repos/chainer/chainer/link.py", line 447, in device_resident_accept
    super(Link, self).device_resident_accept(visitor)
  File "/data2/work/w/repos/chainer/chainer/device_resident.py", line 31, in device_resident_accept
    visitor.visit_device_resident(self)
RecursionError: maximum recursion depth exceeded
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `chainer/device_resident.py`
Content:
```
1 import abc
2 import sys
3 import typing as tp  # NOQA
4 
5 import numpy
6 
7 import chainer
8 from chainer import backend
9 from chainer.backends import _cpu
10 from chainer.backends import cuda
11 from chainer.backends import intel64
12 from chainer import types  # NOQA
13 from chainer import utils
14 import chainerx
15 
16 
17 class DeviceResident(utils.enable_final(meta_base=abc.ABCMeta)):
18 
19     """A base class of objects with multi-device hierarchy."""
20 
21     _device = _cpu.CpuDevice()
22 
23     def __init__(self):
24         # Store overridden to_device family method names.
25         self._overridden_to_methods = tuple([
26             m for m in ('to_cpu', 'to_gpu', 'to_intel64')
27             if _is_to_device_method_overridden(self, m)])
28 
29     def device_resident_accept(self, visitor):
30         """Applies the visitor to all the device objects in this instance."""
31         visitor.visit_device_resident(self)
32 
33     @property
34     def device(self):
35         """Returns the device"""
36         return self._device
37 
38     @property
39     def xp(self):
40         # type: () -> types.Xp
41         """Array module for this link.
42 
43         Depending on which of CPU/GPU this link is on, this property returns
44         :mod:`numpy` or :mod:`cupy`.
45 
46         """
47         device = self.device
48         if device is None:
49             return None
50         return device.xp
51 
52     def to_cpu(self):
53         # type: () -> 'DeviceResident'
54         """Copies parameter variables and persistent values to CPU.
55 
56         This method does not handle non-registered attributes. If some of such
57         attributes must be copied to CPU, the link implementation must
58         override :meth:`Link.to_device` to do so.
59 
60         Returns: self
61 
62         """
63         visitor = _ToDeviceVisitor(
64             backend.CpuDevice(),
65             entry_method_info=('to_cpu', {}),
66             skip_between_cupy_devices=True)
67         self.__to_device(visitor)
68         return self
69 
70     def to_gpu(
71             self,
72             device=None,  # type: tp.Optional[types.CudaDeviceSpec]
73     ):
74         # type: (...) -> 'DeviceResident'
75         """Copies parameter variables and persistent values to GPU.
76 
77         This method does not handle non-registered attributes. If some of such
78         attributes must be copied to GPU, the link implementation must
79         override :meth:`Link.to_device` to do so.
80 
81         Args:
82             device: Target device specifier. If omitted, the current device is
83                 used.
84 
85         Returns: self
86 
87         """
88         cuda.check_cuda_available()
89         cuda_device = cuda._get_device_or_current(device)
90         device = chainer.backends.cuda.GpuDevice(cuda_device)
91         visitor = _ToDeviceVisitor(
92             device,
93             entry_method_info=('to_gpu', {'device': device.device}),
94             skip_between_cupy_devices=True)
95         self.__to_device(visitor)
96         return self
97 
98     def to_intel64(self):
99         # type: () -> 'DeviceResident'
100         """Copies parameter variables and persistent values to CPU."""
101         intel64.check_ideep_available()
102         visitor = _ToDeviceVisitor(
103             chainer.get_device(intel64.Intel64Device()),
104             entry_method_info=('to_intel64', {}))
105         self.__to_device(visitor)
106         return self
107 
108     @utils.final
109     def to_chx(self):
110         """Converts parameter variables and persistent values to ChainerX \
111 without any copy.
112 
113         This method does not handle non-registered attributes. If some of such
114         attributes must be copied to ChainerX, the link implementation must
115         override this method to do so.
116 
117         Returns: self
118         """
119         if not chainerx.is_available():
120             raise RuntimeError('ChainerX is not available.')
121 
122         if self.xp is chainerx:
123             return self
124 
125         self.device_resident_accept(_ToChxVisitor())
126         return self
127 
128     @utils.final
129     def from_chx(self):
130         """Converts parameter variables and persistent values from ChainerX \
131 to NumPy/CuPy devices without any copy."""
132         if isinstance(self._device, backend.ChainerxDevice):
133             self._device = self._device.fallback_device
134 
135         self.device_resident_accept(_FromChxVisitor())
136         return self
137 
138     def __to_device(self, to_device_visitor):
139         self.device_resident_accept(to_device_visitor)
140 
141     @utils.final
142     def to_device(
143             self,
144             device  # type: types.DeviceSpec
145     ):
146         # type: (...) -> 'DeviceResident'
147         """Copies parameter variables and persistent values to the specified \
148 device.
149 
150         This method does not handle non-registered attributes. If some of such
151         attributes must be copied to the device, the link implementation must
152         override this method to do so.
153 
154         Args:
155             device: Target device specifier. See
156                 :func:`~chainer.get_device` for available values.
157 
158         Returns: self
159 
160         """
161         device = chainer.get_device(device)
162         self.__to_device(_ToDeviceVisitor(device))
163         return self
164 
165 
166 def _is_to_device_method_overridden(device_resident, method_name):
167     # Returns whether the specified to_device family method is overridden.
168     to_method = getattr(device_resident, method_name, None).__func__
169     to_method_orig = getattr(DeviceResident, method_name)
170     if sys.version_info < (3,):
171         to_method_orig = to_method_orig.__func__
172     if to_method is not to_method_orig:
173         return True  # overridden
174     return False
175 
176 
177 class DeviceResidentsVisitor(object):
178 
179     """Base class of visitors that visits device resident objects recursively.
180     """
181 
182     def visit_device_resident(self, device_resident):
183         """Processes a :class:`DeviceResident` instance."""
184         raise NotImplementedError()
185 
186     def visit_array(self, arr):
187         """Processes an array and returns a new one.
188 
189         If the visitor does not create a new array, it can simply return the
190         original array.
191         """
192         raise NotImplementedError()
193 
194     def visit_variable(self, param):
195         """Processes a variable or a parameter."""
196         raise NotImplementedError()
197 
198 
199 class _ToDeviceVisitor(DeviceResidentsVisitor):
200     # A visitor that implements recursive to_device().
201     # For backward compatibility, if any of to_cpu/to_gpu/to_intel64 are
202     # overridden on a device resident, this visitor calls it instead of
203     # `visit_device_resident`. That's true even if `to_device` was originally
204     # called.
205 
206     def __init__(
207             self, device, entry_method_info=None,
208             skip_between_cupy_devices=False):
209 
210         assert isinstance(device, chainer.backend.Device)
211 
212         # `entry_method_info` is for backward compatibility workaround for
213         # overridden methods.
214         # It indicates which method originally causes this visitor.
215         # If it is any of the to_??? method names, descendant resident's
216         # respective method will be called if it's overridden
217         # (instead of `device_resident_accept`).
218         if entry_method_info is not None:
219             assert len(entry_method_info) == 2
220             assert entry_method_info[0] in ('to_cpu', 'to_gpu', 'to_intel64')
221 
222         self._device = device
223         self._entry_method_info = entry_method_info
224         self._skip_between_cupy_devices = skip_between_cupy_devices
225 
226     def visit_device_resident(self, device_resident):
227         device_resident._device = self._device
228 
229         # Backward compatibility workaround for overridden methods
230         if device_resident._overridden_to_methods:
231             if self._entry_method_info is not None:
232                 # Deprecated method is being called: e.g. to_cpu and to_gpu.
233                 method_name, kwargs = self._entry_method_info
234             else:
235                 # to_device is being called
236                 method_name, kwargs = (
237                     self._device_to_method_name_and_kwargs(self._device))
238             if method_name in device_resident._overridden_to_methods:
239                 to_method = getattr(device_resident, method_name)
240                 to_method(**kwargs)
241                 return
242 
243     def _device_to_method_name_and_kwargs(self, device):
244         # Converts a device instance to the corresponding combination of
245         # to_??? method name and kwargs.
246 
247         # chainerx
248         if device.xp is chainerx:
249             return None, {}
250         # cupy
251         if device.xp is cuda.cupy:
252             return 'to_gpu', {'device': device.device.id}
253         # numpy
254         assert device.xp is numpy
255         if isinstance(device, _cpu.CpuDevice):
256             return 'to_cpu', {}
257         # intel64
258         assert isinstance(device, intel64.Intel64Device)
259         return 'to_intel64', {}
260 
261     def visit_array(self, arr):
262         assert isinstance(arr, chainer.get_array_types())
263         if not (self._skip_between_cupy_devices
264                 and self._device.xp is cuda.cupy
265                 and isinstance(arr, cuda.ndarray)):
266             return self._device.send(arr)
267         return arr
268 
269     def visit_variable(self, param):
270         assert isinstance(param, chainer.Variable)
271         if not (self._skip_between_cupy_devices
272                 and self._device.xp is cuda.cupy
273                 and param.device.xp is cuda.cupy):
274             param.to_device(self._device)
275 
276 
277 class _ToChxVisitor(DeviceResidentsVisitor):
278     # A visitor that recursively calls to_chx().
279 
280     def visit_device_resident(self, device_resident):
281         device_resident._device = backend.ChainerxDevice.from_fallback_device(
282             device_resident._device)
283 
284     def visit_array(self, arr):
285         assert isinstance(arr, chainer.get_array_types())
286         return backend.to_chx(arr)
287 
288     def visit_variable(self, param):
289         assert isinstance(param, chainer.Variable)
290         param.to_chx()
291 
292 
293 class _FromChxVisitor(DeviceResidentsVisitor):
294     # A visitor that recursively calls from_chx().
295 
296     def visit_device_resident(self, device_resident):
297         if isinstance(device_resident._device, backend.ChainerxDevice):
298             device_resident._device = device_resident._device.fallback_device
299 
300     def visit_array(self, arr):
301         assert isinstance(arr, chainer.get_array_types())
302         return backend.from_chx(arr)
303 
304     def visit_variable(self, param):
305         assert isinstance(param, chainer.Variable)
306         param.from_chx()
307
```
--- 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/chainer/device_resident.py b/chainer/device_resident.py
--- a/chainer/device_resident.py
+++ b/chainer/device_resident.py
@@ -63,7 +63,8 @@
         visitor = _ToDeviceVisitor(
             backend.CpuDevice(),
             entry_method_info=('to_cpu', {}),
-            skip_between_cupy_devices=True)
+            skip_between_cupy_devices=True,
+            starting_device_resident=self)
         self.__to_device(visitor)
         return self
 
@@ -91,7 +92,8 @@
         visitor = _ToDeviceVisitor(
             device,
             entry_method_info=('to_gpu', {'device': device.device}),
-            skip_between_cupy_devices=True)
+            skip_between_cupy_devices=True,
+            starting_device_resident=self)
         self.__to_device(visitor)
         return self
 
@@ -101,7 +103,8 @@
         intel64.check_ideep_available()
         visitor = _ToDeviceVisitor(
             chainer.get_device(intel64.Intel64Device()),
-            entry_method_info=('to_intel64', {}))
+            entry_method_info=('to_intel64', {}),
+            starting_device_resident=self)
         self.__to_device(visitor)
         return self
 
@@ -205,7 +208,8 @@
 
     def __init__(
             self, device, entry_method_info=None,
-            skip_between_cupy_devices=False):
+            skip_between_cupy_devices=False,
+            starting_device_resident=None):
 
         assert isinstance(device, chainer.backend.Device)
 
@@ -219,15 +223,29 @@
             assert len(entry_method_info) == 2
             assert entry_method_info[0] in ('to_cpu', 'to_gpu', 'to_intel64')
 
+        # starting_device_resident is also for backward compatibility
+        # workaround for overridden methods.
+        # It is a DeviceResident if to_xxx methods were initially called
+        # on this visitor. This is used to avoid infinite accept-visit loop
+        # that would occur by calling to_xxx methods.
+        assert (starting_device_resident is None
+                or isinstance(starting_device_resident, DeviceResident))
+
         self._device = device
         self._entry_method_info = entry_method_info
         self._skip_between_cupy_devices = skip_between_cupy_devices
+        self._starting_device_resident = starting_device_resident
 
     def visit_device_resident(self, device_resident):
         device_resident._device = self._device
 
         # Backward compatibility workaround for overridden methods
         if device_resident._overridden_to_methods:
+            # Skip this device resident, if the visitor was initially triggered
+            # from it.
+            if device_resident is self._starting_device_resident:
+                return
+
             if self._entry_method_info is not None:
                 # Deprecated method is being called: e.g. to_cpu and to_gpu.
                 method_name, kwargs = self._entry_method_info

{"golden_diff": "diff --git a/chainer/device_resident.py b/chainer/device_resident.py\n--- a/chainer/device_resident.py\n+++ b/chainer/device_resident.py\n@@ -63,7 +63,8 @@\n         visitor = _ToDeviceVisitor(\n             backend.CpuDevice(),\n             entry_method_info=('to_cpu', {}),\n-            skip_between_cupy_devices=True)\n+            skip_between_cupy_devices=True,\n+            starting_device_resident=self)\n         self.__to_device(visitor)\n         return self\n \n@@ -91,7 +92,8 @@\n         visitor = _ToDeviceVisitor(\n             device,\n             entry_method_info=('to_gpu', {'device': device.device}),\n-            skip_between_cupy_devices=True)\n+            skip_between_cupy_devices=True,\n+            starting_device_resident=self)\n         self.__to_device(visitor)\n         return self\n \n@@ -101,7 +103,8 @@\n         intel64.check_ideep_available()\n         visitor = _ToDeviceVisitor(\n             chainer.get_device(intel64.Intel64Device()),\n-            entry_method_info=('to_intel64', {}))\n+            entry_method_info=('to_intel64', {}),\n+            starting_device_resident=self)\n         self.__to_device(visitor)\n         return self\n \n@@ -205,7 +208,8 @@\n \n     def __init__(\n             self, device, entry_method_info=None,\n-            skip_between_cupy_devices=False):\n+            skip_between_cupy_devices=False,\n+            starting_device_resident=None):\n \n         assert isinstance(device, chainer.backend.Device)\n \n@@ -219,15 +223,29 @@\n             assert len(entry_method_info) == 2\n             assert entry_method_info[0] in ('to_cpu', 'to_gpu', 'to_intel64')\n \n+        # starting_device_resident is also for backward compatibility\n+        # workaround for overridden methods.\n+        # It is a DeviceResident if to_xxx methods were initially called\n+        # on this visitor. This is used to avoid infinite accept-visit loop\n+        # that would occur by calling to_xxx methods.\n+        assert (starting_device_resident is None\n+                or isinstance(starting_device_resident, DeviceResident))\n+\n         self._device = device\n         self._entry_method_info = entry_method_info\n         self._skip_between_cupy_devices = skip_between_cupy_devices\n+        self._starting_device_resident = starting_device_resident\n \n     def visit_device_resident(self, device_resident):\n         device_resident._device = self._device\n \n         # Backward compatibility workaround for overridden methods\n         if device_resident._overridden_to_methods:\n+            # Skip this device resident, if the visitor was initially triggered\n+            # from it.\n+            if device_resident is self._starting_device_resident:\n+                return\n+\n             if self._entry_method_info is not None:\n                 # Deprecated method is being called: e.g. to_cpu and to_gpu.\n                 method_name, kwargs = self._entry_method_info\n", "issue": "Stack overflow when `to_cpu`-family is overridden\n### Code\r\n```py\r\nimport chainer\r\n\r\n\r\nclass MyNet(chainer.Link):\r\n    def to_cpu(self):\r\n        super(MyNet, self).to_cpu()\r\n\r\n\r\nnet = MyNet()\r\nnet.to_cpu()\r\n```\r\n\r\n### Result\r\n```\r\n:\r\n  File \"/data2/work/w/repos/chainer/chainer/link.py\", line 447, in device_resident_accept\r\n    super(Link, self).device_resident_accept(visitor)\r\n  File \"/data2/work/w/repos/chainer/chainer/device_resident.py\", line 31, in device_resident_accept\r\n    visitor.visit_device_resident(self)\r\n  File \"/data2/work/w/repos/chainer/chainer/device_resident.py\", line 240, in visit_device_resident\r\n    to_method(**kwargs)\r\n  File \"/home/niboshi/t/a.py\", line 6, in to_cpu\r\n    super(MyNet, self).to_cpu()\r\n  File \"/data2/work/w/repos/chainer/chainer/device_resident.py\", line 67, in to_cpu\r\n    self.__to_device(visitor)\r\n  File \"/data2/work/w/repos/chainer/chainer/device_resident.py\", line 139, in __to_device\r\n    self.device_resident_accept(to_device_visitor)\r\n  File \"/data2/work/w/repos/chainer/chainer/link.py\", line 447, in device_resident_accept\r\n    super(Link, self).device_resident_accept(visitor)\r\n  File \"/data2/work/w/repos/chainer/chainer/device_resident.py\", line 31, in device_resident_accept\r\n    visitor.visit_device_resident(self)\r\nRecursionError: maximum recursion depth exceeded\r\n```\n", "before_files": [{"content": "import abc\nimport sys\nimport typing as tp  # NOQA\n\nimport numpy\n\nimport chainer\nfrom chainer import backend\nfrom chainer.backends import _cpu\nfrom chainer.backends import cuda\nfrom chainer.backends import intel64\nfrom chainer import types  # NOQA\nfrom chainer import utils\nimport chainerx\n\n\nclass DeviceResident(utils.enable_final(meta_base=abc.ABCMeta)):\n\n    \"\"\"A base class of objects with multi-device hierarchy.\"\"\"\n\n    _device = _cpu.CpuDevice()\n\n    def __init__(self):\n        # Store overridden to_device family method names.\n        self._overridden_to_methods = tuple([\n            m for m in ('to_cpu', 'to_gpu', 'to_intel64')\n            if _is_to_device_method_overridden(self, m)])\n\n    def device_resident_accept(self, visitor):\n        \"\"\"Applies the visitor to all the device objects in this instance.\"\"\"\n        visitor.visit_device_resident(self)\n\n    @property\n    def device(self):\n        \"\"\"Returns the device\"\"\"\n        return self._device\n\n    @property\n    def xp(self):\n        # type: () -> types.Xp\n        \"\"\"Array module for this link.\n\n        Depending on which of CPU/GPU this link is on, this property returns\n        :mod:`numpy` or :mod:`cupy`.\n\n        \"\"\"\n        device = self.device\n        if device is None:\n            return None\n        return device.xp\n\n    def to_cpu(self):\n        # type: () -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to CPU.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to CPU, the link implementation must\n        override :meth:`Link.to_device` to do so.\n\n        Returns: self\n\n        \"\"\"\n        visitor = _ToDeviceVisitor(\n            backend.CpuDevice(),\n            entry_method_info=('to_cpu', {}),\n            skip_between_cupy_devices=True)\n        self.__to_device(visitor)\n        return self\n\n    def to_gpu(\n            self,\n            device=None,  # type: tp.Optional[types.CudaDeviceSpec]\n    ):\n        # type: (...) -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to GPU.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to GPU, the link implementation must\n        override :meth:`Link.to_device` to do so.\n\n        Args:\n            device: Target device specifier. If omitted, the current device is\n                used.\n\n        Returns: self\n\n        \"\"\"\n        cuda.check_cuda_available()\n        cuda_device = cuda._get_device_or_current(device)\n        device = chainer.backends.cuda.GpuDevice(cuda_device)\n        visitor = _ToDeviceVisitor(\n            device,\n            entry_method_info=('to_gpu', {'device': device.device}),\n            skip_between_cupy_devices=True)\n        self.__to_device(visitor)\n        return self\n\n    def to_intel64(self):\n        # type: () -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to CPU.\"\"\"\n        intel64.check_ideep_available()\n        visitor = _ToDeviceVisitor(\n            chainer.get_device(intel64.Intel64Device()),\n            entry_method_info=('to_intel64', {}))\n        self.__to_device(visitor)\n        return self\n\n    @utils.final\n    def to_chx(self):\n        \"\"\"Converts parameter variables and persistent values to ChainerX \\\nwithout any copy.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to ChainerX, the link implementation must\n        override this method to do so.\n\n        Returns: self\n        \"\"\"\n        if not chainerx.is_available():\n            raise RuntimeError('ChainerX is not available.')\n\n        if self.xp is chainerx:\n            return self\n\n        self.device_resident_accept(_ToChxVisitor())\n        return self\n\n    @utils.final\n    def from_chx(self):\n        \"\"\"Converts parameter variables and persistent values from ChainerX \\\nto NumPy/CuPy devices without any copy.\"\"\"\n        if isinstance(self._device, backend.ChainerxDevice):\n            self._device = self._device.fallback_device\n\n        self.device_resident_accept(_FromChxVisitor())\n        return self\n\n    def __to_device(self, to_device_visitor):\n        self.device_resident_accept(to_device_visitor)\n\n    @utils.final\n    def to_device(\n            self,\n            device  # type: types.DeviceSpec\n    ):\n        # type: (...) -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to the specified \\\ndevice.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to the device, the link implementation must\n        override this method to do so.\n\n        Args:\n            device: Target device specifier. See\n                :func:`~chainer.get_device` for available values.\n\n        Returns: self\n\n        \"\"\"\n        device = chainer.get_device(device)\n        self.__to_device(_ToDeviceVisitor(device))\n        return self\n\n\ndef _is_to_device_method_overridden(device_resident, method_name):\n    # Returns whether the specified to_device family method is overridden.\n    to_method = getattr(device_resident, method_name, None).__func__\n    to_method_orig = getattr(DeviceResident, method_name)\n    if sys.version_info < (3,):\n        to_method_orig = to_method_orig.__func__\n    if to_method is not to_method_orig:\n        return True  # overridden\n    return False\n\n\nclass DeviceResidentsVisitor(object):\n\n    \"\"\"Base class of visitors that visits device resident objects recursively.\n    \"\"\"\n\n    def visit_device_resident(self, device_resident):\n        \"\"\"Processes a :class:`DeviceResident` instance.\"\"\"\n        raise NotImplementedError()\n\n    def visit_array(self, arr):\n        \"\"\"Processes an array and returns a new one.\n\n        If the visitor does not create a new array, it can simply return the\n        original array.\n        \"\"\"\n        raise NotImplementedError()\n\n    def visit_variable(self, param):\n        \"\"\"Processes a variable or a parameter.\"\"\"\n        raise NotImplementedError()\n\n\nclass _ToDeviceVisitor(DeviceResidentsVisitor):\n    # A visitor that implements recursive to_device().\n    # For backward compatibility, if any of to_cpu/to_gpu/to_intel64 are\n    # overridden on a device resident, this visitor calls it instead of\n    # `visit_device_resident`. That's true even if `to_device` was originally\n    # called.\n\n    def __init__(\n            self, device, entry_method_info=None,\n            skip_between_cupy_devices=False):\n\n        assert isinstance(device, chainer.backend.Device)\n\n        # `entry_method_info` is for backward compatibility workaround for\n        # overridden methods.\n        # It indicates which method originally causes this visitor.\n        # If it is any of the to_??? method names, descendant resident's\n        # respective method will be called if it's overridden\n        # (instead of `device_resident_accept`).\n        if entry_method_info is not None:\n            assert len(entry_method_info) == 2\n            assert entry_method_info[0] in ('to_cpu', 'to_gpu', 'to_intel64')\n\n        self._device = device\n        self._entry_method_info = entry_method_info\n        self._skip_between_cupy_devices = skip_between_cupy_devices\n\n    def visit_device_resident(self, device_resident):\n        device_resident._device = self._device\n\n        # Backward compatibility workaround for overridden methods\n        if device_resident._overridden_to_methods:\n            if self._entry_method_info is not None:\n                # Deprecated method is being called: e.g. to_cpu and to_gpu.\n                method_name, kwargs = self._entry_method_info\n            else:\n                # to_device is being called\n                method_name, kwargs = (\n                    self._device_to_method_name_and_kwargs(self._device))\n            if method_name in device_resident._overridden_to_methods:\n                to_method = getattr(device_resident, method_name)\n                to_method(**kwargs)\n                return\n\n    def _device_to_method_name_and_kwargs(self, device):\n        # Converts a device instance to the corresponding combination of\n        # to_??? method name and kwargs.\n\n        # chainerx\n        if device.xp is chainerx:\n            return None, {}\n        # cupy\n        if device.xp is cuda.cupy:\n            return 'to_gpu', {'device': device.device.id}\n        # numpy\n        assert device.xp is numpy\n        if isinstance(device, _cpu.CpuDevice):\n            return 'to_cpu', {}\n        # intel64\n        assert isinstance(device, intel64.Intel64Device)\n        return 'to_intel64', {}\n\n    def visit_array(self, arr):\n        assert isinstance(arr, chainer.get_array_types())\n        if not (self._skip_between_cupy_devices\n                and self._device.xp is cuda.cupy\n                and isinstance(arr, cuda.ndarray)):\n            return self._device.send(arr)\n        return arr\n\n    def visit_variable(self, param):\n        assert isinstance(param, chainer.Variable)\n        if not (self._skip_between_cupy_devices\n                and self._device.xp is cuda.cupy\n                and param.device.xp is cuda.cupy):\n            param.to_device(self._device)\n\n\nclass _ToChxVisitor(DeviceResidentsVisitor):\n    # A visitor that recursively calls to_chx().\n\n    def visit_device_resident(self, device_resident):\n        device_resident._device = backend.ChainerxDevice.from_fallback_device(\n            device_resident._device)\n\n    def visit_array(self, arr):\n        assert isinstance(arr, chainer.get_array_types())\n        return backend.to_chx(arr)\n\n    def visit_variable(self, param):\n        assert isinstance(param, chainer.Variable)\n        param.to_chx()\n\n\nclass _FromChxVisitor(DeviceResidentsVisitor):\n    # A visitor that recursively calls from_chx().\n\n    def visit_device_resident(self, device_resident):\n        if isinstance(device_resident._device, backend.ChainerxDevice):\n            device_resident._device = device_resident._device.fallback_device\n\n    def visit_array(self, arr):\n        assert isinstance(arr, chainer.get_array_types())\n        return backend.from_chx(arr)\n\n    def visit_variable(self, param):\n        assert isinstance(param, chainer.Variable)\n        param.from_chx()\n", "path": "chainer/device_resident.py"}], "after_files": [{"content": "import abc\nimport sys\nimport typing as tp  # NOQA\n\nimport numpy\n\nimport chainer\nfrom chainer import backend\nfrom chainer.backends import _cpu\nfrom chainer.backends import cuda\nfrom chainer.backends import intel64\nfrom chainer import types  # NOQA\nfrom chainer import utils\nimport chainerx\n\n\nclass DeviceResident(utils.enable_final(meta_base=abc.ABCMeta)):\n\n    \"\"\"A base class of objects with multi-device hierarchy.\"\"\"\n\n    _device = _cpu.CpuDevice()\n\n    def __init__(self):\n        # Store overridden to_device family method names.\n        self._overridden_to_methods = tuple([\n            m for m in ('to_cpu', 'to_gpu', 'to_intel64')\n            if _is_to_device_method_overridden(self, m)])\n\n    def device_resident_accept(self, visitor):\n        \"\"\"Applies the visitor to all the device objects in this instance.\"\"\"\n        visitor.visit_device_resident(self)\n\n    @property\n    def device(self):\n        \"\"\"Returns the device\"\"\"\n        return self._device\n\n    @property\n    def xp(self):\n        # type: () -> types.Xp\n        \"\"\"Array module for this link.\n\n        Depending on which of CPU/GPU this link is on, this property returns\n        :mod:`numpy` or :mod:`cupy`.\n\n        \"\"\"\n        device = self.device\n        if device is None:\n            return None\n        return device.xp\n\n    def to_cpu(self):\n        # type: () -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to CPU.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to CPU, the link implementation must\n        override :meth:`Link.to_device` to do so.\n\n        Returns: self\n\n        \"\"\"\n        visitor = _ToDeviceVisitor(\n            backend.CpuDevice(),\n            entry_method_info=('to_cpu', {}),\n            skip_between_cupy_devices=True,\n            starting_device_resident=self)\n        self.__to_device(visitor)\n        return self\n\n    def to_gpu(\n            self,\n            device=None,  # type: tp.Optional[types.CudaDeviceSpec]\n    ):\n        # type: (...) -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to GPU.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to GPU, the link implementation must\n        override :meth:`Link.to_device` to do so.\n\n        Args:\n            device: Target device specifier. If omitted, the current device is\n                used.\n\n        Returns: self\n\n        \"\"\"\n        cuda.check_cuda_available()\n        cuda_device = cuda._get_device_or_current(device)\n        device = chainer.backends.cuda.GpuDevice(cuda_device)\n        visitor = _ToDeviceVisitor(\n            device,\n            entry_method_info=('to_gpu', {'device': device.device}),\n            skip_between_cupy_devices=True,\n            starting_device_resident=self)\n        self.__to_device(visitor)\n        return self\n\n    def to_intel64(self):\n        # type: () -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to CPU.\"\"\"\n        intel64.check_ideep_available()\n        visitor = _ToDeviceVisitor(\n            chainer.get_device(intel64.Intel64Device()),\n            entry_method_info=('to_intel64', {}),\n            starting_device_resident=self)\n        self.__to_device(visitor)\n        return self\n\n    @utils.final\n    def to_chx(self):\n        \"\"\"Converts parameter variables and persistent values to ChainerX \\\nwithout any copy.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to ChainerX, the link implementation must\n        override this method to do so.\n\n        Returns: self\n        \"\"\"\n        if not chainerx.is_available():\n            raise RuntimeError('ChainerX is not available.')\n\n        if self.xp is chainerx:\n            return self\n\n        self.device_resident_accept(_ToChxVisitor())\n        return self\n\n    @utils.final\n    def from_chx(self):\n        \"\"\"Converts parameter variables and persistent values from ChainerX \\\nto NumPy/CuPy devices without any copy.\"\"\"\n        if isinstance(self._device, backend.ChainerxDevice):\n            self._device = self._device.fallback_device\n\n        self.device_resident_accept(_FromChxVisitor())\n        return self\n\n    def __to_device(self, to_device_visitor):\n        self.device_resident_accept(to_device_visitor)\n\n    @utils.final\n    def to_device(\n            self,\n            device  # type: types.DeviceSpec\n    ):\n        # type: (...) -> 'DeviceResident'\n        \"\"\"Copies parameter variables and persistent values to the specified \\\ndevice.\n\n        This method does not handle non-registered attributes. If some of such\n        attributes must be copied to the device, the link implementation must\n        override this method to do so.\n\n        Args:\n            device: Target device specifier. See\n                :func:`~chainer.get_device` for available values.\n\n        Returns: self\n\n        \"\"\"\n        device = chainer.get_device(device)\n        self.__to_device(_ToDeviceVisitor(device))\n        return self\n\n\ndef _is_to_device_method_overridden(device_resident, method_name):\n    # Returns whether the specified to_device family method is overridden.\n    to_method = getattr(device_resident, method_name, None).__func__\n    to_method_orig = getattr(DeviceResident, method_name)\n    if sys.version_info < (3,):\n        to_method_orig = to_method_orig.__func__\n    if to_method is not to_method_orig:\n        return True  # overridden\n    return False\n\n\nclass DeviceResidentsVisitor(object):\n\n    \"\"\"Base class of visitors that visits device resident objects recursively.\n    \"\"\"\n\n    def visit_device_resident(self, device_resident):\n        \"\"\"Processes a :class:`DeviceResident` instance.\"\"\"\n        raise NotImplementedError()\n\n    def visit_array(self, arr):\n        \"\"\"Processes an array and returns a new one.\n\n        If the visitor does not create a new array, it can simply return the\n        original array.\n        \"\"\"\n        raise NotImplementedError()\n\n    def visit_variable(self, param):\n        \"\"\"Processes a variable or a parameter.\"\"\"\n        raise NotImplementedError()\n\n\nclass _ToDeviceVisitor(DeviceResidentsVisitor):\n    # A visitor that implements recursive to_device().\n    # For backward compatibility, if any of to_cpu/to_gpu/to_intel64 are\n    # overridden on a device resident, this visitor calls it instead of\n    # `visit_device_resident`. That's true even if `to_device` was originally\n    # called.\n\n    def __init__(\n            self, device, entry_method_info=None,\n            skip_between_cupy_devices=False,\n            starting_device_resident=None):\n\n        assert isinstance(device, chainer.backend.Device)\n\n        # `entry_method_info` is for backward compatibility workaround for\n        # overridden methods.\n        # It indicates which method originally causes this visitor.\n        # If it is any of the to_??? method names, descendant resident's\n        # respective method will be called if it's overridden\n        # (instead of `device_resident_accept`).\n        if entry_method_info is not None:\n            assert len(entry_method_info) == 2\n            assert entry_method_info[0] in ('to_cpu', 'to_gpu', 'to_intel64')\n\n        # starting_device_resident is also for backward compatibility\n        # workaround for overridden methods.\n        # It is a DeviceResident if to_xxx methods were initially called\n        # on this visitor. This is used to avoid infinite accept-visit loop\n        # that would occur by calling to_xxx methods.\n        assert (starting_device_resident is None\n                or isinstance(starting_device_resident, DeviceResident))\n\n        self._device = device\n        self._entry_method_info = entry_method_info\n        self._skip_between_cupy_devices = skip_between_cupy_devices\n        self._starting_device_resident = starting_device_resident\n\n    def visit_device_resident(self, device_resident):\n        device_resident._device = self._device\n\n        # Backward compatibility workaround for overridden methods\n        if device_resident._overridden_to_methods:\n            # Skip this device resident, if the visitor was initially triggered\n            # from it.\n            if device_resident is self._starting_device_resident:\n                return\n\n            if self._entry_method_info is not None:\n                # Deprecated method is being called: e.g. to_cpu and to_gpu.\n                method_name, kwargs = self._entry_method_info\n            else:\n                # to_device is being called\n                method_name, kwargs = (\n                    self._device_to_method_name_and_kwargs(self._device))\n            if method_name in device_resident._overridden_to_methods:\n                to_method = getattr(device_resident, method_name)\n                to_method(**kwargs)\n                return\n\n    def _device_to_method_name_and_kwargs(self, device):\n        # Converts a device instance to the corresponding combination of\n        # to_??? method name and kwargs.\n\n        # chainerx\n        if device.xp is chainerx:\n            return None, {}\n        # cupy\n        if device.xp is cuda.cupy:\n            return 'to_gpu', {'device': device.device.id}\n        # numpy\n        assert device.xp is numpy\n        if isinstance(device, _cpu.CpuDevice):\n            return 'to_cpu', {}\n        # intel64\n        assert isinstance(device, intel64.Intel64Device)\n        return 'to_intel64', {}\n\n    def visit_array(self, arr):\n        assert isinstance(arr, chainer.get_array_types())\n        if not (self._skip_between_cupy_devices\n                and self._device.xp is cuda.cupy\n                and isinstance(arr, cuda.ndarray)):\n            return self._device.send(arr)\n        return arr\n\n    def visit_variable(self, param):\n        assert isinstance(param, chainer.Variable)\n        if not (self._skip_between_cupy_devices\n                and self._device.xp is cuda.cupy\n                and param.device.xp is cuda.cupy):\n            param.to_device(self._device)\n\n\nclass _ToChxVisitor(DeviceResidentsVisitor):\n    # A visitor that recursively calls to_chx().\n\n    def visit_device_resident(self, device_resident):\n        device_resident._device = backend.ChainerxDevice.from_fallback_device(\n            device_resident._device)\n\n    def visit_array(self, arr):\n        assert isinstance(arr, chainer.get_array_types())\n        return backend.to_chx(arr)\n\n    def visit_variable(self, param):\n        assert isinstance(param, chainer.Variable)\n        param.to_chx()\n\n\nclass _FromChxVisitor(DeviceResidentsVisitor):\n    # A visitor that recursively calls from_chx().\n\n    def visit_device_resident(self, device_resident):\n        if isinstance(device_resident._device, backend.ChainerxDevice):\n            device_resident._device = device_resident._device.fallback_device\n\n    def visit_array(self, arr):\n        assert isinstance(arr, chainer.get_array_types())\n        return backend.from_chx(arr)\n\n    def visit_variable(self, param):\n        assert isinstance(param, chainer.Variable)\n        param.from_chx()\n", "path": "chainer/device_resident.py"}]}