We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
cuda tensor parameter fail to convert to numpy in InternalTorchIRGraph 
## 🐞Describe the bug
- If the input parameter type to a traced model is tensor.cuda(),  ct.convert fails with the below error
- Torch

## Trace
```
  File "/home/josh/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/internal_graph.py", line 180, in __init__
    value = param.detach().numpy()
TypeError: can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.

```
Note, possible fix:

replace
`    value = param.detach().numpy()
`
with
`    value = param.cpu().detach().numpy()
`


## System environment (please complete the following information):
 - coremltools version:  4.0b1
 - OS: Linux
 - How you install python: anaconda
 - python version: 3.7.6



## Additional context
Add any other context about the problem here.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `coremltools/converters/mil/frontend/torch/internal_graph.py`
Content:
```
1 #  Copyright (c) 2020, Apple Inc. All rights reserved.
2 #
3 #  Use of this source code is governed by a BSD-3-clause license that can be
4 #  found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5 
6 from collections import OrderedDict
7 from itertools import islice
8 
9 import torch
10 
11 
12 def _make_ssa_name(name):
13     """Converts a symbol name (string) into an SSA name, by prepending '%'.
14     Only used for pretty printing the graph.
15     """
16     return "%" + name
17 
18 
19 def _ssa_name_list(names):
20     """Take a list of symbol names (strings) and return them as SSA names. Only
21     used for pretty printing the graph.
22     """
23     return [_make_ssa_name(x) for x in names]
24 
25 
26 def _find_new_name(old_name, node_names):
27     """Disambiguate a node's name from a list of existing node names by adding
28     successively larger integers.
29     """
30     count = 0
31     new_name = old_name + "." + str(count)
32     while new_name in node_names:
33         count += 1
34         new_name = old_name + "." + str(count)
35     return new_name
36 
37 
38 def _replace_in_list(ls, old_val, new_val):
39     """Helper function to replace a value in a list."""
40     try:
41         idx = ls.index(old_val)
42     except ValueError:
43         pass
44     else:
45         ls[idx] = new_val
46 
47 
48 class InternalTorchIRBlock:
49     """CoreML internal representation of a torch IR block.
50 
51         Arguments:
52             raw_block: The torch._C.Block to convert, or None.
53             parent: The InternalTorchIRNode this block belongs to.
54             nodes: If @raw_block is None, the list of InternalTorchIRNodes in the block
55             inputs: If @raw_block is None, the list of input symbols.
56             outputs: If @raw_block is None, the list of output symbols.
57     """
58 
59     def __init__(self, raw_block=None, parent=None, nodes=None, inputs=None, outputs=None):
60         self.nodes = []
61         node_names = set()
62         self.inputs = []
63         self.outputs = []
64         self.parent = parent
65 
66         if raw_block:
67             # Add nodes
68             for raw_node in raw_block.nodes():
69                 new_node = InternalTorchIRNode(raw_node, parent=self)
70                 if new_node.name == new_node.kind:
71                     new_node.name = _find_new_name(new_node.name, node_names)
72                 self.nodes.append(new_node)
73                 node_names.add(new_node.name)
74 
75             # Add inputs
76             for inp in raw_block.inputs():
77                 self.inputs.append(inp.debugName())
78 
79             # Add outputs
80             for outp in raw_block.outputs():
81                 self.outputs.append(outp.debugName())
82         else:
83             self.nodes = nodes
84             self.inputs = inputs
85             self.outputs = outputs
86 
87     def __str__(self, indent=2):
88         indent_str = " " * indent
89         graph_str = "{}block({}):\n".format(
90             indent_str, ", ".join(_ssa_name_list(self.inputs))
91         )
92         graph_str += "{}\n".format(indent_str).join(
93             [x.__str__(indent=indent + 2) for x in self.nodes]
94         )
95         graph_str += "\n{}return ({})".format(
96             indent_str, ", ".join(_ssa_name_list(self.outputs))
97         )
98         return graph_str
99 
100     def __repr__(self):
101         return str(self)
102 
103     def replace_name(self, old_name, new_name):
104         """Replaces all instances of @old_name with @new_name in @self."""
105 
106         # Replace graph inputs/outputs
107         _replace_in_list(self.inputs, old_name, new_name)
108         _replace_in_list(self.outputs, old_name, new_name)
109 
110         for node in self.nodes:
111             node.replace_name(old_name, new_name)
112 
113 
114 class InternalTorchIRNode:
115     """CoreML internal representation of a torch IR node.
116     Can construct itself from a provided torchIR node or manually constructed with
117     args for testing.
118 
119     See InternalTorchIRGraph for the motivation behind this structure.
120 
121         Arguments:
122             node: The torch._C.Node to convert, or None.
123             parent: The InternalTorchIRGraph/Block this node belongs to.
124             attr: If @node is not specified, the dict of named attributes.
125             inputs: If @node is not specified, the list of input symbols.
126             outputs: If @node is not specified, the list of output symbols.
127             kind: If @node is not specified, the kind (op) of the node.
128             blocks: If @node is not specified, the list of InternalTorchIRBlock.
129     """
130 
131     def __init__(
132         self, node=None, parent=None, attr=None, inputs=None, outputs=None, kind=None, blocks=None,
133     ):
134         self.parent = parent
135         if node is not None:
136             self.inputs = [_input.debugName() for _input in node.inputs()]
137             self.outputs = [output.debugName() for output in node.outputs()]
138             self.kind = node.kind().split("::")[-1].lower()
139             self.blocks = [InternalTorchIRBlock(raw_block=b, parent=self) for b in node.blocks()]
140             self.attr = {
141                 name: getattr(node, node.kindOf(name))(name)
142                 for name in node.attributeNames()
143             }
144             if "value" not in self.attr:
145                 self.attr["value"] = None
146             # If the output is boolean, explicitly cast it so type inference
147             # will work correctly.
148             if len(self.outputs) == 1 and next(node.outputs()).type().str() == "bool":
149                 self.attr["value"] = bool(self.attr["value"])
150         else:
151             self.inputs = inputs
152             self.outputs = outputs
153             self.kind = kind
154             self.blocks = blocks if blocks is not None else []
155             self.attr = attr if attr is not None else {"value": None}
156         # On rare occassions, a node has no outputs. In that case, the node's
157         # name will be its kind. However, this no longer guarantees the node's
158         # name is unique. It will be up to the graph constructing the node to
159         # make sure names are unique.
160         self.name = self.outputs[0] if len(self.outputs) > 0 else self.kind
161 
162     def __str__(self, indent=2):
163         node_str = " " * indent + "{} = {}".format(
164             ", ".join(_ssa_name_list(self.outputs)), self.kind
165         )
166         node_str += "[{}]".format(
167             ", ".join(
168                 ["{}={}".format(n, v) for n, v in self.attr.items() if v is not None]
169             )
170         )
171         node_str += "({})".format(", ".join(_ssa_name_list(self.inputs)))
172         for b in self.blocks:
173             node_str += "\n" + b.__str__(indent=indent + 2)
174         return node_str
175 
176     def __repr__(self):
177         return str(self)
178 
179     def replace_name(self, old_name, new_name):
180         """Replaces all instances of @old_name with @new_name in @self."""
181 
182         _replace_in_list(self.inputs, old_name, new_name)
183         _replace_in_list(self.outputs, old_name, new_name)
184 
185         if self.name == old_name:
186             self.name = new_name
187         for block in self.blocks:
188             block.replace_name(old_name, new_name)
189 
190 
191 class InternalTorchIRGraph:
192     """CoreML internal representation of a torch IR graph. A torch._C.Graph
193     object is not an ideal structure to use in converting to CoreML. Conversion
194     to an InternalTorchIRGraph is inserted between the original graph and the
195     final CoreML model to address several issues:
196         1. A torch._C.graph is hard to work with. For example, its .inputs()
197           and .outputs() functions return iterators, so the only way to
198           determine the number of inputs/outputs is by counting to the end.
199           There are other examples of why the torch structure is hard to work
200           with, and this structure alleviates those isses.
201         2. torch._C.graph is an internal API and so we can't count on its
202           stability. By inserting a layer in between, we can handle any changes
203           to torch._C.graph here and isolate the ops code that processes the
204           graph.
205         3. torch._C.graph does not expose a Python constructor. This makes
206           it impossible to write unit tests that isolate specific ops since
207           they have to come from actually converting a PyTorch graph. With an
208           internal structure, we can directly build the test cases we need for
209           unit testing.
210 
211         Arguments:
212             raw_graph: raw_graph: The torch._C.Graph to convert, or None.
213             params_dict: A dictionary mapping graph parameter names to tensors.
214                 Must be given if @raw_graph is not None.
215             input_values: A list of inputs to the graph. Must be given is
216                 @raw_graph if not None.
217             cut_at_symbols: The list of desired outputs from the graph. Symbols
218                 must be present in the graph. For debugging use only. Can only
219                 be given if @raw_graph is not None.
220             nodes: If @raw_graph is None, the list of InternalTorchIRNodes in
221                 the graph.
222             params: If @raw_graph is None, the dict mapping parameter names to
223                 their numpy value.
224             inputs: If @raw_graph is None, the OrderedDict mapping input names
225                 to their example values.
226             outputs: If @raw_graph is None, the list of outputs from the graph.
227     """
228 
229     def __init__(
230         self, raw_graph=None, params_dict=None, input_values=None, cut_at_symbols=None, nodes=None, params=None, inputs=None, outputs=None,
231     ):
232         self.nodes = []
233         node_names = set()
234         self.params = {}
235         self.inputs = OrderedDict()
236         self.outputs = []
237 
238         if raw_graph is not None:
239             # Add nodes
240             for raw_node in raw_graph.nodes():
241                 new_node = InternalTorchIRNode(raw_node, parent=self)
242                 if new_node.name == new_node.kind:
243                     new_node.name = _find_new_name(new_node.name, node_names)
244                 self.nodes.append(new_node)
245                 node_names.add(new_node.name)
246 
247             # Add params
248             for name, param in params_dict.items():
249                 value = param.detach().numpy()
250                 self.params[name] = value
251 
252             # Add inputs
253             for index, _input in enumerate(islice(raw_graph.inputs(), len(input_values))):
254                 name = _input.debugName()
255                 value = input_values[index]
256                 self.inputs[name] = value
257 
258             # Add outputs, cutting if @cut_at_symbols is set
259             output_names = cut_at_symbols
260             if output_names is None:
261                 output_names = [x.debugName() for x in raw_graph.outputs()]
262             for output in output_names:
263                 self.outputs.append(output)
264         else:
265             self.nodes = nodes
266             self.params = params
267             self.inputs = inputs
268             self.outputs = outputs
269 
270     def __str__(self):
271         graph_str = "graph(\n"
272         graph_str += self._format_inputs(self.inputs, unpack=True)
273         graph_str += self._format_inputs(self.params)
274         graph_str += "):\n"
275         graph_str += "\n".join([str(x) for x in self.nodes]) + "\n"
276         graph_str += "return ({})".format(", ".join(_ssa_name_list(self.outputs)))
277         return graph_str
278 
279     def _format_inputs(self, inputs, unpack=False):
280         def tensor_str(x):
281             return "Tensor{}".format(
282                 tuple(list(x.shape.shape if unpack else x.shape) + [str(x.dtype)])
283             )
284 
285         inp_str = ""
286         for k, v in inputs.items():
287             if isinstance(v, (tuple, list)):
288                 shape_str = "({})".format(", ".join([tensor_str(x) for x in v]))
289             else:
290                 shape_str = tensor_str(v)
291             inp_str += "    {} : {},\n".format(_make_ssa_name(k), shape_str)
292         return inp_str
293 
294     def __repr__(self):
295         return str(self)
296 
297     def replace_name(self, old_name, new_name):
298         """Replaces all instances of @old_name with @new_name in @self."""
299 
300         # Replace graph inputs/outputs
301         _replace_in_list(self.inputs, old_name, new_name)
302         _replace_in_list(self.outputs, old_name, new_name)
303 
304         for node in self.nodes:
305             node.replace_name(old_name, new_name)
306
```
--- 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/coremltools/converters/mil/frontend/torch/internal_graph.py b/coremltools/converters/mil/frontend/torch/internal_graph.py
--- a/coremltools/converters/mil/frontend/torch/internal_graph.py
+++ b/coremltools/converters/mil/frontend/torch/internal_graph.py
@@ -246,7 +246,7 @@
 
             # Add params
             for name, param in params_dict.items():
-                value = param.detach().numpy()
+                value = param.detach().cpu().numpy()
                 self.params[name] = value
 
             # Add inputs

{"golden_diff": "diff --git a/coremltools/converters/mil/frontend/torch/internal_graph.py b/coremltools/converters/mil/frontend/torch/internal_graph.py\n--- a/coremltools/converters/mil/frontend/torch/internal_graph.py\n+++ b/coremltools/converters/mil/frontend/torch/internal_graph.py\n@@ -246,7 +246,7 @@\n \n             # Add params\n             for name, param in params_dict.items():\n-                value = param.detach().numpy()\n+                value = param.detach().cpu().numpy()\n                 self.params[name] = value\n \n             # Add inputs\n", "issue": "cuda tensor parameter fail to convert to numpy in InternalTorchIRGraph \n## \ud83d\udc1eDescribe the bug\r\n- If the input parameter type to a traced model is tensor.cuda(),  ct.convert fails with the below error\r\n- Torch\r\n\r\n## Trace\r\n```\r\n  File \"/home/josh/anaconda3/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/internal_graph.py\", line 180, in __init__\r\n    value = param.detach().numpy()\r\nTypeError: can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.\r\n\r\n```\r\nNote, possible fix:\r\n\r\nreplace\r\n`    value = param.detach().numpy()\r\n`\r\nwith\r\n`    value = param.cpu().detach().numpy()\r\n`\r\n\r\n\r\n## System environment (please complete the following information):\r\n - coremltools version:  4.0b1\r\n - OS: Linux\r\n - How you install python: anaconda\r\n - python version: 3.7.6\r\n\r\n\r\n\r\n## Additional context\r\nAdd any other context about the problem here.\r\n\n", "before_files": [{"content": "#  Copyright (c) 2020, Apple Inc. All rights reserved.\n#\n#  Use of this source code is governed by a BSD-3-clause license that can be\n#  found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause\n\nfrom collections import OrderedDict\nfrom itertools import islice\n\nimport torch\n\n\ndef _make_ssa_name(name):\n    \"\"\"Converts a symbol name (string) into an SSA name, by prepending '%'.\n    Only used for pretty printing the graph.\n    \"\"\"\n    return \"%\" + name\n\n\ndef _ssa_name_list(names):\n    \"\"\"Take a list of symbol names (strings) and return them as SSA names. Only\n    used for pretty printing the graph.\n    \"\"\"\n    return [_make_ssa_name(x) for x in names]\n\n\ndef _find_new_name(old_name, node_names):\n    \"\"\"Disambiguate a node's name from a list of existing node names by adding\n    successively larger integers.\n    \"\"\"\n    count = 0\n    new_name = old_name + \".\" + str(count)\n    while new_name in node_names:\n        count += 1\n        new_name = old_name + \".\" + str(count)\n    return new_name\n\n\ndef _replace_in_list(ls, old_val, new_val):\n    \"\"\"Helper function to replace a value in a list.\"\"\"\n    try:\n        idx = ls.index(old_val)\n    except ValueError:\n        pass\n    else:\n        ls[idx] = new_val\n\n\nclass InternalTorchIRBlock:\n    \"\"\"CoreML internal representation of a torch IR block.\n\n        Arguments:\n            raw_block: The torch._C.Block to convert, or None.\n            parent: The InternalTorchIRNode this block belongs to.\n            nodes: If @raw_block is None, the list of InternalTorchIRNodes in the block\n            inputs: If @raw_block is None, the list of input symbols.\n            outputs: If @raw_block is None, the list of output symbols.\n    \"\"\"\n\n    def __init__(self, raw_block=None, parent=None, nodes=None, inputs=None, outputs=None):\n        self.nodes = []\n        node_names = set()\n        self.inputs = []\n        self.outputs = []\n        self.parent = parent\n\n        if raw_block:\n            # Add nodes\n            for raw_node in raw_block.nodes():\n                new_node = InternalTorchIRNode(raw_node, parent=self)\n                if new_node.name == new_node.kind:\n                    new_node.name = _find_new_name(new_node.name, node_names)\n                self.nodes.append(new_node)\n                node_names.add(new_node.name)\n\n            # Add inputs\n            for inp in raw_block.inputs():\n                self.inputs.append(inp.debugName())\n\n            # Add outputs\n            for outp in raw_block.outputs():\n                self.outputs.append(outp.debugName())\n        else:\n            self.nodes = nodes\n            self.inputs = inputs\n            self.outputs = outputs\n\n    def __str__(self, indent=2):\n        indent_str = \" \" * indent\n        graph_str = \"{}block({}):\\n\".format(\n            indent_str, \", \".join(_ssa_name_list(self.inputs))\n        )\n        graph_str += \"{}\\n\".format(indent_str).join(\n            [x.__str__(indent=indent + 2) for x in self.nodes]\n        )\n        graph_str += \"\\n{}return ({})\".format(\n            indent_str, \", \".join(_ssa_name_list(self.outputs))\n        )\n        return graph_str\n\n    def __repr__(self):\n        return str(self)\n\n    def replace_name(self, old_name, new_name):\n        \"\"\"Replaces all instances of @old_name with @new_name in @self.\"\"\"\n\n        # Replace graph inputs/outputs\n        _replace_in_list(self.inputs, old_name, new_name)\n        _replace_in_list(self.outputs, old_name, new_name)\n\n        for node in self.nodes:\n            node.replace_name(old_name, new_name)\n\n\nclass InternalTorchIRNode:\n    \"\"\"CoreML internal representation of a torch IR node.\n    Can construct itself from a provided torchIR node or manually constructed with\n    args for testing.\n\n    See InternalTorchIRGraph for the motivation behind this structure.\n\n        Arguments:\n            node: The torch._C.Node to convert, or None.\n            parent: The InternalTorchIRGraph/Block this node belongs to.\n            attr: If @node is not specified, the dict of named attributes.\n            inputs: If @node is not specified, the list of input symbols.\n            outputs: If @node is not specified, the list of output symbols.\n            kind: If @node is not specified, the kind (op) of the node.\n            blocks: If @node is not specified, the list of InternalTorchIRBlock.\n    \"\"\"\n\n    def __init__(\n        self, node=None, parent=None, attr=None, inputs=None, outputs=None, kind=None, blocks=None,\n    ):\n        self.parent = parent\n        if node is not None:\n            self.inputs = [_input.debugName() for _input in node.inputs()]\n            self.outputs = [output.debugName() for output in node.outputs()]\n            self.kind = node.kind().split(\"::\")[-1].lower()\n            self.blocks = [InternalTorchIRBlock(raw_block=b, parent=self) for b in node.blocks()]\n            self.attr = {\n                name: getattr(node, node.kindOf(name))(name)\n                for name in node.attributeNames()\n            }\n            if \"value\" not in self.attr:\n                self.attr[\"value\"] = None\n            # If the output is boolean, explicitly cast it so type inference\n            # will work correctly.\n            if len(self.outputs) == 1 and next(node.outputs()).type().str() == \"bool\":\n                self.attr[\"value\"] = bool(self.attr[\"value\"])\n        else:\n            self.inputs = inputs\n            self.outputs = outputs\n            self.kind = kind\n            self.blocks = blocks if blocks is not None else []\n            self.attr = attr if attr is not None else {\"value\": None}\n        # On rare occassions, a node has no outputs. In that case, the node's\n        # name will be its kind. However, this no longer guarantees the node's\n        # name is unique. It will be up to the graph constructing the node to\n        # make sure names are unique.\n        self.name = self.outputs[0] if len(self.outputs) > 0 else self.kind\n\n    def __str__(self, indent=2):\n        node_str = \" \" * indent + \"{} = {}\".format(\n            \", \".join(_ssa_name_list(self.outputs)), self.kind\n        )\n        node_str += \"[{}]\".format(\n            \", \".join(\n                [\"{}={}\".format(n, v) for n, v in self.attr.items() if v is not None]\n            )\n        )\n        node_str += \"({})\".format(\", \".join(_ssa_name_list(self.inputs)))\n        for b in self.blocks:\n            node_str += \"\\n\" + b.__str__(indent=indent + 2)\n        return node_str\n\n    def __repr__(self):\n        return str(self)\n\n    def replace_name(self, old_name, new_name):\n        \"\"\"Replaces all instances of @old_name with @new_name in @self.\"\"\"\n\n        _replace_in_list(self.inputs, old_name, new_name)\n        _replace_in_list(self.outputs, old_name, new_name)\n\n        if self.name == old_name:\n            self.name = new_name\n        for block in self.blocks:\n            block.replace_name(old_name, new_name)\n\n\nclass InternalTorchIRGraph:\n    \"\"\"CoreML internal representation of a torch IR graph. A torch._C.Graph\n    object is not an ideal structure to use in converting to CoreML. Conversion\n    to an InternalTorchIRGraph is inserted between the original graph and the\n    final CoreML model to address several issues:\n        1. A torch._C.graph is hard to work with. For example, its .inputs()\n          and .outputs() functions return iterators, so the only way to\n          determine the number of inputs/outputs is by counting to the end.\n          There are other examples of why the torch structure is hard to work\n          with, and this structure alleviates those isses.\n        2. torch._C.graph is an internal API and so we can't count on its\n          stability. By inserting a layer in between, we can handle any changes\n          to torch._C.graph here and isolate the ops code that processes the\n          graph.\n        3. torch._C.graph does not expose a Python constructor. This makes\n          it impossible to write unit tests that isolate specific ops since\n          they have to come from actually converting a PyTorch graph. With an\n          internal structure, we can directly build the test cases we need for\n          unit testing.\n\n        Arguments:\n            raw_graph: raw_graph: The torch._C.Graph to convert, or None.\n            params_dict: A dictionary mapping graph parameter names to tensors.\n                Must be given if @raw_graph is not None.\n            input_values: A list of inputs to the graph. Must be given is\n                @raw_graph if not None.\n            cut_at_symbols: The list of desired outputs from the graph. Symbols\n                must be present in the graph. For debugging use only. Can only\n                be given if @raw_graph is not None.\n            nodes: If @raw_graph is None, the list of InternalTorchIRNodes in\n                the graph.\n            params: If @raw_graph is None, the dict mapping parameter names to\n                their numpy value.\n            inputs: If @raw_graph is None, the OrderedDict mapping input names\n                to their example values.\n            outputs: If @raw_graph is None, the list of outputs from the graph.\n    \"\"\"\n\n    def __init__(\n        self, raw_graph=None, params_dict=None, input_values=None, cut_at_symbols=None, nodes=None, params=None, inputs=None, outputs=None,\n    ):\n        self.nodes = []\n        node_names = set()\n        self.params = {}\n        self.inputs = OrderedDict()\n        self.outputs = []\n\n        if raw_graph is not None:\n            # Add nodes\n            for raw_node in raw_graph.nodes():\n                new_node = InternalTorchIRNode(raw_node, parent=self)\n                if new_node.name == new_node.kind:\n                    new_node.name = _find_new_name(new_node.name, node_names)\n                self.nodes.append(new_node)\n                node_names.add(new_node.name)\n\n            # Add params\n            for name, param in params_dict.items():\n                value = param.detach().numpy()\n                self.params[name] = value\n\n            # Add inputs\n            for index, _input in enumerate(islice(raw_graph.inputs(), len(input_values))):\n                name = _input.debugName()\n                value = input_values[index]\n                self.inputs[name] = value\n\n            # Add outputs, cutting if @cut_at_symbols is set\n            output_names = cut_at_symbols\n            if output_names is None:\n                output_names = [x.debugName() for x in raw_graph.outputs()]\n            for output in output_names:\n                self.outputs.append(output)\n        else:\n            self.nodes = nodes\n            self.params = params\n            self.inputs = inputs\n            self.outputs = outputs\n\n    def __str__(self):\n        graph_str = \"graph(\\n\"\n        graph_str += self._format_inputs(self.inputs, unpack=True)\n        graph_str += self._format_inputs(self.params)\n        graph_str += \"):\\n\"\n        graph_str += \"\\n\".join([str(x) for x in self.nodes]) + \"\\n\"\n        graph_str += \"return ({})\".format(\", \".join(_ssa_name_list(self.outputs)))\n        return graph_str\n\n    def _format_inputs(self, inputs, unpack=False):\n        def tensor_str(x):\n            return \"Tensor{}\".format(\n                tuple(list(x.shape.shape if unpack else x.shape) + [str(x.dtype)])\n            )\n\n        inp_str = \"\"\n        for k, v in inputs.items():\n            if isinstance(v, (tuple, list)):\n                shape_str = \"({})\".format(\", \".join([tensor_str(x) for x in v]))\n            else:\n                shape_str = tensor_str(v)\n            inp_str += \"    {} : {},\\n\".format(_make_ssa_name(k), shape_str)\n        return inp_str\n\n    def __repr__(self):\n        return str(self)\n\n    def replace_name(self, old_name, new_name):\n        \"\"\"Replaces all instances of @old_name with @new_name in @self.\"\"\"\n\n        # Replace graph inputs/outputs\n        _replace_in_list(self.inputs, old_name, new_name)\n        _replace_in_list(self.outputs, old_name, new_name)\n\n        for node in self.nodes:\n            node.replace_name(old_name, new_name)\n", "path": "coremltools/converters/mil/frontend/torch/internal_graph.py"}], "after_files": [{"content": "#  Copyright (c) 2020, Apple Inc. All rights reserved.\n#\n#  Use of this source code is governed by a BSD-3-clause license that can be\n#  found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause\n\nfrom collections import OrderedDict\nfrom itertools import islice\n\nimport torch\n\n\ndef _make_ssa_name(name):\n    \"\"\"Converts a symbol name (string) into an SSA name, by prepending '%'.\n    Only used for pretty printing the graph.\n    \"\"\"\n    return \"%\" + name\n\n\ndef _ssa_name_list(names):\n    \"\"\"Take a list of symbol names (strings) and return them as SSA names. Only\n    used for pretty printing the graph.\n    \"\"\"\n    return [_make_ssa_name(x) for x in names]\n\n\ndef _find_new_name(old_name, node_names):\n    \"\"\"Disambiguate a node's name from a list of existing node names by adding\n    successively larger integers.\n    \"\"\"\n    count = 0\n    new_name = old_name + \".\" + str(count)\n    while new_name in node_names:\n        count += 1\n        new_name = old_name + \".\" + str(count)\n    return new_name\n\n\ndef _replace_in_list(ls, old_val, new_val):\n    \"\"\"Helper function to replace a value in a list.\"\"\"\n    try:\n        idx = ls.index(old_val)\n    except ValueError:\n        pass\n    else:\n        ls[idx] = new_val\n\n\nclass InternalTorchIRBlock:\n    \"\"\"CoreML internal representation of a torch IR block.\n\n        Arguments:\n            raw_block: The torch._C.Block to convert, or None.\n            parent: The InternalTorchIRNode this block belongs to.\n            nodes: If @raw_block is None, the list of InternalTorchIRNodes in the block\n            inputs: If @raw_block is None, the list of input symbols.\n            outputs: If @raw_block is None, the list of output symbols.\n    \"\"\"\n\n    def __init__(self, raw_block=None, parent=None, nodes=None, inputs=None, outputs=None):\n        self.nodes = []\n        node_names = set()\n        self.inputs = []\n        self.outputs = []\n        self.parent = parent\n\n        if raw_block:\n            # Add nodes\n            for raw_node in raw_block.nodes():\n                new_node = InternalTorchIRNode(raw_node, parent=self)\n                if new_node.name == new_node.kind:\n                    new_node.name = _find_new_name(new_node.name, node_names)\n                self.nodes.append(new_node)\n                node_names.add(new_node.name)\n\n            # Add inputs\n            for inp in raw_block.inputs():\n                self.inputs.append(inp.debugName())\n\n            # Add outputs\n            for outp in raw_block.outputs():\n                self.outputs.append(outp.debugName())\n        else:\n            self.nodes = nodes\n            self.inputs = inputs\n            self.outputs = outputs\n\n    def __str__(self, indent=2):\n        indent_str = \" \" * indent\n        graph_str = \"{}block({}):\\n\".format(\n            indent_str, \", \".join(_ssa_name_list(self.inputs))\n        )\n        graph_str += \"{}\\n\".format(indent_str).join(\n            [x.__str__(indent=indent + 2) for x in self.nodes]\n        )\n        graph_str += \"\\n{}return ({})\".format(\n            indent_str, \", \".join(_ssa_name_list(self.outputs))\n        )\n        return graph_str\n\n    def __repr__(self):\n        return str(self)\n\n    def replace_name(self, old_name, new_name):\n        \"\"\"Replaces all instances of @old_name with @new_name in @self.\"\"\"\n\n        # Replace graph inputs/outputs\n        _replace_in_list(self.inputs, old_name, new_name)\n        _replace_in_list(self.outputs, old_name, new_name)\n\n        for node in self.nodes:\n            node.replace_name(old_name, new_name)\n\n\nclass InternalTorchIRNode:\n    \"\"\"CoreML internal representation of a torch IR node.\n    Can construct itself from a provided torchIR node or manually constructed with\n    args for testing.\n\n    See InternalTorchIRGraph for the motivation behind this structure.\n\n        Arguments:\n            node: The torch._C.Node to convert, or None.\n            parent: The InternalTorchIRGraph/Block this node belongs to.\n            attr: If @node is not specified, the dict of named attributes.\n            inputs: If @node is not specified, the list of input symbols.\n            outputs: If @node is not specified, the list of output symbols.\n            kind: If @node is not specified, the kind (op) of the node.\n            blocks: If @node is not specified, the list of InternalTorchIRBlock.\n    \"\"\"\n\n    def __init__(\n        self, node=None, parent=None, attr=None, inputs=None, outputs=None, kind=None, blocks=None,\n    ):\n        self.parent = parent\n        if node is not None:\n            self.inputs = [_input.debugName() for _input in node.inputs()]\n            self.outputs = [output.debugName() for output in node.outputs()]\n            self.kind = node.kind().split(\"::\")[-1].lower()\n            self.blocks = [InternalTorchIRBlock(raw_block=b, parent=self) for b in node.blocks()]\n            self.attr = {\n                name: getattr(node, node.kindOf(name))(name)\n                for name in node.attributeNames()\n            }\n            if \"value\" not in self.attr:\n                self.attr[\"value\"] = None\n            # If the output is boolean, explicitly cast it so type inference\n            # will work correctly.\n            if len(self.outputs) == 1 and next(node.outputs()).type().str() == \"bool\":\n                self.attr[\"value\"] = bool(self.attr[\"value\"])\n        else:\n            self.inputs = inputs\n            self.outputs = outputs\n            self.kind = kind\n            self.blocks = blocks if blocks is not None else []\n            self.attr = attr if attr is not None else {\"value\": None}\n        # On rare occassions, a node has no outputs. In that case, the node's\n        # name will be its kind. However, this no longer guarantees the node's\n        # name is unique. It will be up to the graph constructing the node to\n        # make sure names are unique.\n        self.name = self.outputs[0] if len(self.outputs) > 0 else self.kind\n\n    def __str__(self, indent=2):\n        node_str = \" \" * indent + \"{} = {}\".format(\n            \", \".join(_ssa_name_list(self.outputs)), self.kind\n        )\n        node_str += \"[{}]\".format(\n            \", \".join(\n                [\"{}={}\".format(n, v) for n, v in self.attr.items() if v is not None]\n            )\n        )\n        node_str += \"({})\".format(\", \".join(_ssa_name_list(self.inputs)))\n        for b in self.blocks:\n            node_str += \"\\n\" + b.__str__(indent=indent + 2)\n        return node_str\n\n    def __repr__(self):\n        return str(self)\n\n    def replace_name(self, old_name, new_name):\n        \"\"\"Replaces all instances of @old_name with @new_name in @self.\"\"\"\n\n        _replace_in_list(self.inputs, old_name, new_name)\n        _replace_in_list(self.outputs, old_name, new_name)\n\n        if self.name == old_name:\n            self.name = new_name\n        for block in self.blocks:\n            block.replace_name(old_name, new_name)\n\n\nclass InternalTorchIRGraph:\n    \"\"\"CoreML internal representation of a torch IR graph. A torch._C.Graph\n    object is not an ideal structure to use in converting to CoreML. Conversion\n    to an InternalTorchIRGraph is inserted between the original graph and the\n    final CoreML model to address several issues:\n        1. A torch._C.graph is hard to work with. For example, its .inputs()\n          and .outputs() functions return iterators, so the only way to\n          determine the number of inputs/outputs is by counting to the end.\n          There are other examples of why the torch structure is hard to work\n          with, and this structure alleviates those isses.\n        2. torch._C.graph is an internal API and so we can't count on its\n          stability. By inserting a layer in between, we can handle any changes\n          to torch._C.graph here and isolate the ops code that processes the\n          graph.\n        3. torch._C.graph does not expose a Python constructor. This makes\n          it impossible to write unit tests that isolate specific ops since\n          they have to come from actually converting a PyTorch graph. With an\n          internal structure, we can directly build the test cases we need for\n          unit testing.\n\n        Arguments:\n            raw_graph: raw_graph: The torch._C.Graph to convert, or None.\n            params_dict: A dictionary mapping graph parameter names to tensors.\n                Must be given if @raw_graph is not None.\n            input_values: A list of inputs to the graph. Must be given is\n                @raw_graph if not None.\n            cut_at_symbols: The list of desired outputs from the graph. Symbols\n                must be present in the graph. For debugging use only. Can only\n                be given if @raw_graph is not None.\n            nodes: If @raw_graph is None, the list of InternalTorchIRNodes in\n                the graph.\n            params: If @raw_graph is None, the dict mapping parameter names to\n                their numpy value.\n            inputs: If @raw_graph is None, the OrderedDict mapping input names\n                to their example values.\n            outputs: If @raw_graph is None, the list of outputs from the graph.\n    \"\"\"\n\n    def __init__(\n        self, raw_graph=None, params_dict=None, input_values=None, cut_at_symbols=None, nodes=None, params=None, inputs=None, outputs=None,\n    ):\n        self.nodes = []\n        node_names = set()\n        self.params = {}\n        self.inputs = OrderedDict()\n        self.outputs = []\n\n        if raw_graph is not None:\n            # Add nodes\n            for raw_node in raw_graph.nodes():\n                new_node = InternalTorchIRNode(raw_node, parent=self)\n                if new_node.name == new_node.kind:\n                    new_node.name = _find_new_name(new_node.name, node_names)\n                self.nodes.append(new_node)\n                node_names.add(new_node.name)\n\n            # Add params\n            for name, param in params_dict.items():\n                value = param.detach().cpu().numpy()\n                self.params[name] = value\n\n            # Add inputs\n            for index, _input in enumerate(islice(raw_graph.inputs(), len(input_values))):\n                name = _input.debugName()\n                value = input_values[index]\n                self.inputs[name] = value\n\n            # Add outputs, cutting if @cut_at_symbols is set\n            output_names = cut_at_symbols\n            if output_names is None:\n                output_names = [x.debugName() for x in raw_graph.outputs()]\n            for output in output_names:\n                self.outputs.append(output)\n        else:\n            self.nodes = nodes\n            self.params = params\n            self.inputs = inputs\n            self.outputs = outputs\n\n    def __str__(self):\n        graph_str = \"graph(\\n\"\n        graph_str += self._format_inputs(self.inputs, unpack=True)\n        graph_str += self._format_inputs(self.params)\n        graph_str += \"):\\n\"\n        graph_str += \"\\n\".join([str(x) for x in self.nodes]) + \"\\n\"\n        graph_str += \"return ({})\".format(\", \".join(_ssa_name_list(self.outputs)))\n        return graph_str\n\n    def _format_inputs(self, inputs, unpack=False):\n        def tensor_str(x):\n            return \"Tensor{}\".format(\n                tuple(list(x.shape.shape if unpack else x.shape) + [str(x.dtype)])\n            )\n\n        inp_str = \"\"\n        for k, v in inputs.items():\n            if isinstance(v, (tuple, list)):\n                shape_str = \"({})\".format(\", \".join([tensor_str(x) for x in v]))\n            else:\n                shape_str = tensor_str(v)\n            inp_str += \"    {} : {},\\n\".format(_make_ssa_name(k), shape_str)\n        return inp_str\n\n    def __repr__(self):\n        return str(self)\n\n    def replace_name(self, old_name, new_name):\n        \"\"\"Replaces all instances of @old_name with @new_name in @self.\"\"\"\n\n        # Replace graph inputs/outputs\n        _replace_in_list(self.inputs, old_name, new_name)\n        _replace_in_list(self.outputs, old_name, new_name)\n\n        for node in self.nodes:\n            node.replace_name(old_name, new_name)\n", "path": "coremltools/converters/mil/frontend/torch/internal_graph.py"}]}