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))`
```
Discussed in https://github.com/cog-imperial/OMLT/discussions/127