An end-to-end demand forecasting and inventory optimisation pipeline for retail stores. The system trains a DeepAR probabilistic forecasting model on weekly sales data, then feeds the forecasts into a Mixed-Integer Linear Program (MILP) that determines optimal order quantities per store and SKU — minimising purchasing, holding, spoilage, and stockout costs. Results are explored through an interactive Streamlit dashboard.
| Category | Tool | Purpose |
|---|---|---|
| Forecasting | GluonTS + PyTorch Lightning | DeepAR probabilistic time-series model |
| Optimisation | PuLP | MILP solver for inventory order planning |
| Orchestration | Prefect | Pipeline orchestration & flow management |
| Experiment Tracking | MLflow | Model & metric tracking |
| Configuration | Hydra | YAML-based configuration management |
| Dashboard | Streamlit + Plotly | Interactive visualisation |
| Data | pandas | Data manipulation & feature engineering |
| ML Utilities | scikit-learn, LightGBM, skforecast | Feature engineering & baseline models |
| API | FastAPI | REST API for serving predictions |
| Packaging | uv | Fast Python dependency management |
| Containerisation | Docker | Reproducible deployment |
| Linting | Ruff, mypy | Code quality & type checking |
.
├── config/
│ └── main.yaml # Hydra configuration (data paths, model params, tuning)
├── data/
│ ├── raw/ # Raw input CSVs (sales, calendar, stores, skus, etc.)
│ ├── processed/ # Processed data after joining & cleaning
│ └── features/ # Engineered feature sets
├── models/ # Serialised GluonTS model artifacts
├── notebooks/ # Exploratory analysis notebooks
├── outputs/
│ ├── forecasts.csv # Exported forecasts (mean, p10, p50, p90)
│ ├── optimization_results.csv # MILP optimisation results per store/SKU
│ └── plots/ # Matplotlib forecast vs actuals plots
├── src/
│ ├── main.py # Prefect pipeline entry point
│ ├── process.py # Data processing & joining
│ ├── feature_engineering.py # Feature creation (lags, rolling, calendar)
│ ├── forecasting.py # GluonTS DeepAR training & dataset building
│ ├── tuning.py # Optuna hyperparameter tuning
│ ├── evaluation.py # Forecast visualisation & CSV export
│ ├── optimization.py # PuLP inventory optimisation (MILP)
│ ├── streamlit_app.py # Interactive Streamlit dashboard
│ ├── app.py # FastAPI application
│ └── utils.py # Helper functions
├── tests/ # Unit tests
├── pyproject.toml # Dependencies & tool configuration
├── Dockerfile # Container build
└── docker-compose.yaml # Container orchestration
Raw Data → Processing → Feature Engineering → DeepAR Training → Forecasting → Optimisation
↓ ↓
forecasts.csv optimization_results.csv
↓ ↓
Streamlit Dashboard
- Data Processing (
process.py): Joins sales history, calendar, store, SKU, supplier, and pricing data into a single weekly dataset. - Feature Engineering (
feature_engineering.py): Creates lag features, rolling statistics, calendar encodings (sin/cos), and promo indicators. - Model Training (
forecasting.py): Trains a DeepAR model via GluonTS with configurable context length, layers, hidden size, and dropout. - Evaluation (
evaluation.py): Generates probabilistic forecasts (mean, p10, p50, p90), exports tooutputs/forecasts.csv, and saves matplotlib plots. - Optimisation (
optimization.py): Solves a per-store MILP that minimises total cost (purchase + holding + spoilage + stockout penalty) subject to lead time, MOQ, case pack, capacity, and safety stock constraints.
- Python ≥ 3.11
- uv package manager
# All dependencies (including dev tools)
uv sync --all-extras
# Production only
uv syncpip install streamlit plotly "altair<5"The main pipeline is orchestrated with Prefect and configured via Hydra:
uv run src/main.pyThis will:
- Read raw data from
data/raw/ - Process and save to
data/processed/processed_data.csv - Run feature engineering
- (Optional) Run hyperparameter tuning with Optuna
- Train the DeepAR model and save to
models/gluonts_model/ - Generate forecasts and export to
outputs/forecasts.csv - Run inventory optimisation and export to
outputs/optimization_results.csv
All parameters are in config/main.yaml:
model:
name: deepar
horizon: 4 # forecast horizon in weeks
context_length: 26 # lookback window in weeks
epochs: 40
num_layers: 2
hidden_size: 40
dropout: 0.1
tuning:
enabled: true
n_trials: 10Override any parameter from the command line:
uv run src/main.py model.epochs=100 model.horizon=8streamlit run src/streamlit_app.pyThe dashboard will be available at http://localhost:8501 and provides:
- Store & SKU selection via sidebar dropdowns
- Item metadata in the sidebar (category, supplier, lead time, MOQ, costs, region)
- Forecast plot — historical actuals (black) with forecast mean (green), median (dashed), and p10–p90 confidence interval (shaded)
- Optimisation chart — weekly order units (bars), projected inventory, lost sales, and forecast demand (lines)
- Cost breakdown — donut chart showing purchase, holding, spoilage, and stockout penalty costs
- Results table — detailed per-week optimisation outputs
Note: The dashboard reads from
outputs/forecasts.csv,outputs/optimization_results.csv, anddata/processed/processed_data.csv. Run the main pipeline first to generate these files.
uv run uvicorn src.app:app --reloadThe API will be available at http://localhost:8000 with interactive docs at http://localhost:8000/docs.
# Build and run
docker-compose up --build
# Or manually
docker build -t forecasting-optimisation .
docker run -p 8000:8000 forecasting-optimisationuv run pre-commit installRuns Ruff (linting + formatting) and mypy (type checking) on every commit.
uv run pdoc src -o docs # static HTML
uv run pdoc src --http localhost:8080 # live serveruv run pytest