# Probabilistic Exponential Smoothing (*PES*) for demand forecasting

## Requirements
The model has been developed using Julia on Windows

```versioninfo
julia> versioninfo()
Julia Version 1.7.2
Commit bf53498635 (2022-02-06 15:21 UTC)
```

The Julia's Windows installer can be download from the [official download page](https://julialang-s3.julialang.org/bin/winnt/x64/1.7/julia-1.7.2-win64.exe).  
  
In a terminal, navigate to the folder where the zip file has been uncompressed. Then run

```instantiate
julia.exe --project -e"using Pkg; Pkg.instantiate()"
```

to activate the project and install all the required dependencies.

### Logging
  
**N.B.** `tensorboard` is not strictly required to run training and evaluation, but it is necessary if `--log` flag is specified.  
  
The logging process uses `TensorBoardlogger.jl` which produces events file readable by `tensorboard` in python. To be able to access these events `tensorboard` has to be installed on your machine. If a working installation of `tensorflow` is present on your system, it is possible that `tensorboard` is already installed too; check it running

```check-tensorboard
pip show tensorboard
```

If `tensorboad` is already installed a message similar to the following should be displayed

```tensorboard-ok
Name: tensorboard
Version: 2.8.0
Summary: TensorBoard lets you watch Tensors Flow
Home-page: https://github.com/tensorflow/tensorboard
Author: Google Inc.
Author-email: packages@tensorflow.org
License: Apache 2.0
Location: <path_to_package>
Requires: absl-py, google-auth, google-auth-oauthlib, grpcio, markdown, numpy, protobuf, requests, setuptools, tensorboard-data-server, tensorboard-plugin-wit, werkzeug, wheel
Required-by:
```

otherwise you will receive a warning

```tensorboard-ko
WARNING: Package(s) not found: tensorflow
```

in which case tensorboard can be installed via

```tensorboard-pip
pip install tensorboard
```

or `conda`, depending on the target system

```tensorboard-conda
conda install -c conda-forge tensorboard
```

## Training & Evaluation

The model presented in the paper can be reproduced launching the following command from a terminal

```train
julia.exe --project .\examples\pes.jl --train --learning-rate 5e-2 --epochs 30 --cell nb --log --log-prefix pes --log-location .\Log\PES --model-location .\Model\PES --modes MuL --frequencies MoY --plot --fig-location .\Fig\PES
```

The model will directly be trained and evaluated on the `parts`[[3]](#3) dataset cited in the paper. At the end of the training phase, the $\rho$*-risk* for the median - $p50$ - and the nineth quantile - $p90$ - will be computed and diplayed in the console. If `--plot` option is given, 5 plot files will be generated at the location specified by `--fig-location`: two for the *S*tock *K*eeping *U*nits (SKUs) for which the minimum and the maximum $p50$ errors are respectively committed; two for SKUs for which the minimum and the maximum $p90$ errors are respectively committed; one for the aggregated level.

## Pre-trained Models

The package comes with the pre-trained model of the approach presented in the paper. It can be accessed running

```re-launch
julia.exe --project .\examples\pes.jl --model-location .\Model\PES --model-name pes_NbOp_monthly --modes MuL --frequencies MoY --plot --fig-location .\Fig\PES
```

As for the training, the $\rho$*-risk* for the median - $p50$ - and the nineth quantile - $p90$ - will be computed and diplayed in the console. If `--plot` option is given, 5 plot files will be generated at the location specified by `--fig-location`: two for the SKUs for which the minimum and the maximum $p50$ errors are respectively committed; two for SKUs for which the minimum and the maximum $p90$ errors are respectively committed; one for the aggregated level.

## Results

Our model achieves the following performance :

|       |              DeepAR[[1]](#1)            |            DeepSSM[[2]](#2)            |   PES  |
|-------|-----------------------------------------|----------------------------------------|--------|
| `p50` |                          **1.273**      | <span style="color: gray;">1.47</span> | *1.42* |
| `p90` | <span style="color: gray;">1.086</span> |                          **0.935**     | *1.04* |


## General Usage
```help
usage: vectorized_skus_moy.jl [--train] [--test]
                        [--learning-rate LEARNING_RATE]
                        [--epochs EPOCHS] [--horizon HORIZON]
                        [--cell CELL] [--frequencies FREQUENCIES]
                        [--modes MODES] [--delimiter DELIMITER]
                        [--model-location MODEL_LOCATION]
                        [--model-name MODEL_NAME] [--use-bson] [--log]
                        [--log-location LOG_LOCATION]
                        [--log-prefix LOG_PREFIX] [--verbose]
                        [--no-timeit-training] [--plot]
                        [--fig-location FIG_LOCATION]
                        [--fig-name FIG_NAME]
                        [--fig-extension FIG_EXTENSION] [-h]

optional arguments:
  --train               if given, triggers training phase
  --test                if given, triggers the computation of the loss
                        over the testing set
  --learning-rate LEARNING_RATE
                        (type: Float64, default: 0.001)
  --epochs EPOCHS       (type: Int64, default: 500)
  --horizon HORIZON     (type: Int64, default: 12)
  --cell CELL           operator to be used within the actual model.
                        See available cells using
                        `Ses.available_cells` (default: "ses")
  --frequencies FREQUENCIES
                        if not empty, defines the seasonal pattern(s)
                        to be added to the model (default: "")
  --modes MODES         if not empty, the string represents the nature
                        of each seasonal pattern defined in
                        `--frequencies` (default: "")
  --delimiter DELIMITER
                        delimiter to split --frequencies and --modes
                        (default: ":")
  --model-location MODEL_LOCATION
                        location where logs are stored (default:
                        ".\\examples\\Model")
  --model-name MODEL_NAME
                        (default: "model")
  --use-bson            if given, use `BSON` package to store/load the
                        model instead of the `Serialization` [default]
  --log                 if given, triggers logs creation.
                        `TensorBoardLogger` is required
  --log-location LOG_LOCATION
                        location where logs are stored (default:
                        ".\\examples\\Log")
  --log-prefix LOG_PREFIX
                        string to prefix logs' name with (default: "")
  --verbose             if given, additional information will be
                        printed during training
  --no-timeit-training  if given, the timing of the training execution
                        is suppressed
  --plot                if given, can trigger plot blocks in the
                        source script
  --fig-location FIG_LOCATION
                        (default: ".\\examples\\Fig")
  --fig-name FIG_NAME   (default: "")
  --fig-extension FIG_EXTENSION
                        (default: ".html")
```


## GluonTS implementations

The package contains also the python implementations of the two main references presented in the paper, namely DeepAR[[1]](#1) and DeepSSM[[2]](#2). They are offered as two distinct Jupyter notebooks, named after the reference model, in the `.\examples\comparison` folder.

### Requirements

The libraries `mxnet` and `gluonts` are required to run the models. Please, visit the [official GluonTS documentation](https://ts.gluon.ai/install.html) for further details on how to install the necessary dependencies.

### Results

Running the target Jupyter notebooks as provided, will retrieve the pre-trained models and evaluate them. A random SKU in the dataset is picked and plotted, together with the uncertainty intervals. The $p50$ and $p90$ *-risk* are evaluated and can be found in the outcome as

```
    ...
    "wQuantileLoss[0.5]": <value>,
    "wQuantileLoss[0.9]": <value>,
    ...
```

Finally a plot for the aggregated level will be produced

## References
<a id="1">[1]</a> David Salinas, Valentin Flunkert, Jan Gasthaus, and Tim Januschowski.  
*DeepAR: Probabilistic forecasting with autoregressive recurrent networks.*  
International Journal of Forecasting, 2019.  
<a id="2">[2]</a> Syama Sundar Rangapuram, Matthias W Seeger, Jan Gasthaus, Lorenzo Stella, Yuyang Wang, and Tim Januschowski.  
*Deep state space models for time series forecasting.*  
Advances in neural information processing systems, 31:7785–7794, 2018  
<a id="3">[3]</a> Rob J. Hyndman, Anne B. Koehler, J. Keith Ord, and Ralph D. Snyder.  
*Forecasting with exponential smoothing: the state space approach.*  
Springer Science & Business Media, 2008