# PyEPO
**Repository Path**: jackfgao/PyEPO
## Basic Information
- **Project Name**: PyEPO
- **Description**: A PyTorch-based End-to-End Predict-then-Optimize Tool
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: MPC
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-07-01
- **Last Updated**: 2025-07-01
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# PyEPO: A PyTorch-based End-to-End Predict-then-Optimize Tool

## Learning Framework

## Publication
This repository is the official implementation of the paper:
[PyEPO: A PyTorch-based End-to-End Predict-then-Optimize Library for Linear and Integer Programming](https://arxiv.org/abs/2206.14234)
Citation:
```
@article{tang2022pyepo,
title={PyEPO: A PyTorch-based End-to-End Predict-then-Optimize Library for Linear and Integer Programming},
author={Tang, Bo and Khalil, Elias B},
journal={arXiv preprint arXiv:2206.14234},
year={2022}
}
```
## Introduction
``PyEPO`` (PyTorch-based End-to-End Predict-then-Optimize Tool) is a Python-based, open-source software that supports modeling and solving predict-then-optimize problems with the linear objective function. The core capability of ``PyEPO`` is to build optimization models with [GurobiPy](https://www.gurobi.com/), [Pyomo](http://www.pyomo.org/), or any other solvers and algorithms, then embed the optimization model into an artificial neural network for the end-to-end training. For this purpose, ``PyEPO`` implements smart predict-then-optimize+ loss [[1]](https://doi.org/10.1287/mnsc.2020.3922) and differentiable Black-Box optimizer [[3]](https://arxiv.org/abs/1912.02175), differentiable perturbed optimizer, and Fenchel-Young loss with Perturbation [[4]](https://papers.nips.cc/paper/2020/hash/6bb56208f672af0dd65451f869fedfd9-Abstract.html) as [PyTorch](https://pytorch.org/) autograd modules.
## Documentation
The official ``PyEPO`` docs can be found at [https://khalil-research.github.io/PyEPO](https://khalil-research.github.io/PyEPO).
## Tutorial
- [01 Optimization Model](https://github.com/khalil-research/PyEPO/blob/main/notebooks/01%20Optimization%20Model.ipynb): Build up optimization solver
- [02 Optimization Dataset](https://github.com/khalil-research/PyEPO/blob/main/notebooks/02%20Optimization%20Dataset.ipynb): Generate synthetic data and use optDataset
- [03 Training and Testing](https://github.com/khalil-research/PyEPO/blob/main/notebooks/03%20Training%20and%20Testing.ipynb): Train and test end-to-end predict-then-optimize for different approaches
- [04 2D knapsack Solution Visualization](https://github.com/khalil-research/PyEPO/blob/main/notebooks/04%202D%20knapsack%20Solution%20Visualization.ipynb): Visualize solutions for knapsack problem
- [05 Warcraft Shortest Path](https://github.com/khalil-research/PyEPO/blob/main/notebooks/05%20Warcraft%20Shortest%20Path.ipynb): Use the Warcraft terrains dateset to train shortest path
## Features
- Implement **SPO+** [[1]](https://doi.org/10.1287/mnsc.2020.3922), **DBB** [[3]](https://arxiv.org/abs/1912.02175), **DPO** [[4]](https://papers.nips.cc/paper/2020/hash/6bb56208f672af0dd65451f869fedfd9-Abstract.html) and **PFYL** [[4]](https://papers.nips.cc/paper/2020/hash/6bb56208f672af0dd65451f869fedfd9-Abstract.html)
- Support [Gurobi](https://www.gurobi.com/) and [Pyomo](http://www.pyomo.org/) API
- Support Parallel computing for optimization solver
- Support solution caching [[5]](https://arxiv.org/abs/2011.05354) to speed up training
## Installation
You can download ``PyEPO`` MPC branch from our GitHub repository.
```bash
git clone --branch MPC https://github.com/khalil-research/PyEPO.git
```
And install it.
```bash
pip install PyEPO/pkg/.
```
## Dependencies
* [NumPy](https://numpy.org/)
* [SciPy](https://scipy.org/)
* [Pathos](https://pathos.readthedocs.io/)
* [tqdm](https://tqdm.github.io/)
* [Pyomo](http://www.pyomo.org/)
* [Gurobi](https://www.gurobi.com/)
* [Scikit Learn](https://scikit-learn.org/)
* [PyTorch](http://pytorch.org/)
## Issue
On Windows system, there is missing ``freeze_support`` to run ``multiprocessing`` directly from ``__main__``. When ``processes`` is not 1, try ``if __name__ == "__main__":`` instead of Jupyter notebook or a PY file.
## Experiments Instruction
For all experiments, all hyperparameters for training (epoch, learning rate, batch size, etc.) are fixed in "./config/*"
However, You can run `pipeline.py` for different experiment setting (including hyperparameters).
```bash
python3 pipeline.py --prob sp --mthd spo --lan gurobi --data 1000 --deg 2 --noise 0.5 --epoch 20 --lr 1e-1 --batch 32 --optm adam --proc 1
```
**Warning**: Although `PyEPO` support multiple processors, these experiments are based on a single CPU.
### Performance Comparison (Figure 5-7)
To draw performance comparison plots, you need to train and evaluate linear regression, random forest, automl, SPO+, DBB, DPO(*Optional*), and PFYL with varying training data size in {100, 1000, 5000}, polynomial degree in {1, 2, 4, 6}, and noise half-width in {0.0, 0.5}.
Experiments for shortest path:
```bash
python3 experiments.py --prob sp --mthd lr --expnum 10
python3 experiments.py --prob sp --mthd rf --expnum 10
python3 experiments.py --prob sp --mthd spo --expnum 10
python3 experiments.py --prob sp --mthd dbb --expnum 10
python3 experiments.py --prob sp --mthd pfyl --expnum 10
```
The argument `expnum` is the number of experiments repeated with different data randomization. For example, in the original paper, `expnum` is 10. Therefore, you can use less repetition to save time.
**Warning:** The two-stage automated model selection and hyperparameters tuning depends on [Auto-Sklearn](https://www.automl.org/automl/auto-sklearn/), which is time-consuming. In addition, automl training requires a time limit (150 sec), so the results may be very different from the paper because of the resource allocations.
Experiments of automl and DPO for shortest path are ***optional***:
```bash
python3 experiments.py --prob sp --mthd auto --expnum 10
python3 experiments.py --prob sp --mthd dpo --expnum 10
```
Once the results of the experiments are ready, you can draw a plot for Figure 6. This figure will be saved to "./images/*"
```bash
python3 plot.py --plot cmp --prob sp
```
Similarly, the comparison of 2D knapsack (Figure 7) and TSP (Figure 8) can be plotted as follows:
```bash
python3 experiments.py --prob ks --mthd lr --expnum 10
python3 experiments.py --prob ks --mthd rf --expnum 10
# python3 experiments.py --prob ks --mthd auto --expnum 10
python3 experiments.py --prob ks --mthd spo --expnum 10
python3 experiments.py --prob ks --mthd dbb --expnum 10
# python3 experiments.py --prob ks --mthd dpo --expnum 10
python3 experiments.py --prob ks --mthd pfyl --expnum 10
python3 plot.py --plot cmp --prob ks
```
```bash
python3 experiments.py --prob tsp --mthd lr --expnum 10
python3 experiments.py --prob tsp --mthd rf --expnum 10
# python3 experiments.py --prob ks --mthd auto --expnum 10
python3 experiments.py --prob tsp --mthd spo --expnum 10
python3 experiments.py --prob tsp --mthd dbb --expnum 10
# python3 experiments.py --prob tsp --mthd dpo --expnum 10
python3 experiments.py --prob tsp --mthd pfyl --expnum 10
python3 plot.py --plot cmp --prob tsp
```
### Relaxation (Figure 8-10)
To draw performance comparison graphs with relaxation, you need to additional train and evaluate SPO+ and DBB with linear relaxation for 2D knapsack and TSP. And TSP has different formulations.
Experiments for 2D knapsack with relaxation:
```bash
python3 experiments.py --prob ks --mthd spo --expnum 10 --rel
python3 experiments.py --prob ks --mthd dbb --expnum 10 --rel
# python3 experiments.py --prob ks --mthd dpo --expnum 10 --rel
python3 experiments.py --prob ks --mthd pfyl --expnum 10 --rel
```
Experiments for TSP with relaxation (Miller-Tucker-Zemlin):
```bash
python3 experiments.py --prob tsp --mthd spo --expnum 10 --rel --tspform mtz
python3 experiments.py --prob tsp --mthd dbb --expnum 10 --rel --tspform mtz
# python3 experiments.py --prob tsp --mthd dpo --expnum 10 --rel --tspform mtz
python3 experiments.py --prob tsp --mthd pfyl --expnum 10 --rel --tspform mtz
```
Experiments for TSP with relaxation (Gavish–Graves):
```bash
python3 experiments.py --prob tsp --mthd spo --expnum 10 --rel --tspform gg
python3 experiments.py --prob tsp --mthd dbb --expnum 10 --rel --tspform gg
# python3 experiments.py --prob tsp --mthd dpo --expnum 10 --rel --tspform gg
python3 experiments.py --prob tsp --mthd pfyl --expnum 10 --rel --tspform gg
```
Once the results of the experiments are ready, you can draw a plot for Figure 9-10:
```bash
# 2D knapsack
python3 plot.py --plot rel --prob ks
# TSP
python3 plot.py --plot rel --prob tsp
```
### Regularization (Figure 11)
To draw performance comparison graphs with regularization, you need to additional train and evaluate SPO+ and DBB with L1/L2 regularization of cost. In our paper, the regularization parameter is 0.001.
Experiments for L1 regularization:
```bash
# shortest path
python3 experiments.py --prob sp --mthd spo --expnum 10 --l1
python3 experiments.py --prob sp --mthd dbb --expnum 10 --l1
# python3 experiments.py --prob sp --mthd dpo --expnum 10 --l1
python3 experiments.py --prob sp --mthd pfyl --expnum 10 --l1
# 2D knapsack
python3 experiments.py --prob ks --mthd spo --expnum 10 --l1
python3 experiments.py --prob ks --mthd dbb --expnum 10 --l1
# python3 experiments.py --prob ks --mthd dpo --expnum 10 --l1
python3 experiments.py --prob ks --mthd pfyl --expnum 10 --l1
# TSP
python3 experiments.py --prob tsp --mthd spo --expnum 10 --l1
python3 experiments.py --prob tsp --mthd dbb --expnum 10 --l1
# python3 experiments.py --prob tsp --mthd dpo --expnum 10 --l1
python3 experiments.py --prob tsp --mthd pfyl --expnum 10 --l1
```
Experiments for L2 regularization:
```bash
# shortest path
python3 experiments.py --prob sp --mthd spo --expnum 10 --l2
python3 experiments.py --prob sp --mthd dbb --expnum 10 --l2
# python3 experiments.py --prob sp --mthd dpo --expnum 10 --l2
python3 experiments.py --prob sp --mthd pfyl --expnum 10 --l2
# 2D knapsack
python3 experiments.py --prob ks --mthd spo --expnum 10 --l2
python3 experiments.py --prob ks --mthd dbb --expnum 10 --l2
# python3 experiments.py --prob ks --mthd dpo --expnum 10 --l2
python3 experiments.py --prob ks --mthd pfyl --expnum 10 --l2
```
Once the results of the experiments are ready, you can draw a plot for Figure 11:
```bash
# shortest path
python3 plot.py --plot reg --prob sp
# 2D knapsack
python3 plot.py --plot reg --prob ks
```
### MSE-Regret Trade-off (Figure 12)
To examine the MSE-regret trade-off among all above methods, you can draw a plot for Figure 12:
```bash
# shortest path
python3 plot.py --plot trd --prob sp
# 2D knapsack
python3 plot.py --plot trd --prob ks
# TSP
python3 plot.py --plot trd --prob tsp
```
### Warcraft Image Data (Figure 13)
We employ a truncated ResNet18 for an image dataset, Warcraft terrain map to find the shortest path. First, you need to download the [Warcraft Map Dataset](https://edmond.mpdl.mpg.de/dataset.xhtml?persistentId=doi:10.17617/3.YJCQ5S) and unzip it to ``./data``.
Then, we can train the convolutional neural network.
```bash
# 2-stage
python3 pipeline_wc.py --mthd 2s
# SPO+
python3 pipeline_wc.py --mthd spo
# PFYL
python pipeline_wc.py --mthd pfyl
# DBB
python pipeline_wc.py --mthd dbb --lr 1e-5
# dpo
python pipeline_wc.py --mthd dpo
```
To draw performance comparison plots:
```bash
python3 plot.py --plot wc
```