Skip to content

Commit

Permalink
Try completing test with Keras
Browse files Browse the repository at this point in the history
Also adds a classification test probably this will be overkill for GH actions
but try it.
  • Loading branch information
pobonomo committed Jan 3, 2025
1 parent 367196e commit f1f1f34
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 36 deletions.
1 change: 0 additions & 1 deletion src/gurobi_ml/modeling/softmax.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ def softmax(
predictor_model.linear_predictor = linear_predictor_vars

exponentials = gp_model.addMVar(output.shape)
exponentials = exponentials
denominator = gp_model.addMVar((output.shape[0]), lb=epsilon)

num_gc = gp_model.NumGenConstrs
Expand Down
84 changes: 50 additions & 34 deletions tests/test_keras/keras_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
"""

import os
from abc import ABC, abstractmethod

import tensorflow as tf
import keras

try:
from gurobipy import nlfunc # noqa: F401

HAS_NL_EXPR = True
except ImportError:
HAS_NL_EXPR = False


def layers_as_string(layers):
if isinstance(layers, str):
Expand All @@ -32,25 +39,11 @@ def __init__(
self,
dataset,
):
self.basedir = os.path.join(os.path.dirname(__file__), "..", "predictors")
self.dataset = dataset

# Filled with get data if needed
self._data = None

keras_version_file = f"{dataset}_keras_version"

try:
with open(os.path.join(self.basedir, keras_version_file)) as file_in:
version = file_in.read().strip()
except FileNotFoundError:
version = None
if version != keras.__version__:
print(f"Keras version changed. Regenerate predictors for {dataset}")
self.build_all_predictors()
with open(os.path.join(self.basedir, keras_version_file), "w") as file_out:
print(keras.__version__, file=file_out)

def __iter__(self):
return self.all_tested_layers.__iter__()

Expand All @@ -69,39 +62,28 @@ def data(self):
self.load_data()
return self._data

def predictor_file(self, predictor):
return f"{self.dataset}_{layers_as_string(predictor)}.keras"

def build_predictor(self, layers):
def get_case(self, layers):
"""Build model for one predictor"""
X, y = self.data
predictor = self.compile(layers)
predictor.fit(X, y)

predictor.save(self.predictor_file(layers))
return predictor

def build_all_predictors(self):
"""Build all the predictor for this case.
(Done when we have a new sklearn version)"""
for predictor in self:
self.build_predictor(predictor)

def get_case(self, predictor):
filename = self.predictor_file(predictor)
try:
return keras.saving.load_model(os.path.join(self.basedir, filename))
except ValueError:
return self.build_predictor(predictor)


class HousingCases(Cases):
"""Base class to have cases for testing regression models on diabetes set
This is appropriate for testing a regression with a single output."""

def __init__(self):
self.all_tested_layers = [[keras.layers.Dense(16, activation="relu")]]
self.all_tested_layers = [
[keras.layers.Dense(16, activation="relu")],
]
if HAS_NL_EXPR:
self.all_tested_layers.append(
[keras.layers.Dense(16, activation="sigmoid")],
)
super().__init__("housing")
self.load_data()

Expand All @@ -117,3 +99,37 @@ def compile(self, layers):
)
nn.compile(loss="mean_squared_error", optimizer="adam")
return nn


class MNISTCases(Cases):
"""Base class to have cases for testing regression models on diabetes set
This is appropriate for testing a regression with a single output."""

def __init__(self):
self.all_tested_layers = [
[keras.layers.Dense(20, activation="relu")],
]

if HAS_NL_EXPR:
self.all_tested_layers += [
[keras.layers.Dense(20, activation="sigmoid")],
]
super().__init__("housing")
self.load_data()

def load_data(self):
(X_train, y_train), (_, _) = keras.datasets.fashion_mnist.load_data()
X_train = tf.reshape(tf.cast(X_train, tf.float32) / 255.0, [-1, 28 * 28])
self._data = (X_train, y_train)

def compile(self, layers):
nn = keras.models.Sequential(
[keras.layers.InputLayer((28 * 28,))] + layers + [keras.layers.Dense(10)]
)
nn.compile(
optimizer="adam",
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()],
)
return nn
17 changes: 16 additions & 1 deletion tests/test_keras/test_keras_formulations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
import keras
from joblib import load

try:
HAS_NL_EXPR = True
except ImportError:
HAS_NL_EXPR = False

from ..fixed_formulation import FixedRegressionModel
from .keras_cases import HousingCases
from .keras_cases import HousingCases, MNISTCases

VERBOSE = False

Expand Down Expand Up @@ -45,3 +50,13 @@ def test_housing_keras(self):
onecase = {"predictor": regressor, "nonconvex": 0}
self.do_one_case(onecase, X, 5, "all")
self.do_one_case(onecase, X, 6, "pairs")

def test_mnist_keras(self):
cases = MNISTCases()

X = cases._data[0].numpy()
for case in cases:
regressor = cases.get_case(case)
onecase = {"predictor": regressor, "nonconvex": 0}
self.do_one_case(onecase, X, 5, "all")
self.do_one_case(onecase, X, 6, "pairs")

0 comments on commit f1f1f34

Please sign in to comment.