leggedrobotics / rayen

Imposition of Hard Convex Constraints on Neural Networks
BSD 3-Clause "New" or "Revised" License
69 stars 7 forks source link

RAYEN: Imposition of Hard Convex Constraints on Neural Networks

Paper: http://arxiv.org/abs/2307.08336

This framework allows you to impose convex constraints on the output or latent variable of a Neural Network.

Installation

First make sure that you have pip up-to-date:

pip install --upgrade pip

Then, you simply need to do:

pip install rayen

If you want to do an editable install, you can also do:

git clone https://github.com/leggedrobotics/rayen.git
cd rayen && pip install -e .

Usage

A minimal example is as follows:

import torch
import numpy as np
from rayen import constraints, constraint_module

#Linear constraints
A1 = np.array([[1.0, 0, 0], [0, 1.0, 0], [0, 0, 1.0], [-1.0, 0, 0], [0, -1.0, 0], [0, 0, -1.0]]);
b1 = np.array([[1.0], [1.0], [1.0], [0], [0], [0]])
A2 = np.array([[1.0, 1.0, 1.0]]);
b2 = np.array([[1.0]]);
lc=constraints.LinearConstraint(A1, b1, A2, b2) #Set lc to None if there are no linear constraints
                                                #Set A1 and b1 to None if there are no linear inequality constraints
                                                #Set A2 and b2 to None if there are no linear equality constraints

#Quadratic constraints
P = np.array([[3.125,0.0,0.0], [0.0,3.125,0.0], [0.0,0.0,3.125]])
q = np.array([[0.0],[0.0],[0.0]])
r = np.array([[-1.0]])
qcs = [constraints.ConvexQuadraticConstraint(P, q, r)] #Set qcs to [] if there are no quadratic constraints
                                                       #More quadratic constraints can be appended to this list

#SOC constraints
M=np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0],[0.0, 0.0, 0.0]])
s=np.array([[0.0],[0.0],[0.0]])
c=np.array([[0.0],[0.0],[1.0]])
d=np.array([[0.0]])
socs = [constraints.SOCConstraint(M, s, c, d)] #Set socs to [] if there are no SOC constraints
                                               #More SOC constraints can be appended to this list

#LMI constraint (semidefinite constraint)
F0=np.array([[1.0, 0.0],[0.0, 0.0]])
F1=np.array([[0.0, 1.0],[1.0, 0.0]])
F2=np.array([[0.0, 0.0],[0.0, 1.0]])
F3=np.array([[0.0, 0.0],[0.0, 0.0]])
lmic=constraints.LMIConstraint([F0, F1, F2, F3]) #Set lmic to None if there are no LMI constraints

#----

cs = constraints.ConvexConstraints(lc=lc, qcs=qcs, socs=socs, lmic=lmic)

model = torch.nn.Sequential(torch.nn.Flatten(), torch.nn.Linear(3, 64),
                            torch.nn.ReLU(),    torch.nn.Linear(64, 64),
                            constraint_module.ConstraintModule(cs, input_dim=64, create_map=True)) 

x_batched = torch.Tensor(500, 3, 1).uniform_(-1.0, 1.0)
y_batched = model(x_batched)

#Each element of y_batched is guaranteed to satisfy the constraints

# loss = ...      # y_batched can be used here
# loss.backward() # Backpropagate

These are the methods implemented in this repo (please see the paper for details):

Method Linear Quadratic SOC LMI
UU
UP
PP
DC3
Bar
RAYEN

where denotes supported by the algorithm and implemented in the code, denotes not supported by the algorithm, and denotes supported by the algorithm but not implemented yet.

You can choose the method to use setting the argument method when creating the layer.

More examples

There are more complex examples in the examples folder. If you want to run these examples:

sudo apt-get install git-lfs
git clone https://github.com/leggedrobotics/rayen.git
cd rayen
git lfs install 
git submodule init && git submodule update --init --recursive
pip install -r examples/requirements_examples.txt

These are the most important files in the examples folder:

Some of these examples use (or can use) Gurobi Optimizer. Once installed (following the instructions in the previous link) you can test the installation typing gurobi.sh in the terminal. You will also need this package:

pip install gurobipy
Casadi installation instructions (optional dependency) ```bash #IPOPT stuff sudo apt-get install gcc g++ gfortran git cmake liblapack-dev pkg-config --install-recommends sudo apt-get install coinor-libipopt1v5 coinor-libipopt-dev #SWIG stuff sudo apt-get remove swig swig3.0 swig4.0 #If you don't do this, the compilation of casadi may fail with the error "swig error : Unrecognized option -matlab" mkdir ~/installations && cd ~/installations git clone https://github.com/jaeandersson/swig cd swig git checkout -b matlab-customdoc origin/matlab-customdoc sh autogen.sh sudo apt-get install gcc-7 g++-7 bison byacc sudo apt-get install libpcre3 libpcre3-dev ./configure CXX=g++-7 CC=gcc-7 make sudo make install #CASADI stuff cd ~/installations && mkdir casadi && cd casadi git clone https://github.com/casadi/casadi cd casadi/cmake && wget https://github.com/leggedrobotics/rayen/raw/master/examples/other/FindGurobi.cmake #This ones works for higher versions of Gurobi cd .. #cd build && make clean && cd .. && rm -rf build #Only if you want to clean any previous installation/compilation mkdir build && cd build cmake . -DCMAKE_BUILD_TYPE=Release -DWITH_IPOPT=ON -DWITH_MATLAB=ON -DWITH_PYTHON=ON -DWITH_DEEPBIND=ON -DWITH_GUROBI=ON .. #You may need to run the command above twice until the output says that `Ipopt` has been detected (although `IPOPT` is also being detected when you run it for the first time) make -j20 sudo make install ```
Publishing to PyPI More info [here](https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/). See also the file `python-publish.yml` First change the `version` line in `pyproject.toml` to X.X.X. Then do the following: ```bash git add pyproject.toml && git commit -m "updated version" && git tag vX.X.X git push origin master vX.X.X ```