Source code for omlt.block
"""
The omlt.block module contains the implementation of the OmltBlock class. This
class is used in combination with a formulation object to construct the
necessary constraints and variables to represent ML models.
Example:
.. code-block:: python
import tensorflow.keras as keras
from omlt import OmltBlock
from omlt.neuralnet import FullSpaceNNFormulation
from omlt.io import load_keras_sequential
nn = keras.models.load_model(keras_fname)
net = load_keras_sequential(nn)
m = pyo.ConcreteModel()
m.neural_net_block = OmltBlock()
m.neural_net_block.build_formulation(FullSpaceNNFormulation(net))
m.obj = pyo.Objective(expr=(m.neural_net_block.outputs[2]-4.0)**2)
status = pyo.SolverFactory('ipopt').solve(m, tee=True)
pyo.assert_optimal_termination(status)
"""
import warnings
import pyomo.environ as pyo
from pyomo.core.base.block import _BlockData, declare_custom_block
[docs]@declare_custom_block(name="OmltBlock")
class OmltBlockData(_BlockData):
def __init__(self, component):
super(OmltBlockData, self).__init__(component)
self.__formulation = None
self.__input_indexes = None
self.__output_indexes = None
[docs] def _setup_inputs_outputs(self, *, input_indexes, output_indexes):
"""
This function should be called by the derived class to create the
inputs and outputs on the block
Args:
input_indexes : list
list of indexes (can be tuples) defining the set to be used for
the input variables
output_indexes : list
list of indexes (can be tuples) defining the set to be used for
the input variables
"""
self.__input_indexes = input_indexes
self.__output_indexes = output_indexes
if not input_indexes or not output_indexes:
# TODO: implement this check higher up in the class hierarchy to provide more contextual error msg
raise ValueError(
"OmltBlock must have at least one input and at least one output."
)
self.inputs_set = pyo.Set(initialize=input_indexes)
self.inputs = pyo.Var(self.inputs_set, initialize=0)
self.outputs_set = pyo.Set(initialize=output_indexes)
self.outputs = pyo.Var(self.outputs_set, initialize=0)
[docs] def build_formulation(self, formulation):
"""
Call this method to construct the constraints (and possibly
intermediate variables) necessary for the particular neural network
formulation. The formulation object can be accessed later through the
"formulation" attribute.
Parameters
----------
formulation : instance of _PyomoFormulation
see, for example, FullSpaceNNFormulation
"""
self._setup_inputs_outputs(
input_indexes=list(formulation.input_indexes),
output_indexes=list(formulation.output_indexes),
)
self.__formulation = formulation
# tell the formulation that it is working on this block (self)
self.__formulation._set_block(self)
# tell the formulation object to construct the necessary models
self.__formulation._build_formulation()