cog-imperial / OMLT

Represent trained machine learning models as Pyomo optimization formulations
Other
257 stars 56 forks source link

OMLT Main Example: Pyomo build_formation function fails #130

Closed bspiveyxom closed 8 months ago

bspiveyxom commented 8 months ago

Discussed in https://github.com/cog-imperial/OMLT/discussions/127

Originally posted by **bspiveyxom** October 20, 2023 I tried testing the main OMLT example using a Keras model. The only code I replaced is defining the Keras model "nn". Loading the Keras model into an OMLT network definition and creating the formulation worked. Then this example fails when calling build_formulation. Has anyone else tested this and seen this error? Maybe I just need more examples of how to use custom NN models? Help is appreciated to know if this is a bug or need to change the code to use a custom NN model. ERROR: Rule failed when initializing variable for Var nn.scaled_inputs with index 1: KeyError: 1 ERROR: Constructing component 'nn.scaled_inputs' from data=None failed: KeyError: 1 KeyError Traceback (most recent call last) File :44 41 formulation = FullSpaceNNFormulation(net) 43 #build the formulation on the OMLT block ---> 44 model.nn.build_formulation(formulation) 46 #query inputs and outputs, as well as scaled inputs and outputs 47 model.nn.inputs.display() File /local_disk0/.ephemeral_nfs/envs/pythonEnv-270249cb-9f79-4e2c-a55c-4f7dd0a7b838/lib/python3.10/site-packages/omlt/block.py:89, in OmltBlockData.build_formulation(self, formulation) 86 self.__formulation._set_block(self) 88 # tell the formulation object to construct the necessary models ---> 89 self.__formulation._build_formulation() File /local_disk0/.ephemeral_nfs/envs/pythonEnv-270249cb-9f79-4e2c-a55c-4f7dd0a7b838/lib/python3.10/site-packages/omlt/neuralnet/nn_formulation.py:106, in FullSpaceNNFormulation._build_formulation(self) 105 def _build_formulation(self): --> 106 _setup_scaled_inputs_outputs( 107 self.block, self.__scaling_object, self.__scaled_input_bounds 108 ) 110 _build_neural_network_formulation( ``` import tensorflow as tf from tensorflow.keras.layers import Dense from tensorflow.keras.models import Sequential import pyomo.environ as pyo from omlt import OmltBlock, OffsetScaling from omlt.neuralnet import FullSpaceNNFormulation, NetworkDefinition from omlt.io import load_keras_sequential # define the Keras model nn = Sequential() nn.add(Dense(12, input_shape=(8,), activation='relu')) nn.add(Dense(8, activation='relu')) nn.add(Dense(1, activation='sigmoid')) #create a Pyomo model with an OMLT block model = pyo.ConcreteModel() model.nn = OmltBlock() #the neural net contains one input and one output model.input = pyo.Var() model.output = pyo.Var() #apply simple offset scaling for the input and output scale_x = (1, 0.5) #(mean,stdev) of the input scale_y = (-0.25, 0.125) #(mean,stdev) of the output scaler = OffsetScaling(offset_inputs=[scale_x[0]], factor_inputs=[scale_x[1]], offset_outputs=[scale_y[0]], factor_outputs=[scale_y[1]]) #provide bounds on the input variable (e.g. from training) scaled_input_bounds = {0:(0,5)} #load the keras model into a network definition net = load_keras_sequential(nn,scaler,scaled_input_bounds) #multiple formulations of a neural network are possible #this uses the default NeuralNetworkFormulation object formulation = FullSpaceNNFormulation(net) #build the formulation on the OMLT block model.nn.build_formulation(formulation) #query inputs and outputs, as well as scaled inputs and outputs model.nn.inputs.display() model.nn.outputs.display() model.nn.scaled_inputs.display() model.nn.scaled_outputs.display() #connect pyomo model input and output to the neural network @model.Constraint() def connect_input(mdl): return mdl.input == mdl.nn.inputs[0] @model.Constraint() def connect_output(mdl): return mdl.output == mdl.nn.outputs[0] #solve an inverse problem to find that input that most closely matches the output value of 0.5 model.obj = pyo.Objective(expr=(model.output - 0.5)**2) status = pyo.SolverFactory('ipopt').solve(model, tee=False) print(pyo.value(model.input)) print(pyo.value(model.output))` ```
bspiveyxom commented 8 months ago

Closing issue for now. Revisiting OMLT example notebooks.