|
78 | 78 | ],
|
79 | 79 | "source": [
|
80 | 80 | "import os\n",
|
81 |
| - "os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # suppress CUDA warnings from tensorflow\n", |
| 81 | + "\n", |
| 82 | + "os.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"2\" # suppress CUDA warnings from tensorflow\n", |
82 | 83 | "\n",
|
83 | 84 | "# import the necessary packages\n",
|
84 |
| - "from omlt import OmltBlock, OffsetScaling\n", |
85 |
| - "from omlt.io.keras import load_keras_sequential\n", |
86 |
| - "from omlt.neuralnet import ReluBigMFormulation\n", |
87 |
| - "import pyomo.environ as pyo\n", |
88 | 85 | "import pandas as pd\n",
|
89 |
| - "import tensorflow.keras as keras\n", |
90 |
| - "from tensorflow.keras.models import Sequential\n", |
| 86 | + "import pyomo.environ as pyo\n", |
| 87 | + "from tensorflow import keras\n", |
91 | 88 | "from tensorflow.keras.layers import Dense\n",
|
| 89 | + "from tensorflow.keras.models import Sequential\n", |
92 | 90 | "from tensorflow.keras.optimizers import Adam\n",
|
93 |
| - "from tensorflow.keras.callbacks import ModelCheckpoint" |
| 91 | + "\n", |
| 92 | + "from omlt import OffsetScaling, OmltBlock\n", |
| 93 | + "from omlt.io.keras import load_keras_sequential\n", |
| 94 | + "from omlt.neuralnet import ReluBigMFormulation" |
94 | 95 | ]
|
95 | 96 | },
|
96 | 97 | {
|
|
151 | 152 | ],
|
152 | 153 | "source": [
|
153 | 154 | "# read in our csv data\n",
|
154 |
| - "columns = ['Bypass Fraction', 'NG Steam Ratio', 'Steam Flow',\n", |
155 |
| - " 'Reformer Duty','AR', 'C2H6', 'C3H8', 'C4H10',\n", |
156 |
| - " 'CH4', 'CO', 'CO2', 'H2', 'H2O', 'N2']\n", |
157 |
| - "df = pd.read_csv('../data/reformer.csv', usecols=columns)\n", |
| 155 | + "columns = [\n", |
| 156 | + " \"Bypass Fraction\",\n", |
| 157 | + " \"NG Steam Ratio\",\n", |
| 158 | + " \"Steam Flow\",\n", |
| 159 | + " \"Reformer Duty\",\n", |
| 160 | + " \"AR\",\n", |
| 161 | + " \"C2H6\",\n", |
| 162 | + " \"C3H8\",\n", |
| 163 | + " \"C4H10\",\n", |
| 164 | + " \"CH4\",\n", |
| 165 | + " \"CO\",\n", |
| 166 | + " \"CO2\",\n", |
| 167 | + " \"H2\",\n", |
| 168 | + " \"H2O\",\n", |
| 169 | + " \"N2\",\n", |
| 170 | + "]\n", |
| 171 | + "df = pd.read_csv(\"../data/reformer.csv\", usecols=columns)\n", |
158 | 172 | "print(df)"
|
159 | 173 | ]
|
160 | 174 | },
|
|
169 | 183 | "outputs": [],
|
170 | 184 | "source": [
|
171 | 185 | "# separate the data into inputs and outputs\n",
|
172 |
| - "inputs = ['Bypass Fraction', 'NG Steam Ratio']\n", |
173 |
| - "outputs = [ 'Steam Flow', 'Reformer Duty','AR', 'C2H6', 'C3H8', 'C4H10',\n", |
174 |
| - " 'CH4', 'CO', 'CO2', 'H2', 'H2O', 'N2']\n", |
| 186 | + "inputs = [\"Bypass Fraction\", \"NG Steam Ratio\"]\n", |
| 187 | + "outputs = [\n", |
| 188 | + " \"Steam Flow\",\n", |
| 189 | + " \"Reformer Duty\",\n", |
| 190 | + " \"AR\",\n", |
| 191 | + " \"C2H6\",\n", |
| 192 | + " \"C3H8\",\n", |
| 193 | + " \"C4H10\",\n", |
| 194 | + " \"CH4\",\n", |
| 195 | + " \"CO\",\n", |
| 196 | + " \"CO2\",\n", |
| 197 | + " \"H2\",\n", |
| 198 | + " \"H2O\",\n", |
| 199 | + " \"N2\",\n", |
| 200 | + "]\n", |
175 | 201 | "dfin = df[inputs]\n",
|
176 | 202 | "dfout = df[outputs]"
|
177 | 203 | ]
|
|
198 | 224 | "\n",
|
199 | 225 | "# capture the minimum and maximum values of the scaled inputs\n",
|
200 | 226 | "# so we don't use the model outside the valid range\n",
|
201 |
| - "scaled_lb = dfin.min()[inputs].values\n", |
202 |
| - "scaled_ub = dfin.max()[inputs].values" |
| 227 | + "scaled_lb = dfin.min()[inputs].to_numpy()\n", |
| 228 | + "scaled_ub = dfin.max()[inputs].to_numpy()" |
203 | 229 | ]
|
204 | 230 | },
|
205 | 231 | {
|
|
222 | 248 | ],
|
223 | 249 | "source": [
|
224 | 250 | "# create our Keras Sequential model\n",
|
225 |
| - "nn = Sequential(name='reformer_relu_4_20')\n", |
226 |
| - "nn.add(Dense(units=10, input_dim=len(inputs), activation='relu'))\n", |
227 |
| - "nn.add(Dense(units=10, activation='relu'))\n", |
228 |
| - "nn.add(Dense(units=10, activation='relu'))\n", |
229 |
| - "nn.add(Dense(units=10, activation='relu'))\n", |
| 251 | + "nn = Sequential(name=\"reformer_relu_4_20\")\n", |
| 252 | + "nn.add(Dense(units=10, input_dim=len(inputs), activation=\"relu\"))\n", |
| 253 | + "nn.add(Dense(units=10, activation=\"relu\"))\n", |
| 254 | + "nn.add(Dense(units=10, activation=\"relu\"))\n", |
| 255 | + "nn.add(Dense(units=10, activation=\"relu\"))\n", |
230 | 256 | "nn.add(Dense(units=len(outputs)))\n",
|
231 |
| - "nn.compile(optimizer=Adam(), loss='mse')" |
| 257 | + "nn.compile(optimizer=Adam(), loss=\"mse\")" |
232 | 258 | ]
|
233 | 259 | },
|
234 | 260 | {
|
|
449 | 475 | ],
|
450 | 476 | "source": [
|
451 | 477 | "# train our model\n",
|
452 |
| - "x = dfin.values\n", |
453 |
| - "y = dfout.values\n", |
| 478 | + "x = dfin.to_numpy()\n", |
| 479 | + "y = dfout.to_numpy()\n", |
454 | 480 | "\n",
|
455 | 481 | "history = nn.fit(x, y, epochs=100)"
|
456 | 482 | ]
|
|
468 | 494 | "# save the model to disk\n",
|
469 | 495 | "# While not technically necessary, this shows how we can load a previously saved model into\n",
|
470 | 496 | "# our optimization formulation)\n",
|
471 |
| - "nn.save('reformer_nn_relu.keras')" |
| 497 | + "nn.save(\"reformer_nn_relu.keras\")" |
472 | 498 | ]
|
473 | 499 | },
|
474 | 500 | {
|
|
522 | 548 | "outputs": [],
|
523 | 549 | "source": [
|
524 | 550 | "# load the Keras model\n",
|
525 |
| - "nn_reformer = keras.models.load_model('reformer_nn_relu.keras', compile=False)\n", |
| 551 | + "nn_reformer = keras.models.load_model(\"reformer_nn_relu.keras\", compile=False)\n", |
526 | 552 | "\n",
|
527 | 553 | "# Note: The neural network is in the scaled space. We want access to the\n",
|
528 | 554 | "# variables in the unscaled space. Therefore, we need to tell OMLT about the\n",
|
529 | 555 | "# scaling factors\n",
|
530 | 556 | "scaler = OffsetScaling(\n",
|
531 |
| - " offset_inputs={i: x_offset[inputs[i]] for i in range(len(inputs))},\n", |
532 |
| - " factor_inputs={i: x_factor[inputs[i]] for i in range(len(inputs))},\n", |
533 |
| - " offset_outputs={i: y_offset[outputs[i]] for i in range(len(outputs))},\n", |
534 |
| - " factor_outputs={i: y_factor[outputs[i]] for i in range(len(outputs))}\n", |
535 |
| - " )\n", |
| 557 | + " offset_inputs={i: x_offset[inputs[i]] for i in range(len(inputs))},\n", |
| 558 | + " factor_inputs={i: x_factor[inputs[i]] for i in range(len(inputs))},\n", |
| 559 | + " offset_outputs={i: y_offset[outputs[i]] for i in range(len(outputs))},\n", |
| 560 | + " factor_outputs={i: y_factor[outputs[i]] for i in range(len(outputs))},\n", |
| 561 | + ")\n", |
536 | 562 | "\n",
|
537 | 563 | "scaled_input_bounds = {i: (scaled_lb[i], scaled_ub[i]) for i in range(len(inputs))}\n",
|
538 | 564 | "\n",
|
539 | 565 | "# create a network definition from the Keras model\n",
|
540 |
| - "net = load_keras_sequential(nn_reformer, scaling_object=scaler, scaled_input_bounds=scaled_input_bounds)\n", |
| 566 | + "net = load_keras_sequential(\n", |
| 567 | + " nn_reformer, scaling_object=scaler, scaled_input_bounds=scaled_input_bounds\n", |
| 568 | + ")\n", |
541 | 569 | "\n",
|
542 | 570 | "# create the variables and constraints for the neural network in Pyomo\n",
|
543 | 571 | "m.reformer.build_formulation(ReluBigMFormulation(net))"
|
|
554 | 582 | "outputs": [],
|
555 | 583 | "source": [
|
556 | 584 | "# now add the objective and the constraints\n",
|
557 |
| - "h2_idx = outputs.index('H2')\n", |
558 |
| - "n2_idx = outputs.index('N2')\n", |
| 585 | + "h2_idx = outputs.index(\"H2\")\n", |
| 586 | + "n2_idx = outputs.index(\"N2\")\n", |
559 | 587 | "m.obj = pyo.Objective(expr=m.reformer.outputs[h2_idx], sense=pyo.maximize)\n",
|
560 | 588 | "m.con = pyo.Constraint(expr=m.reformer.outputs[n2_idx] <= 0.34)"
|
561 | 589 | ]
|
|
571 | 599 | "outputs": [],
|
572 | 600 | "source": [
|
573 | 601 | "# now solve the optimization problem (this may take some time)\n",
|
574 |
| - "solver = pyo.SolverFactory('cbc')\n", |
| 602 | + "solver = pyo.SolverFactory(\"cbc\")\n", |
575 | 603 | "status = solver.solve(m, tee=False)"
|
576 | 604 | ]
|
577 | 605 | },
|
|
596 | 624 | }
|
597 | 625 | ],
|
598 | 626 | "source": [
|
599 |
| - "print('Bypass Fraction:', pyo.value(m.reformer.inputs[0]))\n", |
600 |
| - "print('NG Steam Ratio:', pyo.value(m.reformer.inputs[1]))\n", |
601 |
| - "print('H2 Concentration:', pyo.value(m.reformer.outputs[h2_idx]))\n", |
602 |
| - "print('N2 Concentration:', pyo.value(m.reformer.outputs[n2_idx]))" |
| 627 | + "print(\"Bypass Fraction:\", pyo.value(m.reformer.inputs[0]))\n", |
| 628 | + "print(\"NG Steam Ratio:\", pyo.value(m.reformer.inputs[1]))\n", |
| 629 | + "print(\"H2 Concentration:\", pyo.value(m.reformer.outputs[h2_idx]))\n", |
| 630 | + "print(\"N2 Concentration:\", pyo.value(m.reformer.outputs[n2_idx]))" |
603 | 631 | ]
|
604 | 632 | }
|
605 | 633 | ],
|
|
0 commit comments