We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Tutorial notebook Exception
I downloaded the notebook available on https://gluon-ts.mxnet.io/examples/forecasting/tutorial.html, and run it on my local laptop (Darwin Kernel Version 16.7.0, Anaconda3 Distro, Python 3.7.3, Jupyter 4.4.0, gluonts 0.1.1) and get the following exception at:

```
from gluonts.model.simple_feedforward import SimpleFeedForwardEstimator
from gluonts.trainer import Trainer
```

```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/python/anaconda3/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)
    261         try:
--> 262             if issubclass(type_, val_type):
    263                 return validators

TypeError: issubclass() arg 1 must be a class

The above exception was the direct cause of the following exception:

RuntimeError                              Traceback (most recent call last)
<ipython-input-13-1fca1cb620ad> in <module>
----> 1 from gluonts.model.simple_feedforward import SimpleFeedForwardEstimator
      2 from gluonts.trainer import Trainer

~/python/anaconda3/lib/python3.7/site-packages/gluonts/model/simple_feedforward/__init__.py in <module>
      1 # Relative imports
----> 2 from ._estimator import SimpleFeedForwardEstimator
      3 
      4 __all__ = ['SimpleFeedForwardEstimator']

~/python/anaconda3/lib/python3.7/site-packages/gluonts/model/simple_feedforward/_estimator.py in <module>
      7 # First-party imports
      8 from gluonts.core.component import validated
----> 9 from gluonts.distribution import DistributionOutput, StudentTOutput
     10 from gluonts.model.estimator import GluonEstimator
     11 from gluonts.model.predictor import Predictor, RepresentableBlockPredictor

~/python/anaconda3/lib/python3.7/site-packages/gluonts/distribution/__init__.py in <module>
     14 # Relative imports
     15 from . import bijection
---> 16 from .binned import Binned, BinnedOutput
     17 from .distribution import Distribution
     18 from .distribution_output import DistributionOutput

~/python/anaconda3/lib/python3.7/site-packages/gluonts/distribution/binned.py in <module>
    166 
    167 
--> 168 class BinnedOutput(DistributionOutput):
    169     distr_cls: type = Binned
    170 

~/python/anaconda3/lib/python3.7/site-packages/gluonts/distribution/binned.py in BinnedOutput()
    170 
    171     @validated()
--> 172     def __init__(self, bin_centers: List) -> None:
    173         # cannot pass directly nd.array because it is not serializable
    174         bc = mx.nd.array(bin_centers)

~/python/anaconda3/lib/python3.7/site-packages/gluonts/core/component.py in validator(ctor)
    167                 f'{ctor_clsnme}Model',
    168                 __config__=ConfigBase.Config,
--> 169                 **ctor_fields,
    170             )
    171         else:

~/python/anaconda3/lib/python3.7/site-packages/pydantic/main.py in create_model(model_name, __config__, __base__, **field_definitions)
    408                 annotation=f_annotation,
    409                 class_validators=vg.get_validators(f_name),
--> 410                 config=config,
    411             )
    412 

~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in infer(cls, name, value, annotation, class_validators, config)
    105             required=required,
    106             model_config=config,
--> 107             schema=schema,
    108         )
    109 

~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in __init__(self, name, type_, class_validators, default, required, model_config, alias, allow_none, schema)
     85         self.shape: Shape = Shape.SINGLETON
     86         self._schema: Schema = schema
---> 87         self.prepare()
     88 
     89     @classmethod

~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in prepare(self)
    134 
    135         self._populate_sub_fields()
--> 136         self._populate_validators()
    137 
    138     def schema(self, by_alias=True):

~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in _populate_validators(self)
    264                 *tuple(v.func for v in self.class_validators if not v.whole and v.pre),
    265                 *(get_validators() if get_validators else find_validators(self.type_,
--> 266                                                                           self.model_config.arbitrary_types_allowed)),
    267                 *tuple(v.func for v in self.class_validators if not v.whole and not v.pre),
    268             )

~/python/anaconda3/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)
    263                 return validators
    264         except TypeError as e:
--> 265             raise RuntimeError(f'error checking inheritance of {type_!r} (type: {display_as_type(type_)})') from e
    266 
    267     if arbitrary_types_allowed:

RuntimeError: error checking inheritance of ~T (type: T)
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/gluonts/distribution/binned.py`
Content:
```
1 # Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License").
4 # You may not use this file except in compliance with the License.
5 # A copy of the License is located at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # or in the "license" file accompanying this file. This file is distributed
10 # on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11 # express or implied. See the License for the specific language governing
12 # permissions and limitations under the License.
13 
14 # Standard library imports
15 from typing import Tuple, List
16 
17 # Third-party imports
18 import mxnet as mx
19 from mxnet import gluon
20 
21 # First-party imports
22 from gluonts.core.component import validated
23 from gluonts.model.common import Tensor
24 
25 # Relative imports
26 from .distribution import Distribution, _sample_multiple, getF
27 from .distribution_output import DistributionOutput
28 
29 
30 class Binned(Distribution):
31     r"""
32     A binned distribution defined by a set of bins via
33     bin centers and bin probabilities.
34 
35     Parameters
36     ----------
37     bin_probs
38         Tensor containing the bin probabilities, of shape `(*batch_shape, num_bins)`.
39     bin_centers
40         Tensor containing the bin centers, of shape `(*batch_shape, num_bins)`.
41     F
42     """
43 
44     is_reparameterizable = False
45 
46     def __init__(self, bin_probs: Tensor, bin_centers: Tensor, F=None) -> None:
47         self.bin_centers = bin_centers
48         self.bin_probs = bin_probs
49         self.F = F if F else getF(bin_probs)
50 
51         self.bin_edges = Binned._compute_edges(self.F, bin_centers)
52 
53     @staticmethod
54     def _compute_edges(F, bin_centers: Tensor) -> Tensor:
55         r"""
56         Computes the edges of the bins based on the centers. The first and last edge are set to :math:`10^{-10}` and
57         :math:`10^{10}`, repsectively.
58 
59         Parameters
60         ----------
61         F
62         bin_centers
63             Tensor of shape `(*batch_shape, num_bins)`.
64 
65         Returns
66         -------
67         Tensor
68             Tensor of shape (*gamma.shape, num_bins+1)
69         """
70 
71         low = (
72             F.zeros_like(bin_centers.slice_axis(axis=-1, begin=0, end=1))
73             - 1.0e10
74         )
75         high = (
76             F.zeros_like(bin_centers.slice_axis(axis=-1, begin=0, end=1))
77             + 1.0e10
78         )
79 
80         means = (
81             bin_centers.slice_axis(axis=-1, begin=1, end=None)
82             + bin_centers.slice_axis(axis=-1, begin=0, end=-1)
83         ) / 2.0
84 
85         return F.concat(low, means, high, dim=-1)
86 
87     @property
88     def batch_shape(self) -> Tuple:
89         return self.bin_centers.shape[:-1]
90 
91     @property
92     def event_shape(self) -> Tuple:
93         return ()
94 
95     @property
96     def event_dim(self) -> int:
97         return 0
98 
99     @property
100     def mean(self):
101         return (self.bin_probs * self.bin_centers).sum(axis=-1)
102 
103     @property
104     def stddev(self):
105         Ex2 = (self.bin_probs * self.bin_centers.square()).sum(axis=-1)
106         return (Ex2 - self.mean.square()).sqrt()
107 
108     def log_prob(self, x):
109         x = x.expand_dims(axis=-1)
110         # TODO: when mxnet has searchsorted replace this
111         left_edges = self.bin_edges.slice_axis(axis=-1, begin=0, end=-1)
112         right_edges = self.bin_edges.slice_axis(axis=-1, begin=1, end=None)
113         mask = self.F.broadcast_lesser_equal(
114             left_edges, x
115         ) * self.F.broadcast_lesser(x, right_edges)
116         return (self.bin_probs.log() * mask).sum(axis=-1)
117 
118     def sample(self, num_samples=None):
119         def s(bin_probs):
120             F = self.F
121             indices = F.sample_multinomial(bin_probs)
122             if num_samples is None:
123                 return self.bin_centers.pick(indices, -1).reshape_like(
124                     F.zeros_like(indices.astype('float32'))
125                 )
126             else:
127                 return F.repeat(
128                     F.expand_dims(self.bin_centers, axis=0),
129                     repeats=num_samples,
130                     axis=0,
131                 ).pick(indices, -1)
132 
133         return _sample_multiple(s, self.bin_probs, num_samples=num_samples)
134 
135 
136 class BinnedArgs(gluon.HybridBlock):
137     def __init__(self, bin_centers: mx.nd.NDArray, **kwargs) -> None:
138         super().__init__(**kwargs)
139         with self.name_scope():
140             self.bin_centers = self.params.get_constant(
141                 'bincenters', bin_centers
142             )
143             self.num_bins = bin_centers.shape[0]
144 
145             # needs to be named self.proj for consistency with the ArgProj class and the inference tests
146             self.proj = gluon.nn.HybridSequential()
147             self.proj.add(
148                 gluon.nn.Dense(
149                     self.num_bins,
150                     prefix='binproj',
151                     flatten=False,
152                     weight_initializer=mx.init.Xavier(),
153                 )
154             )
155             self.proj.add(gluon.nn.HybridLambda('softmax'))
156 
157     def hybrid_forward(
158         self, F, x: Tensor, bin_centers: Tensor, **kwargs
159     ) -> Tuple[Tensor, Tensor]:
160         ps = self.proj(x)
161         return (
162             ps.reshape(shape=(-2, -1, self.num_bins), reverse=1),
163             # For some reason hybridize does not work when returning constants directly
164             bin_centers + 0.0,
165         )
166 
167 
168 class BinnedOutput(DistributionOutput):
169     distr_cls: type = Binned
170 
171     @validated()
172     def __init__(self, bin_centers: List) -> None:
173         # cannot pass directly nd.array because it is not serializable
174         bc = mx.nd.array(bin_centers)
175         assert len(bc.shape) == 1
176         self.bin_centers = bc
177 
178     def get_args_proj(self, *args, **kwargs) -> gluon.nn.HybridBlock:
179         return BinnedArgs(self.bin_centers)
180 
181     def distribution(self, args, scale=None) -> Binned:
182         probs, centers = args
183         F = getF(probs)
184 
185         if scale is not None:
186             centers = F.broadcast_mul(centers, scale).expand_dims(axis=-2)
187         else:
188             centers = F.broadcast_mul(
189                 centers, F.ones_like(probs.slice_axis(axis=-2, begin=0, end=1))
190             )
191         return Binned(probs, centers)
192 
193     @property
194     def event_shape(self) -> Tuple:
195         return ()
196
```
--- 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/src/gluonts/distribution/binned.py b/src/gluonts/distribution/binned.py
--- a/src/gluonts/distribution/binned.py
+++ b/src/gluonts/distribution/binned.py
@@ -169,7 +169,7 @@
     distr_cls: type = Binned
 
     @validated()
-    def __init__(self, bin_centers: List) -> None:
+    def __init__(self, bin_centers: List[float]) -> None:
         # cannot pass directly nd.array because it is not serializable
         bc = mx.nd.array(bin_centers)
         assert len(bc.shape) == 1

{"golden_diff": "diff --git a/src/gluonts/distribution/binned.py b/src/gluonts/distribution/binned.py\n--- a/src/gluonts/distribution/binned.py\n+++ b/src/gluonts/distribution/binned.py\n@@ -169,7 +169,7 @@\n     distr_cls: type = Binned\n \n     @validated()\n-    def __init__(self, bin_centers: List) -> None:\n+    def __init__(self, bin_centers: List[float]) -> None:\n         # cannot pass directly nd.array because it is not serializable\n         bc = mx.nd.array(bin_centers)\n         assert len(bc.shape) == 1\n", "issue": "Tutorial notebook Exception\nI downloaded the notebook available on https://gluon-ts.mxnet.io/examples/forecasting/tutorial.html, and run it on my local laptop (Darwin Kernel Version 16.7.0, Anaconda3 Distro, Python 3.7.3, Jupyter 4.4.0, gluonts 0.1.1) and get the following exception at:\r\n\r\n```\r\nfrom gluonts.model.simple_feedforward import SimpleFeedForwardEstimator\r\nfrom gluonts.trainer import Trainer\r\n```\r\n\r\n```\r\n---------------------------------------------------------------------------\r\nTypeError                                 Traceback (most recent call last)\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)\r\n    261         try:\r\n--> 262             if issubclass(type_, val_type):\r\n    263                 return validators\r\n\r\nTypeError: issubclass() arg 1 must be a class\r\n\r\nThe above exception was the direct cause of the following exception:\r\n\r\nRuntimeError                              Traceback (most recent call last)\r\n<ipython-input-13-1fca1cb620ad> in <module>\r\n----> 1 from gluonts.model.simple_feedforward import SimpleFeedForwardEstimator\r\n      2 from gluonts.trainer import Trainer\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/gluonts/model/simple_feedforward/__init__.py in <module>\r\n      1 # Relative imports\r\n----> 2 from ._estimator import SimpleFeedForwardEstimator\r\n      3 \r\n      4 __all__ = ['SimpleFeedForwardEstimator']\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/gluonts/model/simple_feedforward/_estimator.py in <module>\r\n      7 # First-party imports\r\n      8 from gluonts.core.component import validated\r\n----> 9 from gluonts.distribution import DistributionOutput, StudentTOutput\r\n     10 from gluonts.model.estimator import GluonEstimator\r\n     11 from gluonts.model.predictor import Predictor, RepresentableBlockPredictor\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/gluonts/distribution/__init__.py in <module>\r\n     14 # Relative imports\r\n     15 from . import bijection\r\n---> 16 from .binned import Binned, BinnedOutput\r\n     17 from .distribution import Distribution\r\n     18 from .distribution_output import DistributionOutput\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/gluonts/distribution/binned.py in <module>\r\n    166 \r\n    167 \r\n--> 168 class BinnedOutput(DistributionOutput):\r\n    169     distr_cls: type = Binned\r\n    170 \r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/gluonts/distribution/binned.py in BinnedOutput()\r\n    170 \r\n    171     @validated()\r\n--> 172     def __init__(self, bin_centers: List) -> None:\r\n    173         # cannot pass directly nd.array because it is not serializable\r\n    174         bc = mx.nd.array(bin_centers)\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/gluonts/core/component.py in validator(ctor)\r\n    167                 f'{ctor_clsnme}Model',\r\n    168                 __config__=ConfigBase.Config,\r\n--> 169                 **ctor_fields,\r\n    170             )\r\n    171         else:\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/main.py in create_model(model_name, __config__, __base__, **field_definitions)\r\n    408                 annotation=f_annotation,\r\n    409                 class_validators=vg.get_validators(f_name),\r\n--> 410                 config=config,\r\n    411             )\r\n    412 \r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in infer(cls, name, value, annotation, class_validators, config)\r\n    105             required=required,\r\n    106             model_config=config,\r\n--> 107             schema=schema,\r\n    108         )\r\n    109 \r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in __init__(self, name, type_, class_validators, default, required, model_config, alias, allow_none, schema)\r\n     85         self.shape: Shape = Shape.SINGLETON\r\n     86         self._schema: Schema = schema\r\n---> 87         self.prepare()\r\n     88 \r\n     89     @classmethod\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in prepare(self)\r\n    134 \r\n    135         self._populate_sub_fields()\r\n--> 136         self._populate_validators()\r\n    137 \r\n    138     def schema(self, by_alias=True):\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/fields.py in _populate_validators(self)\r\n    264                 *tuple(v.func for v in self.class_validators if not v.whole and v.pre),\r\n    265                 *(get_validators() if get_validators else find_validators(self.type_,\r\n--> 266                                                                           self.model_config.arbitrary_types_allowed)),\r\n    267                 *tuple(v.func for v in self.class_validators if not v.whole and not v.pre),\r\n    268             )\r\n\r\n~/python/anaconda3/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)\r\n    263                 return validators\r\n    264         except TypeError as e:\r\n--> 265             raise RuntimeError(f'error checking inheritance of {type_!r} (type: {display_as_type(type_)})') from e\r\n    266 \r\n    267     if arbitrary_types_allowed:\r\n\r\nRuntimeError: error checking inheritance of ~T (type: T)\r\n```\n", "before_files": [{"content": "# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\").\n# You may not use this file except in compliance with the License.\n# A copy of the License is located at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# or in the \"license\" file accompanying this file. This file is distributed\n# on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n# express or implied. See the License for the specific language governing\n# permissions and limitations under the License.\n\n# Standard library imports\nfrom typing import Tuple, List\n\n# Third-party imports\nimport mxnet as mx\nfrom mxnet import gluon\n\n# First-party imports\nfrom gluonts.core.component import validated\nfrom gluonts.model.common import Tensor\n\n# Relative imports\nfrom .distribution import Distribution, _sample_multiple, getF\nfrom .distribution_output import DistributionOutput\n\n\nclass Binned(Distribution):\n    r\"\"\"\n    A binned distribution defined by a set of bins via\n    bin centers and bin probabilities.\n\n    Parameters\n    ----------\n    bin_probs\n        Tensor containing the bin probabilities, of shape `(*batch_shape, num_bins)`.\n    bin_centers\n        Tensor containing the bin centers, of shape `(*batch_shape, num_bins)`.\n    F\n    \"\"\"\n\n    is_reparameterizable = False\n\n    def __init__(self, bin_probs: Tensor, bin_centers: Tensor, F=None) -> None:\n        self.bin_centers = bin_centers\n        self.bin_probs = bin_probs\n        self.F = F if F else getF(bin_probs)\n\n        self.bin_edges = Binned._compute_edges(self.F, bin_centers)\n\n    @staticmethod\n    def _compute_edges(F, bin_centers: Tensor) -> Tensor:\n        r\"\"\"\n        Computes the edges of the bins based on the centers. The first and last edge are set to :math:`10^{-10}` and\n        :math:`10^{10}`, repsectively.\n\n        Parameters\n        ----------\n        F\n        bin_centers\n            Tensor of shape `(*batch_shape, num_bins)`.\n\n        Returns\n        -------\n        Tensor\n            Tensor of shape (*gamma.shape, num_bins+1)\n        \"\"\"\n\n        low = (\n            F.zeros_like(bin_centers.slice_axis(axis=-1, begin=0, end=1))\n            - 1.0e10\n        )\n        high = (\n            F.zeros_like(bin_centers.slice_axis(axis=-1, begin=0, end=1))\n            + 1.0e10\n        )\n\n        means = (\n            bin_centers.slice_axis(axis=-1, begin=1, end=None)\n            + bin_centers.slice_axis(axis=-1, begin=0, end=-1)\n        ) / 2.0\n\n        return F.concat(low, means, high, dim=-1)\n\n    @property\n    def batch_shape(self) -> Tuple:\n        return self.bin_centers.shape[:-1]\n\n    @property\n    def event_shape(self) -> Tuple:\n        return ()\n\n    @property\n    def event_dim(self) -> int:\n        return 0\n\n    @property\n    def mean(self):\n        return (self.bin_probs * self.bin_centers).sum(axis=-1)\n\n    @property\n    def stddev(self):\n        Ex2 = (self.bin_probs * self.bin_centers.square()).sum(axis=-1)\n        return (Ex2 - self.mean.square()).sqrt()\n\n    def log_prob(self, x):\n        x = x.expand_dims(axis=-1)\n        # TODO: when mxnet has searchsorted replace this\n        left_edges = self.bin_edges.slice_axis(axis=-1, begin=0, end=-1)\n        right_edges = self.bin_edges.slice_axis(axis=-1, begin=1, end=None)\n        mask = self.F.broadcast_lesser_equal(\n            left_edges, x\n        ) * self.F.broadcast_lesser(x, right_edges)\n        return (self.bin_probs.log() * mask).sum(axis=-1)\n\n    def sample(self, num_samples=None):\n        def s(bin_probs):\n            F = self.F\n            indices = F.sample_multinomial(bin_probs)\n            if num_samples is None:\n                return self.bin_centers.pick(indices, -1).reshape_like(\n                    F.zeros_like(indices.astype('float32'))\n                )\n            else:\n                return F.repeat(\n                    F.expand_dims(self.bin_centers, axis=0),\n                    repeats=num_samples,\n                    axis=0,\n                ).pick(indices, -1)\n\n        return _sample_multiple(s, self.bin_probs, num_samples=num_samples)\n\n\nclass BinnedArgs(gluon.HybridBlock):\n    def __init__(self, bin_centers: mx.nd.NDArray, **kwargs) -> None:\n        super().__init__(**kwargs)\n        with self.name_scope():\n            self.bin_centers = self.params.get_constant(\n                'bincenters', bin_centers\n            )\n            self.num_bins = bin_centers.shape[0]\n\n            # needs to be named self.proj for consistency with the ArgProj class and the inference tests\n            self.proj = gluon.nn.HybridSequential()\n            self.proj.add(\n                gluon.nn.Dense(\n                    self.num_bins,\n                    prefix='binproj',\n                    flatten=False,\n                    weight_initializer=mx.init.Xavier(),\n                )\n            )\n            self.proj.add(gluon.nn.HybridLambda('softmax'))\n\n    def hybrid_forward(\n        self, F, x: Tensor, bin_centers: Tensor, **kwargs\n    ) -> Tuple[Tensor, Tensor]:\n        ps = self.proj(x)\n        return (\n            ps.reshape(shape=(-2, -1, self.num_bins), reverse=1),\n            # For some reason hybridize does not work when returning constants directly\n            bin_centers + 0.0,\n        )\n\n\nclass BinnedOutput(DistributionOutput):\n    distr_cls: type = Binned\n\n    @validated()\n    def __init__(self, bin_centers: List) -> None:\n        # cannot pass directly nd.array because it is not serializable\n        bc = mx.nd.array(bin_centers)\n        assert len(bc.shape) == 1\n        self.bin_centers = bc\n\n    def get_args_proj(self, *args, **kwargs) -> gluon.nn.HybridBlock:\n        return BinnedArgs(self.bin_centers)\n\n    def distribution(self, args, scale=None) -> Binned:\n        probs, centers = args\n        F = getF(probs)\n\n        if scale is not None:\n            centers = F.broadcast_mul(centers, scale).expand_dims(axis=-2)\n        else:\n            centers = F.broadcast_mul(\n                centers, F.ones_like(probs.slice_axis(axis=-2, begin=0, end=1))\n            )\n        return Binned(probs, centers)\n\n    @property\n    def event_shape(self) -> Tuple:\n        return ()\n", "path": "src/gluonts/distribution/binned.py"}], "after_files": [{"content": "# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\").\n# You may not use this file except in compliance with the License.\n# A copy of the License is located at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# or in the \"license\" file accompanying this file. This file is distributed\n# on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either\n# express or implied. See the License for the specific language governing\n# permissions and limitations under the License.\n\n# Standard library imports\nfrom typing import Tuple, List\n\n# Third-party imports\nimport mxnet as mx\nfrom mxnet import gluon\n\n# First-party imports\nfrom gluonts.core.component import validated\nfrom gluonts.model.common import Tensor\n\n# Relative imports\nfrom .distribution import Distribution, _sample_multiple, getF\nfrom .distribution_output import DistributionOutput\n\n\nclass Binned(Distribution):\n    r\"\"\"\n    A binned distribution defined by a set of bins via\n    bin centers and bin probabilities.\n\n    Parameters\n    ----------\n    bin_probs\n        Tensor containing the bin probabilities, of shape `(*batch_shape, num_bins)`.\n    bin_centers\n        Tensor containing the bin centers, of shape `(*batch_shape, num_bins)`.\n    F\n    \"\"\"\n\n    is_reparameterizable = False\n\n    def __init__(self, bin_probs: Tensor, bin_centers: Tensor, F=None) -> None:\n        self.bin_centers = bin_centers\n        self.bin_probs = bin_probs\n        self.F = F if F else getF(bin_probs)\n\n        self.bin_edges = Binned._compute_edges(self.F, bin_centers)\n\n    @staticmethod\n    def _compute_edges(F, bin_centers: Tensor) -> Tensor:\n        r\"\"\"\n        Computes the edges of the bins based on the centers. The first and last edge are set to :math:`10^{-10}` and\n        :math:`10^{10}`, repsectively.\n\n        Parameters\n        ----------\n        F\n        bin_centers\n            Tensor of shape `(*batch_shape, num_bins)`.\n\n        Returns\n        -------\n        Tensor\n            Tensor of shape (*gamma.shape, num_bins+1)\n        \"\"\"\n\n        low = (\n            F.zeros_like(bin_centers.slice_axis(axis=-1, begin=0, end=1))\n            - 1.0e10\n        )\n        high = (\n            F.zeros_like(bin_centers.slice_axis(axis=-1, begin=0, end=1))\n            + 1.0e10\n        )\n\n        means = (\n            bin_centers.slice_axis(axis=-1, begin=1, end=None)\n            + bin_centers.slice_axis(axis=-1, begin=0, end=-1)\n        ) / 2.0\n\n        return F.concat(low, means, high, dim=-1)\n\n    @property\n    def batch_shape(self) -> Tuple:\n        return self.bin_centers.shape[:-1]\n\n    @property\n    def event_shape(self) -> Tuple:\n        return ()\n\n    @property\n    def event_dim(self) -> int:\n        return 0\n\n    @property\n    def mean(self):\n        return (self.bin_probs * self.bin_centers).sum(axis=-1)\n\n    @property\n    def stddev(self):\n        Ex2 = (self.bin_probs * self.bin_centers.square()).sum(axis=-1)\n        return (Ex2 - self.mean.square()).sqrt()\n\n    def log_prob(self, x):\n        x = x.expand_dims(axis=-1)\n        # TODO: when mxnet has searchsorted replace this\n        left_edges = self.bin_edges.slice_axis(axis=-1, begin=0, end=-1)\n        right_edges = self.bin_edges.slice_axis(axis=-1, begin=1, end=None)\n        mask = self.F.broadcast_lesser_equal(\n            left_edges, x\n        ) * self.F.broadcast_lesser(x, right_edges)\n        return (self.bin_probs.log() * mask).sum(axis=-1)\n\n    def sample(self, num_samples=None):\n        def s(bin_probs):\n            F = self.F\n            indices = F.sample_multinomial(bin_probs)\n            if num_samples is None:\n                return self.bin_centers.pick(indices, -1).reshape_like(\n                    F.zeros_like(indices.astype('float32'))\n                )\n            else:\n                return F.repeat(\n                    F.expand_dims(self.bin_centers, axis=0),\n                    repeats=num_samples,\n                    axis=0,\n                ).pick(indices, -1)\n\n        return _sample_multiple(s, self.bin_probs, num_samples=num_samples)\n\n\nclass BinnedArgs(gluon.HybridBlock):\n    def __init__(self, bin_centers: mx.nd.NDArray, **kwargs) -> None:\n        super().__init__(**kwargs)\n        with self.name_scope():\n            self.bin_centers = self.params.get_constant(\n                'bincenters', bin_centers\n            )\n            self.num_bins = bin_centers.shape[0]\n\n            # needs to be named self.proj for consistency with the ArgProj class and the inference tests\n            self.proj = gluon.nn.HybridSequential()\n            self.proj.add(\n                gluon.nn.Dense(\n                    self.num_bins,\n                    prefix='binproj',\n                    flatten=False,\n                    weight_initializer=mx.init.Xavier(),\n                )\n            )\n            self.proj.add(gluon.nn.HybridLambda('softmax'))\n\n    def hybrid_forward(\n        self, F, x: Tensor, bin_centers: Tensor, **kwargs\n    ) -> Tuple[Tensor, Tensor]:\n        ps = self.proj(x)\n        return (\n            ps.reshape(shape=(-2, -1, self.num_bins), reverse=1),\n            # For some reason hybridize does not work when returning constants directly\n            bin_centers + 0.0,\n        )\n\n\nclass BinnedOutput(DistributionOutput):\n    distr_cls: type = Binned\n\n    @validated()\n    def __init__(self, bin_centers: List[float]) -> None:\n        # cannot pass directly nd.array because it is not serializable\n        bc = mx.nd.array(bin_centers)\n        assert len(bc.shape) == 1\n        self.bin_centers = bc\n\n    def get_args_proj(self, *args, **kwargs) -> gluon.nn.HybridBlock:\n        return BinnedArgs(self.bin_centers)\n\n    def distribution(self, args, scale=None) -> Binned:\n        probs, centers = args\n        F = getF(probs)\n\n        if scale is not None:\n            centers = F.broadcast_mul(centers, scale).expand_dims(axis=-2)\n        else:\n            centers = F.broadcast_mul(\n                centers, F.ones_like(probs.slice_axis(axis=-2, begin=0, end=1))\n            )\n        return Binned(probs, centers)\n\n    @property\n    def event_shape(self) -> Tuple:\n        return ()\n", "path": "src/gluonts/distribution/binned.py"}]}