Repository: awslabs/gluonts

Issue:
Anomaly detection example is not working anymore
## Description
Probably due to code changes, the `anomaly_detecion.py` inside `examples` folder is not working
## To Reproduce


Here's the original code:

```python
if __name__ == "__main__":

    dataset = get_dataset(dataset_name="electricity")

    estimator = DeepAREstimator(
        prediction_length=dataset.metadata.prediction_length,
        freq=dataset.metadata.freq,
        trainer=Trainer(
            learning_rate=1e-3, epochs=50, num_batches_per_epoch=100
        ),
    )

    # instead of calling `train` method, we call `train_model` that returns more things including the training model
    train_output = estimator.train_model(dataset.train)

    # we construct a data_entry that contains 500 random windows
    batch_size = 500
    num_samples = 100
    training_data_loader = TrainDataLoader(
        dataset=dataset.train,
        transform=train_output.transformation,
        batch_size=batch_size,
        num_batches_per_epoch=estimator.trainer.num_batches_per_epoch,
        ctx=mx.cpu(),
    )

    for data_entry in islice(training_data_loader, 1):
        pass

    # we now call the train model to get the predicted distribution on each window
    # this allows us to investigate where are the biggest anomalies
    context_length = train_output.trained_net.context_length
    prediction_length = train_output.trained_net.prediction_length

    input_names = get_hybrid_forward_input_names(train_output.trained_net)

    distr = train_output.trained_net.distribution(
        *[data_entry[k] for k in input_names]
    )

    # gets all information into numpy array for further plotting
    samples = distr.sample(num_samples).asnumpy()
    percentiles = np.percentile(samples, axis=0, q=[10.0, 90.0])
    target = mx.ndarray.concat(
        data_entry["past_target"], data_entry["future_target"], dim=1
    )
    target = target[:, -(context_length + prediction_length) :]
    nll = -distr.log_prob(target).asnumpy()
    target = target.asnumpy()
    mean = samples.mean(axis=0)
    percentiles = np.percentile(samples, axis=0, q=[10.0, 90.0])

    # NLL indices from largest to smallest
    sorted_indices = np.argsort(nll.reshape(-1))[::-1]

    # shows the series and times when the 20 largest NLL were observed
    for k in sorted_indices[:20]:
        i = k // nll.shape[1]
        t = k % nll.shape[1]

        time_index = pd.date_range(
            pd.Timestamp(data_entry["forecast_start"][i]),
            periods=context_length + prediction_length,
        )
        time_index -= context_length * time_index.freq

        plt.figure(figsize=(10, 4))
        plt.fill_between(
            time_index,
            percentiles[0, i],
            percentiles[-1, i],
            alpha=0.5,
            label="80% CI predicted",
        )
        plt.plot(time_index, target[i], label="target")
        plt.axvline(time_index[t], alpha=0.5, color="r")
        plt.title(f"NLL: {nll[i, t]}")
        plt.legend()
        plt.show()
```




I made some changes when trying to run it.
More specifically:

I changed  `training_data_loader` (as it now requires `stack_fn` ) to 

```python
    training_data_loader = TrainDataLoader(
                                            dataset=dataset.train, 
                                            transform=train_output.transformation,        
                                            batch_size=batch_size,
                                            num_batches_per_epoch=estimator.trainer.num_batches_per_epoch,
                                            stack_fn=partial(batchify,ctx=estimator.trainer.ctx, dtype=estimator.dtype))
```

and added `type` to

```python
input_names = get_hybrid_forward_input_names(type(train_output.trained_net))
```

but I still get error in 

```python
distr = train_output.trained_net.distribution(
    *[data_entry[k] for k in input_names]
)
```
## Error message or code output

```
KeyError                                  Traceback (most recent call last)
<ipython-input-6-dee0a4a5f14a> in <module>()
     38 
     39 distr = train_output.trained_net.distribution(
---> 40     *[data_entry[k] for k in input_names]
     41 )
     42 

<ipython-input-6-dee0a4a5f14a> in <listcomp>(.0)
     38 
     39 distr = train_output.trained_net.distribution(
---> 40     *[data_entry[k] for k in input_names]
     41 )
     42 

KeyError: 'past_time_feat'
```

Not all names inside `input_names = ['feat_static_cat',
 'feat_static_real',
 'past_time_feat',
 'past_target',
 'past_observed_values',
 'past_is_pad',
 'future_time_feat',
 'future_target',
 'future_observed_values']` are keys of `data_entry = dict_keys(['start', 'target', 'feat_static_cat', 'item_id', 'source', 'feat_static_real', 'observed_values', 'time_feat'])`  


## Environment
- Operating system: Ubuntu
- Python version: 3.7.10
- GluonTS version: 0.7.3
- MXNet version: 1.6

How should I fix it?
Thanks!



Discussion:

Resolving patch:
diff --git a/examples/anomaly_detection.py b/examples/anomaly_detection.py
--- a/examples/anomaly_detection.py
+++ b/examples/anomaly_detection.py
@@ -17,6 +17,7 @@
 """
 import numpy as np
 from itertools import islice
+from functools import partial
 import mxnet as mx
 import matplotlib.pyplot as plt
 import pandas as pd
@@ -28,6 +29,7 @@
 from gluonts.model.deepar import DeepAREstimator
 from gluonts.mx.util import get_hybrid_forward_input_names
 from gluonts.mx.trainer import Trainer
+from gluonts.mx.batchify import batchify
 from gluonts.dataset.repository.datasets import get_dataset
 
 
@@ -39,34 +41,38 @@
         prediction_length=dataset.metadata.prediction_length,
         freq=dataset.metadata.freq,
         trainer=Trainer(
-            learning_rate=1e-3, epochs=50, num_batches_per_epoch=100
+            learning_rate=1e-3, epochs=20, num_batches_per_epoch=100
         ),
     )
 
     # instead of calling `train` method, we call `train_model` that returns more things including the training model
     train_output = estimator.train_model(dataset.train)
 
+    input_names = get_hybrid_forward_input_names(
+        type(train_output.trained_net)
+    )
+
     # we construct a data_entry that contains 500 random windows
     batch_size = 500
     num_samples = 100
+    instance_splitter = estimator._create_instance_splitter("training")
     training_data_loader = TrainDataLoader(
         dataset=dataset.train,
-        transform=train_output.transformation,
+        transform=train_output.transformation + instance_splitter,
         batch_size=batch_size,
         num_batches_per_epoch=estimator.trainer.num_batches_per_epoch,
-        ctx=mx.cpu(),
+        stack_fn=partial(
+            batchify, ctx=estimator.trainer.ctx, dtype=estimator.dtype
+        ),
     )
 
-    for data_entry in islice(training_data_loader, 1):
-        pass
+    data_entry = next(iter(training_data_loader))
 
     # we now call the train model to get the predicted distribution on each window
     # this allows us to investigate where are the biggest anomalies
     context_length = train_output.trained_net.context_length
     prediction_length = train_output.trained_net.prediction_length
 
-    input_names = get_hybrid_forward_input_names(train_output.trained_net)
-
     distr = train_output.trained_net.distribution(
         *[data_entry[k] for k in input_names]
     )


Test patch: