We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Fitting with log_gpu_memory=True fails in python3.6.
## Bug

Fitting with `log_gpu_memory=True` in the Trainer fails in python3.6 version.

### To Reproduce

1. Use python3.6 version
2. Create any trainer with `log_gpu_memory=True` option.
3. Then fit it.
3. See error:

```
/a/pytorch-lightning/pytorch_lightning/core/memory.py in get_gpu_memory_map()
    237         encoding='utf-8',
    238         capture_output=True,
--> 239         check=True)
    240     # Convert lines into a dictionary
    241     gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]

/usr/lib/python3.6/subprocess.py in run(input, timeout, check, *popenargs, **kwargs)
    421         kwargs['stdin'] = PIPE
    422 
--> 423     with Popen(*popenargs, **kwargs) as process:
    424         try:
    425             stdout, stderr = process.communicate(input, timeout=timeout)

TypeError: __init__() got an unexpected keyword argument 'capture_output'

```


#### Code sample

```
trainer = Trainer(
    log_gpu_memory=True,
   # ....
)
trainer.fit()
```

### Expected behavior

For the same code there is no errors for python3.7

### Environment

pytorch:          1.2.0
Ubuntu 18.04
pytorch-lightning: 
    - installed to pip environment
    - commit 7a1df80f4e98fca
    - python setup.py develop
    - version 0.6.0 
python:         3.6.8
cuda: 10.0, V10.0.130 
cudnn:          7.6.2
GPU: RTX 2080 TI

### Additional context

In the `setup.py`
 python_requires='>=3.6',

But  `capture_output` is used in  `subprocess.run` calling, which is valid only for python3.7
See also workaround to maintain python3.6:
https://stackoverflow.com/questions/53209127/



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pytorch_lightning/core/memory.py`
Content:
```
1 '''
2 Generates a summary of a model's layers and dimensionality
3 '''
4 
5 import gc
6 import os
7 import subprocess
8 
9 import numpy as np
10 import pandas as pd
11 import torch
12 import logging
13 
14 
15 class ModelSummary(object):
16 
17     def __init__(self, model, mode='full'):
18         '''
19         Generates summaries of model layers and dimensions.
20         '''
21         self.model = model
22         self.mode = mode
23         self.in_sizes = []
24         self.out_sizes = []
25 
26         self.summarize()
27 
28     def __str__(self):
29         return self.summary.__str__()
30 
31     def __repr__(self):
32         return self.summary.__str__()
33 
34     def named_modules(self):
35         if self.mode == 'full':
36             mods = self.model.named_modules()
37             mods = list(mods)[1:]  # do not include root module (LightningModule)
38         elif self.mode == 'top':
39             # the children are the top-level modules
40             mods = self.model.named_children()
41         else:
42             mods = []
43         return list(mods)
44 
45     def get_variable_sizes(self):
46         '''Run sample input through each layer to get output sizes'''
47         mods = self.named_modules()
48         in_sizes = []
49         out_sizes = []
50         input_ = self.model.example_input_array
51 
52         if self.model.on_gpu:
53             device = next(self.model.parameters()).get_device()
54             # test if input is a list or a tuple
55             if isinstance(input_, (list, tuple)):
56                 input_ = [input_i.cuda(device) if torch.is_tensor(input_i) else input_i
57                           for input_i in input_]
58             else:
59                 input_ = input_.cuda(device)
60 
61         if self.model.trainer.use_amp:
62             # test if it is not a list or a tuple
63             if isinstance(input_, (list, tuple)):
64                 input_ = [input_i.half() if torch.is_tensor(input_i) else input_i
65                           for input_i in input_]
66             else:
67                 input_ = input_.half()
68 
69         with torch.no_grad():
70 
71             for _, m in mods:
72                 if isinstance(input_, (list, tuple)):  # pragma: no cover
73                     out = m(*input_)
74                 else:
75                     out = m(input_)
76 
77                 if isinstance(input_, (list, tuple)):  # pragma: no cover
78                     in_size = []
79                     for x in input_:
80                         if type(x) is list:
81                             in_size.append(len(x))
82                         else:
83                             in_size.append(x.size())
84                 else:
85                     in_size = np.array(input_.size())
86 
87                 in_sizes.append(in_size)
88 
89                 if isinstance(out, (list, tuple)):  # pragma: no cover
90                     out_size = np.asarray([x.size() for x in out])
91                 else:
92                     out_size = np.array(out.size())
93 
94                 out_sizes.append(out_size)
95                 input_ = out
96 
97         self.in_sizes = in_sizes
98         self.out_sizes = out_sizes
99         assert len(in_sizes) == len(out_sizes)
100         return
101 
102     def get_layer_names(self):
103         '''Collect Layer Names'''
104         mods = self.named_modules()
105         names = []
106         layers = []
107         for name, m in mods:
108             names += [name]
109             layers += [str(m.__class__)]
110 
111         layer_types = [x.split('.')[-1][:-2] for x in layers]
112 
113         self.layer_names = names
114         self.layer_types = layer_types
115         return
116 
117     def get_parameter_sizes(self):
118         '''Get sizes of all parameters in `model`'''
119         mods = self.named_modules()
120         sizes = []
121         for _, m in mods:
122             p = list(m.parameters())
123             modsz = []
124             for j in range(len(p)):
125                 modsz.append(np.array(p[j].size()))
126             sizes.append(modsz)
127 
128         self.param_sizes = sizes
129         return
130 
131     def get_parameter_nums(self):
132         '''Get number of parameters in each layer'''
133         param_nums = []
134         for mod in self.param_sizes:
135             all_params = 0
136             for p in mod:
137                 all_params += np.prod(p)
138             param_nums.append(all_params)
139         self.param_nums = param_nums
140         return
141 
142     def make_summary(self):
143         '''
144         Makes a summary listing with:
145 
146         Layer Name, Layer Type, Input Size, Output Size, Number of Parameters
147         '''
148 
149         cols = ['Name', 'Type', 'Params']
150         if self.model.example_input_array is not None:
151             cols.extend(['In_sizes', 'Out_sizes'])
152 
153         df = pd.DataFrame(np.zeros((len(self.layer_names), len(cols))))
154         df.columns = cols
155 
156         df['Name'] = self.layer_names
157         df['Type'] = self.layer_types
158         df['Params'] = self.param_nums
159         df['Params'] = df['Params'].map(get_human_readable_count)
160 
161         if self.model.example_input_array is not None:
162             df['In_sizes'] = self.in_sizes
163             df['Out_sizes'] = self.out_sizes
164 
165         self.summary = df
166         return
167 
168     def summarize(self):
169         self.get_layer_names()
170         self.get_parameter_sizes()
171         self.get_parameter_nums()
172 
173         if self.model.example_input_array is not None:
174             self.get_variable_sizes()
175         self.make_summary()
176 
177 
178 def print_mem_stack():  # pragma: no cover
179     for obj in gc.get_objects():
180         try:
181             if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):
182                 logging.info(type(obj), obj.size())
183         except Exception:
184             pass
185 
186 
187 def count_mem_items():  # pragma: no cover
188     num_params = 0
189     num_tensors = 0
190     for obj in gc.get_objects():
191         try:
192             if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):
193                 obj_type = str(type(obj))
194                 if 'parameter' in obj_type:
195                     num_params += 1
196                 else:
197                     num_tensors += 1
198         except Exception:
199             pass
200 
201     return num_params, num_tensors
202 
203 
204 def get_memory_profile(mode):
205     """
206     'all' means return memory for all gpus
207     'min_max' means return memory for max and min
208     :param mode:
209     :return:
210     """
211     memory_map = get_gpu_memory_map()
212 
213     if mode == 'min_max':
214         min_index, min_memory = min(memory_map.items(), key=lambda item: item[1])
215         max_index, max_memory = max(memory_map.items(), key=lambda item: item[1])
216 
217         memory_map = {min_index: min_memory, max_index: max_memory}
218 
219     return memory_map
220 
221 
222 def get_gpu_memory_map():
223     """Get the current gpu usage.
224 
225     Returns
226     -------
227     usage: dict
228         Keys are device ids as integers.
229         Values are memory usage as integers in MB.
230     """
231     result = subprocess.run(
232         [
233             'nvidia-smi',
234             '--query-gpu=memory.used',
235             '--format=csv,nounits,noheader',
236         ],
237         encoding='utf-8',
238         capture_output=True,
239         check=True)
240     # Convert lines into a dictionary
241     gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]
242     gpu_memory_map = {f'gpu_{index}': memory for index, memory in enumerate(gpu_memory)}
243     return gpu_memory_map
244 
245 
246 def get_human_readable_count(number):
247     """
248     Abbreviates an integer number with K, M, B, T for thousands, millions,
249     billions and trillions, respectively.
250     Examples:
251         123     -> 123
252         1234    -> 1 K       (one thousand)
253         2e6     -> 2 M       (two million)
254         3e9     -> 3 B       (three billion)
255         4e12    -> 4 T       (four trillion)
256         5e15    -> 5,000 T
257     :param number: a positive integer number
258     :returns a string formatted according to the pattern described above.
259     """
260     assert number >= 0
261     labels = [' ', 'K', 'M', 'B', 'T']
262     num_digits = int(np.floor(np.log10(number)) + 1 if number > 0 else 1)
263     num_groups = int(np.ceil(num_digits / 3))
264     num_groups = min(num_groups, len(labels))  # don't abbreviate beyond trillions
265     shift = -3 * (num_groups - 1)
266     number = number * (10 ** shift)
267     index = num_groups - 1
268     return f'{int(number):,d} {labels[index]}'
269
```
--- 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/pytorch_lightning/core/memory.py b/pytorch_lightning/core/memory.py
--- a/pytorch_lightning/core/memory.py
+++ b/pytorch_lightning/core/memory.py
@@ -5,6 +5,7 @@
 import gc
 import os
 import subprocess
+from subprocess import PIPE
 
 import numpy as np
 import pandas as pd
@@ -235,7 +236,8 @@
             '--format=csv,nounits,noheader',
         ],
         encoding='utf-8',
-        capture_output=True,
+        # capture_output=True,          # valid for python version >=3.7
+        stdout=PIPE, stderr=PIPE,       # for backward compatibility with python version 3.6
         check=True)
     # Convert lines into a dictionary
     gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]

{"golden_diff": "diff --git a/pytorch_lightning/core/memory.py b/pytorch_lightning/core/memory.py\n--- a/pytorch_lightning/core/memory.py\n+++ b/pytorch_lightning/core/memory.py\n@@ -5,6 +5,7 @@\n import gc\n import os\n import subprocess\n+from subprocess import PIPE\n \n import numpy as np\n import pandas as pd\n@@ -235,7 +236,8 @@\n             '--format=csv,nounits,noheader',\n         ],\n         encoding='utf-8',\n-        capture_output=True,\n+        # capture_output=True,          # valid for python version >=3.7\n+        stdout=PIPE, stderr=PIPE,       # for backward compatibility with python version 3.6\n         check=True)\n     # Convert lines into a dictionary\n     gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]\n", "issue": "Fitting with log_gpu_memory=True fails in python3.6.\n## Bug\r\n\r\nFitting with `log_gpu_memory=True` in the Trainer fails in python3.6 version.\r\n\r\n### To Reproduce\r\n\r\n1. Use python3.6 version\r\n2. Create any trainer with `log_gpu_memory=True` option.\r\n3. Then fit it.\r\n3. See error:\r\n\r\n```\r\n/a/pytorch-lightning/pytorch_lightning/core/memory.py in get_gpu_memory_map()\r\n    237         encoding='utf-8',\r\n    238         capture_output=True,\r\n--> 239         check=True)\r\n    240     # Convert lines into a dictionary\r\n    241     gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]\r\n\r\n/usr/lib/python3.6/subprocess.py in run(input, timeout, check, *popenargs, **kwargs)\r\n    421         kwargs['stdin'] = PIPE\r\n    422 \r\n--> 423     with Popen(*popenargs, **kwargs) as process:\r\n    424         try:\r\n    425             stdout, stderr = process.communicate(input, timeout=timeout)\r\n\r\nTypeError: __init__() got an unexpected keyword argument 'capture_output'\r\n\r\n```\r\n\r\n\r\n#### Code sample\r\n\r\n```\r\ntrainer = Trainer(\r\n    log_gpu_memory=True,\r\n   # ....\r\n)\r\ntrainer.fit()\r\n```\r\n\r\n### Expected behavior\r\n\r\nFor the same code there is no errors for python3.7\r\n\r\n### Environment\r\n\r\npytorch:          1.2.0\r\nUbuntu 18.04\r\npytorch-lightning: \r\n    - installed to pip environment\r\n    - commit 7a1df80f4e98fca\r\n    - python setup.py develop\r\n    - version 0.6.0 \r\npython:         3.6.8\r\ncuda: 10.0, V10.0.130 \r\ncudnn:          7.6.2\r\nGPU: RTX 2080 TI\r\n\r\n### Additional context\r\n\r\nIn the `setup.py`\r\n python_requires='>=3.6',\r\n\r\nBut  `capture_output` is used in  `subprocess.run` calling, which is valid only for python3.7\r\nSee also workaround to maintain python3.6:\r\nhttps://stackoverflow.com/questions/53209127/\r\n\r\n\n", "before_files": [{"content": "'''\nGenerates a summary of a model's layers and dimensionality\n'''\n\nimport gc\nimport os\nimport subprocess\n\nimport numpy as np\nimport pandas as pd\nimport torch\nimport logging\n\n\nclass ModelSummary(object):\n\n    def __init__(self, model, mode='full'):\n        '''\n        Generates summaries of model layers and dimensions.\n        '''\n        self.model = model\n        self.mode = mode\n        self.in_sizes = []\n        self.out_sizes = []\n\n        self.summarize()\n\n    def __str__(self):\n        return self.summary.__str__()\n\n    def __repr__(self):\n        return self.summary.__str__()\n\n    def named_modules(self):\n        if self.mode == 'full':\n            mods = self.model.named_modules()\n            mods = list(mods)[1:]  # do not include root module (LightningModule)\n        elif self.mode == 'top':\n            # the children are the top-level modules\n            mods = self.model.named_children()\n        else:\n            mods = []\n        return list(mods)\n\n    def get_variable_sizes(self):\n        '''Run sample input through each layer to get output sizes'''\n        mods = self.named_modules()\n        in_sizes = []\n        out_sizes = []\n        input_ = self.model.example_input_array\n\n        if self.model.on_gpu:\n            device = next(self.model.parameters()).get_device()\n            # test if input is a list or a tuple\n            if isinstance(input_, (list, tuple)):\n                input_ = [input_i.cuda(device) if torch.is_tensor(input_i) else input_i\n                          for input_i in input_]\n            else:\n                input_ = input_.cuda(device)\n\n        if self.model.trainer.use_amp:\n            # test if it is not a list or a tuple\n            if isinstance(input_, (list, tuple)):\n                input_ = [input_i.half() if torch.is_tensor(input_i) else input_i\n                          for input_i in input_]\n            else:\n                input_ = input_.half()\n\n        with torch.no_grad():\n\n            for _, m in mods:\n                if isinstance(input_, (list, tuple)):  # pragma: no cover\n                    out = m(*input_)\n                else:\n                    out = m(input_)\n\n                if isinstance(input_, (list, tuple)):  # pragma: no cover\n                    in_size = []\n                    for x in input_:\n                        if type(x) is list:\n                            in_size.append(len(x))\n                        else:\n                            in_size.append(x.size())\n                else:\n                    in_size = np.array(input_.size())\n\n                in_sizes.append(in_size)\n\n                if isinstance(out, (list, tuple)):  # pragma: no cover\n                    out_size = np.asarray([x.size() for x in out])\n                else:\n                    out_size = np.array(out.size())\n\n                out_sizes.append(out_size)\n                input_ = out\n\n        self.in_sizes = in_sizes\n        self.out_sizes = out_sizes\n        assert len(in_sizes) == len(out_sizes)\n        return\n\n    def get_layer_names(self):\n        '''Collect Layer Names'''\n        mods = self.named_modules()\n        names = []\n        layers = []\n        for name, m in mods:\n            names += [name]\n            layers += [str(m.__class__)]\n\n        layer_types = [x.split('.')[-1][:-2] for x in layers]\n\n        self.layer_names = names\n        self.layer_types = layer_types\n        return\n\n    def get_parameter_sizes(self):\n        '''Get sizes of all parameters in `model`'''\n        mods = self.named_modules()\n        sizes = []\n        for _, m in mods:\n            p = list(m.parameters())\n            modsz = []\n            for j in range(len(p)):\n                modsz.append(np.array(p[j].size()))\n            sizes.append(modsz)\n\n        self.param_sizes = sizes\n        return\n\n    def get_parameter_nums(self):\n        '''Get number of parameters in each layer'''\n        param_nums = []\n        for mod in self.param_sizes:\n            all_params = 0\n            for p in mod:\n                all_params += np.prod(p)\n            param_nums.append(all_params)\n        self.param_nums = param_nums\n        return\n\n    def make_summary(self):\n        '''\n        Makes a summary listing with:\n\n        Layer Name, Layer Type, Input Size, Output Size, Number of Parameters\n        '''\n\n        cols = ['Name', 'Type', 'Params']\n        if self.model.example_input_array is not None:\n            cols.extend(['In_sizes', 'Out_sizes'])\n\n        df = pd.DataFrame(np.zeros((len(self.layer_names), len(cols))))\n        df.columns = cols\n\n        df['Name'] = self.layer_names\n        df['Type'] = self.layer_types\n        df['Params'] = self.param_nums\n        df['Params'] = df['Params'].map(get_human_readable_count)\n\n        if self.model.example_input_array is not None:\n            df['In_sizes'] = self.in_sizes\n            df['Out_sizes'] = self.out_sizes\n\n        self.summary = df\n        return\n\n    def summarize(self):\n        self.get_layer_names()\n        self.get_parameter_sizes()\n        self.get_parameter_nums()\n\n        if self.model.example_input_array is not None:\n            self.get_variable_sizes()\n        self.make_summary()\n\n\ndef print_mem_stack():  # pragma: no cover\n    for obj in gc.get_objects():\n        try:\n            if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):\n                logging.info(type(obj), obj.size())\n        except Exception:\n            pass\n\n\ndef count_mem_items():  # pragma: no cover\n    num_params = 0\n    num_tensors = 0\n    for obj in gc.get_objects():\n        try:\n            if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):\n                obj_type = str(type(obj))\n                if 'parameter' in obj_type:\n                    num_params += 1\n                else:\n                    num_tensors += 1\n        except Exception:\n            pass\n\n    return num_params, num_tensors\n\n\ndef get_memory_profile(mode):\n    \"\"\"\n    'all' means return memory for all gpus\n    'min_max' means return memory for max and min\n    :param mode:\n    :return:\n    \"\"\"\n    memory_map = get_gpu_memory_map()\n\n    if mode == 'min_max':\n        min_index, min_memory = min(memory_map.items(), key=lambda item: item[1])\n        max_index, max_memory = max(memory_map.items(), key=lambda item: item[1])\n\n        memory_map = {min_index: min_memory, max_index: max_memory}\n\n    return memory_map\n\n\ndef get_gpu_memory_map():\n    \"\"\"Get the current gpu usage.\n\n    Returns\n    -------\n    usage: dict\n        Keys are device ids as integers.\n        Values are memory usage as integers in MB.\n    \"\"\"\n    result = subprocess.run(\n        [\n            'nvidia-smi',\n            '--query-gpu=memory.used',\n            '--format=csv,nounits,noheader',\n        ],\n        encoding='utf-8',\n        capture_output=True,\n        check=True)\n    # Convert lines into a dictionary\n    gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]\n    gpu_memory_map = {f'gpu_{index}': memory for index, memory in enumerate(gpu_memory)}\n    return gpu_memory_map\n\n\ndef get_human_readable_count(number):\n    \"\"\"\n    Abbreviates an integer number with K, M, B, T for thousands, millions,\n    billions and trillions, respectively.\n    Examples:\n        123     -> 123\n        1234    -> 1 K       (one thousand)\n        2e6     -> 2 M       (two million)\n        3e9     -> 3 B       (three billion)\n        4e12    -> 4 T       (four trillion)\n        5e15    -> 5,000 T\n    :param number: a positive integer number\n    :returns a string formatted according to the pattern described above.\n    \"\"\"\n    assert number >= 0\n    labels = [' ', 'K', 'M', 'B', 'T']\n    num_digits = int(np.floor(np.log10(number)) + 1 if number > 0 else 1)\n    num_groups = int(np.ceil(num_digits / 3))\n    num_groups = min(num_groups, len(labels))  # don't abbreviate beyond trillions\n    shift = -3 * (num_groups - 1)\n    number = number * (10 ** shift)\n    index = num_groups - 1\n    return f'{int(number):,d} {labels[index]}'\n", "path": "pytorch_lightning/core/memory.py"}], "after_files": [{"content": "'''\nGenerates a summary of a model's layers and dimensionality\n'''\n\nimport gc\nimport os\nimport subprocess\nfrom subprocess import PIPE\n\nimport numpy as np\nimport pandas as pd\nimport torch\nimport logging\n\n\nclass ModelSummary(object):\n\n    def __init__(self, model, mode='full'):\n        '''\n        Generates summaries of model layers and dimensions.\n        '''\n        self.model = model\n        self.mode = mode\n        self.in_sizes = []\n        self.out_sizes = []\n\n        self.summarize()\n\n    def __str__(self):\n        return self.summary.__str__()\n\n    def __repr__(self):\n        return self.summary.__str__()\n\n    def named_modules(self):\n        if self.mode == 'full':\n            mods = self.model.named_modules()\n            mods = list(mods)[1:]  # do not include root module (LightningModule)\n        elif self.mode == 'top':\n            # the children are the top-level modules\n            mods = self.model.named_children()\n        else:\n            mods = []\n        return list(mods)\n\n    def get_variable_sizes(self):\n        '''Run sample input through each layer to get output sizes'''\n        mods = self.named_modules()\n        in_sizes = []\n        out_sizes = []\n        input_ = self.model.example_input_array\n\n        if self.model.on_gpu:\n            device = next(self.model.parameters()).get_device()\n            # test if input is a list or a tuple\n            if isinstance(input_, (list, tuple)):\n                input_ = [input_i.cuda(device) if torch.is_tensor(input_i) else input_i\n                          for input_i in input_]\n            else:\n                input_ = input_.cuda(device)\n\n        if self.model.trainer.use_amp:\n            # test if it is not a list or a tuple\n            if isinstance(input_, (list, tuple)):\n                input_ = [input_i.half() if torch.is_tensor(input_i) else input_i\n                          for input_i in input_]\n            else:\n                input_ = input_.half()\n\n        with torch.no_grad():\n\n            for _, m in mods:\n                if isinstance(input_, (list, tuple)):  # pragma: no cover\n                    out = m(*input_)\n                else:\n                    out = m(input_)\n\n                if isinstance(input_, (list, tuple)):  # pragma: no cover\n                    in_size = []\n                    for x in input_:\n                        if type(x) is list:\n                            in_size.append(len(x))\n                        else:\n                            in_size.append(x.size())\n                else:\n                    in_size = np.array(input_.size())\n\n                in_sizes.append(in_size)\n\n                if isinstance(out, (list, tuple)):  # pragma: no cover\n                    out_size = np.asarray([x.size() for x in out])\n                else:\n                    out_size = np.array(out.size())\n\n                out_sizes.append(out_size)\n                input_ = out\n\n        self.in_sizes = in_sizes\n        self.out_sizes = out_sizes\n        assert len(in_sizes) == len(out_sizes)\n        return\n\n    def get_layer_names(self):\n        '''Collect Layer Names'''\n        mods = self.named_modules()\n        names = []\n        layers = []\n        for name, m in mods:\n            names += [name]\n            layers += [str(m.__class__)]\n\n        layer_types = [x.split('.')[-1][:-2] for x in layers]\n\n        self.layer_names = names\n        self.layer_types = layer_types\n        return\n\n    def get_parameter_sizes(self):\n        '''Get sizes of all parameters in `model`'''\n        mods = self.named_modules()\n        sizes = []\n        for _, m in mods:\n            p = list(m.parameters())\n            modsz = []\n            for j in range(len(p)):\n                modsz.append(np.array(p[j].size()))\n            sizes.append(modsz)\n\n        self.param_sizes = sizes\n        return\n\n    def get_parameter_nums(self):\n        '''Get number of parameters in each layer'''\n        param_nums = []\n        for mod in self.param_sizes:\n            all_params = 0\n            for p in mod:\n                all_params += np.prod(p)\n            param_nums.append(all_params)\n        self.param_nums = param_nums\n        return\n\n    def make_summary(self):\n        '''\n        Makes a summary listing with:\n\n        Layer Name, Layer Type, Input Size, Output Size, Number of Parameters\n        '''\n\n        cols = ['Name', 'Type', 'Params']\n        if self.model.example_input_array is not None:\n            cols.extend(['In_sizes', 'Out_sizes'])\n\n        df = pd.DataFrame(np.zeros((len(self.layer_names), len(cols))))\n        df.columns = cols\n\n        df['Name'] = self.layer_names\n        df['Type'] = self.layer_types\n        df['Params'] = self.param_nums\n        df['Params'] = df['Params'].map(get_human_readable_count)\n\n        if self.model.example_input_array is not None:\n            df['In_sizes'] = self.in_sizes\n            df['Out_sizes'] = self.out_sizes\n\n        self.summary = df\n        return\n\n    def summarize(self):\n        self.get_layer_names()\n        self.get_parameter_sizes()\n        self.get_parameter_nums()\n\n        if self.model.example_input_array is not None:\n            self.get_variable_sizes()\n        self.make_summary()\n\n\ndef print_mem_stack():  # pragma: no cover\n    for obj in gc.get_objects():\n        try:\n            if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):\n                logging.info(type(obj), obj.size())\n        except Exception:\n            pass\n\n\ndef count_mem_items():  # pragma: no cover\n    num_params = 0\n    num_tensors = 0\n    for obj in gc.get_objects():\n        try:\n            if torch.is_tensor(obj) or (hasattr(obj, 'data') and torch.is_tensor(obj.data)):\n                obj_type = str(type(obj))\n                if 'parameter' in obj_type:\n                    num_params += 1\n                else:\n                    num_tensors += 1\n        except Exception:\n            pass\n\n    return num_params, num_tensors\n\n\ndef get_memory_profile(mode):\n    \"\"\"\n    'all' means return memory for all gpus\n    'min_max' means return memory for max and min\n    :param mode:\n    :return:\n    \"\"\"\n    memory_map = get_gpu_memory_map()\n\n    if mode == 'min_max':\n        min_index, min_memory = min(memory_map.items(), key=lambda item: item[1])\n        max_index, max_memory = max(memory_map.items(), key=lambda item: item[1])\n\n        memory_map = {min_index: min_memory, max_index: max_memory}\n\n    return memory_map\n\n\ndef get_gpu_memory_map():\n    \"\"\"Get the current gpu usage.\n\n    Returns\n    -------\n    usage: dict\n        Keys are device ids as integers.\n        Values are memory usage as integers in MB.\n    \"\"\"\n    result = subprocess.run(\n        [\n            'nvidia-smi',\n            '--query-gpu=memory.used',\n            '--format=csv,nounits,noheader',\n        ],\n        encoding='utf-8',\n        # capture_output=True,          # valid for python version >=3.7\n        stdout=PIPE, stderr=PIPE,       # for backward compatibility with python version 3.6\n        check=True)\n    # Convert lines into a dictionary\n    gpu_memory = [int(x) for x in result.stdout.strip().split(os.linesep)]\n    gpu_memory_map = {f'gpu_{index}': memory for index, memory in enumerate(gpu_memory)}\n    return gpu_memory_map\n\n\ndef get_human_readable_count(number):\n    \"\"\"\n    Abbreviates an integer number with K, M, B, T for thousands, millions,\n    billions and trillions, respectively.\n    Examples:\n        123     -> 123\n        1234    -> 1 K       (one thousand)\n        2e6     -> 2 M       (two million)\n        3e9     -> 3 B       (three billion)\n        4e12    -> 4 T       (four trillion)\n        5e15    -> 5,000 T\n    :param number: a positive integer number\n    :returns a string formatted according to the pattern described above.\n    \"\"\"\n    assert number >= 0\n    labels = [' ', 'K', 'M', 'B', 'T']\n    num_digits = int(np.floor(np.log10(number)) + 1 if number > 0 else 1)\n    num_groups = int(np.ceil(num_digits / 3))\n    num_groups = min(num_groups, len(labels))  # don't abbreviate beyond trillions\n    shift = -3 * (num_groups - 1)\n    number = number * (10 ** shift)\n    index = num_groups - 1\n    return f'{int(number):,d} {labels[index]}'\n", "path": "pytorch_lightning/core/memory.py"}]}