Repository: awslabs/gluonts

Issue:
Can't save DeepState Model; RuntimeError: Cannot serialize type gluonts.distribution.lds.ParameterBounds. 
Hi, I'm trying to save the DeepState Model and got an error message. The details are attached.

Code
```python
import pprint

from gluonts.dataset.repository.datasets import get_dataset, dataset_recipes
from gluonts.evaluation import Evaluator
from gluonts.evaluation.backtest import make_evaluation_predictions
from gluonts.model.deepstate import DeepStateEstimator

from pathlib import Path
from gluonts.model.predictor import Predictor

from gluonts.trainer import Trainer


if __name__ == "__main__":

    print(f"datasets available: {dataset_recipes.keys()}")

    # we pick m4_hourly as it only contains a few hundred time series
    dataset = get_dataset("m4_hourly", regenerate=False)

    estimator = DeepStateEstimator(
        prediction_length=dataset.metadata.prediction_length,
        freq=dataset.metadata.freq,
        trainer=Trainer(epochs=1, num_batches_per_epoch=3),
        # cardinality = 0,
        use_feat_dynamic_real = False,
        use_feat_static_cat = False,
        cardinality=[0],
    )

    predictor = estimator.train(dataset.train)
    predictor.serialize(Path("/tmp/"))
    forecast_it, ts_it = make_evaluation_predictions(
        dataset.test, predictor=predictor, num_samples=100
    )

    agg_metrics, item_metrics = Evaluator()(
        ts_it, forecast_it, num_series=len(dataset.test)
    )

    pprint.pprint(agg_metrics)
```
Error Massage:
```
Traceback (most recent call last):
  File "/Users/xue.w/Desktop/project_code/deep_time_prediction/gluon_test/M4_TEST.py", line 48, in <module>
    predictor.serialize(Path(f"/tmp/"))
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/model/predictor.py", line 331, in serialize
    self.serialize_prediction_net(path)
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/model/predictor.py", line 482, in serialize_prediction_net
    export_repr_block(self.prediction_net, path, "prediction_net")
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/support/util.py", line 283, in export_repr_block
    print(dump_json(rb), file=fp)
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/core/serde.py", line 134, in dump_json
    return json.dumps(encode(o), indent=indent, sort_keys=True)
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/functools.py", line 840, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/core/serde.py", line 417, in encode
    "kwargs": encode(kwargs),
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/functools.py", line 840, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/core/serde.py", line 402, in encode
    return {k: encode(v) for k, v in v.items()}
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/core/serde.py", line 402, in <dictcomp>
    return {k: encode(v) for k, v in v.items()}
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/functools.py", line 840, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/Users/xue.w/.virtualenvs/myvenv/lib/python3.7/site-packages/gluonts/core/serde.py", line 420, in encode
    raise RuntimeError(bad_type_msg.format(fqname_for(v.__class__)))
RuntimeError: Cannot serialize type gluonts.distribution.lds.ParameterBounds. See the documentation of the `encode` and
`validate` functions at  http://gluon-ts.mxnet.io/api/gluonts/gluonts.html
and the Python documentation of the `__getnewargs_ex__` magic method at
https://docs.python.org/3/library/pickle.html#object.__getnewargs_ex__
for more information how to make this type serializable.
```


Discussion:

Resolving patch:
diff --git a/src/gluonts/distribution/lds.py b/src/gluonts/distribution/lds.py
--- a/src/gluonts/distribution/lds.py
+++ b/src/gluonts/distribution/lds.py
@@ -28,6 +28,7 @@
 
 
 class ParameterBounds:
+    @validated()
     def __init__(self, lower, upper) -> None:
         assert (
             lower <= upper
diff --git a/src/gluonts/model/deepstate/_estimator.py b/src/gluonts/model/deepstate/_estimator.py
--- a/src/gluonts/model/deepstate/_estimator.py
+++ b/src/gluonts/model/deepstate/_estimator.py
@@ -129,7 +129,7 @@ class DeepStateEstimator(GluonEstimator):
         (default: False)
     use_feat_static_cat
         Whether to use the ``feat_static_cat`` field from the data
-        (default: False)
+        (default: True)
     embedding_dimension
         Dimension of the embeddings for categorical features
         (default: [min(50, (cat+1)//2) for cat in cardinality])


Test patch:
diff --git a/test/model/test_models.py b/test/model/test_models.py
--- a/test/model/test_models.py
+++ b/test/model/test_models.py
@@ -26,6 +26,7 @@
 from gluonts.evaluation.backtest import backtest_metrics
 from gluonts.model.deepar import DeepAREstimator
 from gluonts.model.deep_factor import DeepFactorEstimator
+from gluonts.model.deepstate import DeepStateEstimator
 from gluonts.model.gp_forecaster import GaussianProcessEstimator
 from gluonts.model.npts import NPTSEstimator
 from gluonts.model.predictor import Predictor
@@ -229,6 +230,28 @@ def seasonal_estimator():
     return SeasonalNaiveEstimator, dict(prediction_length=prediction_length)
 
 
+def deepstate_estimator(hybridize: bool = False, batches_per_epoch=1):
+    return (
+        DeepStateEstimator,
+        dict(
+            ctx="cpu",
+            epochs=epochs,
+            learning_rate=1e-2,
+            hybridize=hybridize,
+            num_cells=2,
+            num_layers=1,
+            prediction_length=prediction_length,
+            context_length=2,
+            past_length=prediction_length,
+            cardinality=[1],
+            use_feat_static_cat=False,
+            num_batches_per_epoch=batches_per_epoch,
+            use_symbol_block_predictor=False,
+            num_parallel_samples=2,
+        ),
+    )
+
+
 @flaky(max_runs=3, min_passes=1)
 @pytest.mark.timeout(10)  # DeepAR occasionally fails with the 5 second timeout
 @pytest.mark.parametrize(
@@ -252,7 +275,11 @@ def seasonal_estimator():
             + (0.2,),
         ]
     ]
-    + [npts_estimator() + (0.0,), seasonal_estimator() + (0.0,)],
+    + [
+        npts_estimator() + (0.0,),
+        seasonal_estimator() + (0.0,),
+        deepstate_estimator(hybridize=False, batches_per_epoch=100) + (0.5,),
+    ],
 )
 def test_accuracy(Estimator, hyperparameters, accuracy):
     estimator = Estimator.from_hyperparameters(freq=freq, **hyperparameters)
@@ -296,6 +323,7 @@ def test_repr(Estimator, hyperparameters):
         mqrnn_estimator(),
         gp_estimator(),
         transformer_estimator(),
+        deepstate_estimator(),
     ],
 )
 def test_serialize(Estimator, hyperparameters):