We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pytorch track_gradients_dists errors out if some parameters don't have gradients
## 🐛 Bug

When collecting gradients for each layer weight of a model, the function `get_model_layers` errors out if some model parameters don't have gradients.

### Expected behavior

Ignore weights if grad is None.

### Environment

- Aim Version (e.g., 3.11.1)
- Python version 3.10
- pip version 22.0
- Any OS



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `aim/sdk/adapters/pytorch.py`
Content:
```
1 def track_params_dists(model, run):
2     from aim import Distribution
3     data_hist = get_model_layers(model, 'data')
4 
5     for name, params in data_hist.items():
6         if 'weight' in params:
7             run.track(
8                 Distribution(params['weight']),
9                 name=name,
10                 context={
11                     'type': 'data',
12                     'params': 'weights',
13                 }
14             )
15         if 'bias' in params:
16             run.track(
17                 Distribution(params['bias']),
18                 name=name,
19                 context={
20                     'type': 'data',
21                     'params': 'biases',
22                 }
23             )
24 
25 
26 def track_gradients_dists(model, run):
27     from aim import Distribution
28     grad_hist = get_model_layers(model, 'grad')
29 
30     for name, params in grad_hist.items():
31         if 'weight' in params:
32             run.track(
33                 Distribution(params['weight']),
34                 name=name,
35                 context={
36                     'type': 'gradients',
37                     'params': 'weights',
38                 }
39             )
40         if 'bias' in params:
41             run.track(
42                 Distribution(params['bias']),
43                 name=name,
44                 context={
45                     'type': 'gradients',
46                     'params': 'biases',
47                 }
48             )
49 
50 
51 def get_model_layers(model, dt, parent_name=None):
52     layers = {}
53     for name, m in model.named_children():
54         layer_name = '{}__{}'.format(parent_name, name) \
55             if parent_name \
56             else name
57         layer_name += '.{}'.format(type(m).__name__)
58 
59         if len(list(m.named_children())):
60             layers.update(get_model_layers(m, dt, layer_name))
61         else:
62             layers[layer_name] = {}
63             if hasattr(m, 'weight') \
64                     and m.weight is not None \
65                     and hasattr(m.weight, dt):
66                 layers[layer_name]['weight'] = get_pt_tensor(getattr(m.weight, dt)).numpy()
67 
68             if hasattr(m, 'bias') \
69                     and m.bias is not None \
70                     and hasattr(m.bias, dt):
71                 layers[layer_name]['bias'] = get_pt_tensor(getattr(m.bias, dt)).numpy()
72 
73     return layers
74 
75 
76 # Move tensor from GPU to CPU
77 def get_pt_tensor(t):
78     return t.cpu() if hasattr(t, 'is_cuda') and t.is_cuda else t
79
```
--- 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/aim/sdk/adapters/pytorch.py b/aim/sdk/adapters/pytorch.py
--- a/aim/sdk/adapters/pytorch.py
+++ b/aim/sdk/adapters/pytorch.py
@@ -60,15 +60,17 @@
             layers.update(get_model_layers(m, dt, layer_name))
         else:
             layers[layer_name] = {}
-            if hasattr(m, 'weight') \
-                    and m.weight is not None \
-                    and hasattr(m.weight, dt):
-                layers[layer_name]['weight'] = get_pt_tensor(getattr(m.weight, dt)).numpy()
+            weight = None
+            if hasattr(m, 'weight') and m.weight is not None:
+                weight = getattr(m.weight, dt, None)
+                if weight is not None:
+                    layers[layer_name]['weight'] = get_pt_tensor(weight).numpy()
 
-            if hasattr(m, 'bias') \
-                    and m.bias is not None \
-                    and hasattr(m.bias, dt):
-                layers[layer_name]['bias'] = get_pt_tensor(getattr(m.bias, dt)).numpy()
+            bias = None
+            if hasattr(m, 'bias') and m.bias is not None:
+                bias = getattr(m.bias, dt, None)
+                if bias is not None:
+                    layers[layer_name]['bias'] = get_pt_tensor(bias).numpy()
 
     return layers

{"golden_diff": "diff --git a/aim/sdk/adapters/pytorch.py b/aim/sdk/adapters/pytorch.py\n--- a/aim/sdk/adapters/pytorch.py\n+++ b/aim/sdk/adapters/pytorch.py\n@@ -60,15 +60,17 @@\n             layers.update(get_model_layers(m, dt, layer_name))\n         else:\n             layers[layer_name] = {}\n-            if hasattr(m, 'weight') \\\n-                    and m.weight is not None \\\n-                    and hasattr(m.weight, dt):\n-                layers[layer_name]['weight'] = get_pt_tensor(getattr(m.weight, dt)).numpy()\n+            weight = None\n+            if hasattr(m, 'weight') and m.weight is not None:\n+                weight = getattr(m.weight, dt, None)\n+                if weight is not None:\n+                    layers[layer_name]['weight'] = get_pt_tensor(weight).numpy()\n \n-            if hasattr(m, 'bias') \\\n-                    and m.bias is not None \\\n-                    and hasattr(m.bias, dt):\n-                layers[layer_name]['bias'] = get_pt_tensor(getattr(m.bias, dt)).numpy()\n+            bias = None\n+            if hasattr(m, 'bias') and m.bias is not None:\n+                bias = getattr(m.bias, dt, None)\n+                if bias is not None:\n+                    layers[layer_name]['bias'] = get_pt_tensor(bias).numpy()\n \n     return layers\n", "issue": "Pytorch track_gradients_dists errors out if some parameters don't have gradients\n## \ud83d\udc1b Bug\r\n\r\nWhen collecting gradients for each layer weight of a model, the function `get_model_layers` errors out if some model parameters don't have gradients.\r\n\r\n### Expected behavior\r\n\r\nIgnore weights if grad is None.\r\n\r\n### Environment\r\n\r\n- Aim Version (e.g., 3.11.1)\r\n- Python version 3.10\r\n- pip version 22.0\r\n- Any OS\r\n\r\n\n", "before_files": [{"content": "def track_params_dists(model, run):\n    from aim import Distribution\n    data_hist = get_model_layers(model, 'data')\n\n    for name, params in data_hist.items():\n        if 'weight' in params:\n            run.track(\n                Distribution(params['weight']),\n                name=name,\n                context={\n                    'type': 'data',\n                    'params': 'weights',\n                }\n            )\n        if 'bias' in params:\n            run.track(\n                Distribution(params['bias']),\n                name=name,\n                context={\n                    'type': 'data',\n                    'params': 'biases',\n                }\n            )\n\n\ndef track_gradients_dists(model, run):\n    from aim import Distribution\n    grad_hist = get_model_layers(model, 'grad')\n\n    for name, params in grad_hist.items():\n        if 'weight' in params:\n            run.track(\n                Distribution(params['weight']),\n                name=name,\n                context={\n                    'type': 'gradients',\n                    'params': 'weights',\n                }\n            )\n        if 'bias' in params:\n            run.track(\n                Distribution(params['bias']),\n                name=name,\n                context={\n                    'type': 'gradients',\n                    'params': 'biases',\n                }\n            )\n\n\ndef get_model_layers(model, dt, parent_name=None):\n    layers = {}\n    for name, m in model.named_children():\n        layer_name = '{}__{}'.format(parent_name, name) \\\n            if parent_name \\\n            else name\n        layer_name += '.{}'.format(type(m).__name__)\n\n        if len(list(m.named_children())):\n            layers.update(get_model_layers(m, dt, layer_name))\n        else:\n            layers[layer_name] = {}\n            if hasattr(m, 'weight') \\\n                    and m.weight is not None \\\n                    and hasattr(m.weight, dt):\n                layers[layer_name]['weight'] = get_pt_tensor(getattr(m.weight, dt)).numpy()\n\n            if hasattr(m, 'bias') \\\n                    and m.bias is not None \\\n                    and hasattr(m.bias, dt):\n                layers[layer_name]['bias'] = get_pt_tensor(getattr(m.bias, dt)).numpy()\n\n    return layers\n\n\n# Move tensor from GPU to CPU\ndef get_pt_tensor(t):\n    return t.cpu() if hasattr(t, 'is_cuda') and t.is_cuda else t\n", "path": "aim/sdk/adapters/pytorch.py"}], "after_files": [{"content": "def track_params_dists(model, run):\n    from aim import Distribution\n    data_hist = get_model_layers(model, 'data')\n\n    for name, params in data_hist.items():\n        if 'weight' in params:\n            run.track(\n                Distribution(params['weight']),\n                name=name,\n                context={\n                    'type': 'data',\n                    'params': 'weights',\n                }\n            )\n        if 'bias' in params:\n            run.track(\n                Distribution(params['bias']),\n                name=name,\n                context={\n                    'type': 'data',\n                    'params': 'biases',\n                }\n            )\n\n\ndef track_gradients_dists(model, run):\n    from aim import Distribution\n    grad_hist = get_model_layers(model, 'grad')\n\n    for name, params in grad_hist.items():\n        if 'weight' in params:\n            run.track(\n                Distribution(params['weight']),\n                name=name,\n                context={\n                    'type': 'gradients',\n                    'params': 'weights',\n                }\n            )\n        if 'bias' in params:\n            run.track(\n                Distribution(params['bias']),\n                name=name,\n                context={\n                    'type': 'gradients',\n                    'params': 'biases',\n                }\n            )\n\n\ndef get_model_layers(model, dt, parent_name=None):\n    layers = {}\n    for name, m in model.named_children():\n        layer_name = '{}__{}'.format(parent_name, name) \\\n            if parent_name \\\n            else name\n        layer_name += '.{}'.format(type(m).__name__)\n\n        if len(list(m.named_children())):\n            layers.update(get_model_layers(m, dt, layer_name))\n        else:\n            layers[layer_name] = {}\n            weight = None\n            if hasattr(m, 'weight') and m.weight is not None:\n                weight = getattr(m.weight, dt, None)\n                if weight is not None:\n                    layers[layer_name]['weight'] = get_pt_tensor(weight).numpy()\n\n            bias = None\n            if hasattr(m, 'bias') and m.bias is not None:\n                bias = getattr(m.bias, dt, None)\n                if bias is not None:\n                    layers[layer_name]['bias'] = get_pt_tensor(bias).numpy()\n\n    return layers\n\n\n# Move tensor from GPU to CPU\ndef get_pt_tensor(t):\n    return t.cpu() if hasattr(t, 'is_cuda') and t.is_cuda else t\n", "path": "aim/sdk/adapters/pytorch.py"}]}