Skip to content

New models for softmax#355

Open
pobonomo wants to merge 10 commits into
Gurobi:mainfrom
pobonomo:mutlinomialv12
Open

New models for softmax#355
pobonomo wants to merge 10 commits into
Gurobi:mainfrom
pobonomo:mutlinomialv12

Conversation

@pobonomo

Copy link
Copy Markdown
Member

Do new models for softmax

@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 3 times, most recently from 347a9e3 to 8042b51 Compare November 2, 2024 21:07
@pobonomo pobonomo added safe to test If applied to a PR, will start the tests that require a Gurobi license and removed safe to test If applied to a PR, will start the tests that require a Gurobi license labels Nov 2, 2024
@mmaaz-git

Copy link
Copy Markdown

Hi Pierre: just wanted to check if you have an estimate for when you think this will be merged. I'd love to use it! No pressure at all. Or as you indicate it's safe to test, so I could locally clone this PR and play around with it? Thanks.

@pobonomo pobonomo added Models and removed safe to test If applied to a PR, will start the tests that require a Gurobi license labels Nov 8, 2024
@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 2 times, most recently from aa2ef69 to 0c981b3 Compare November 8, 2024 08:45
@pobonomo pobonomo added the safe to test If applied to a PR, will start the tests that require a Gurobi license label Nov 8, 2024
@pobonomo

pobonomo commented Nov 8, 2024

Copy link
Copy Markdown
Member Author

Hi Pierre: just wanted to check if you have an estimate for when you think this will be merged. I'd love to use it! No pressure at all. Or as you indicate it's safe to test, so I could locally clone this PR and play around with it? Thanks.

Hi,

I have no estimate currently. The models are working I think but it's a big change and there is a lot of cleanup.

Note that what is implemented so far is using softmax for scikit-learn only: multinomial logistic regression and neural networks. I didn't implement counter-parts for Keras and Pytorch yet (the code should be very simple but there would be a lot of testing).

I think that it is usable though so if you want to play with it you could try (and more testing cannot hurt).

Best,
Pierre

@mmaaz-git

Copy link
Copy Markdown

Thanks, will do!

@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 3 times, most recently from 363b38d to ad4c84c Compare November 12, 2024 09:19
@pobonomo pobonomo added safe to test If applied to a PR, will start the tests that require a Gurobi license and removed safe to test If applied to a PR, will start the tests that require a Gurobi license labels Nov 12, 2024
@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 3 times, most recently from dbab218 to 327d178 Compare December 7, 2024 14:07
@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 5 times, most recently from 2259241 to f75c9e6 Compare January 2, 2025 17:59
@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 2 times, most recently from 1830edf to 86c8f73 Compare February 22, 2026 11:37
@CLAassistant

CLAassistant commented Feb 22, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 37 out of 43 changed files in this pull request and generated 17 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/gurobi_ml/sklearn/skgetter.py Outdated
Comment thread src/gurobi_ml/sklearn/mlpregressor.py Outdated
Comment on lines 72 to +87
@@ -74,7 +79,12 @@ class PipelineConstr(SKgetter, AbstractPredictorConstr):
def __init__(self, gp_model, pipeline, input_vars, output_vars=None, **kwargs):
self._steps = []
self._default_name = "pipe"
SKgetter.__init__(self, pipeline, input_vars, **kwargs)
if hasattr(pipeline, "predict_proba"):
SKClassifier.__init__(self, pipeline, input_vars, **kwargs)
self._isclassifier = True
else:
SKRegressor.__init__(self, pipeline, input_vars, **kwargs)
self._isclassifier = False

Copilot AI Feb 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diamond inheritance pattern (SKRegressor, SKClassifier both inherit from SKgetter) combined with conditional initialization could lead to unexpected behavior. While the comment acknowledges this, the Method Resolution Order (MRO) means SKRegressor.init will be called first regardless of the conditional. Consider using composition instead of multiple inheritance, or ensure the parent classes properly use super() to handle the diamond pattern correctly.

Copilot uses AI. Check for mistakes.
Comment thread src/gurobi_ml/modeling/softmax.py Outdated
Comment thread tests/fixed_formulation.py Outdated
else:
tol = 1e-5
vio = gpm.MaxVio
tol = 5e-3

Copilot AI Feb 22, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tolerance is set based on the nonconvex parameter (line 80-83), but then immediately overwritten to 5e-3 on line 84 regardless of the nonconvex value. This makes the conditional logic on lines 80-83 dead code. Either remove the conditional or remove line 84 if it was added for debugging.

Suggested change
tol = 5e-3

Copilot uses AI. Check for mistakes.
Comment thread tests/fixed_formulation.py Outdated
Comment thread src/gurobi_ml/keras/keras.py Outdated
Comment thread src/gurobi_ml/sklearn/skgetter.py Outdated
Comment thread src/gurobi_ml/sklearn/mlpregressor.py Outdated
Comment thread src/gurobi_ml/modeling/neuralnet/layers.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 37 out of 43 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 2 times, most recently from 5c8135d to b8b538b Compare February 23, 2026 08:23
@pobonomo
pobonomo force-pushed the mutlinomialv12 branch 2 times, most recently from 9da9c74 to bc62309 Compare April 26, 2026 19:32
pobonomo and others added 10 commits May 8, 2026 16:49
Introduce softmax layer modeling for neural networks and extend
LogisticRegression to support multinomial classification (one-vs-rest
and multinomial/softmax modes).

Key changes:
   - Add softmax.py module for softmax layer formulation
   - Refactor LogisticRegression to handle multinomial classification
   - Extend activation functions with softmax support
   - Add adversarial example notebooks
   - Update predictor getter to support classification mip-models
Extend neural network modeling to support MLPClassifier from scikit-learn,
enabling multi-class classification with neural networks in optimization
models. This builds on the softmax infrastructure to handle the classifier's
output layer appropriately.

Changes:
  - Add MLPClassifierConstr class in mlpregressor.py module
  - Handle both regression and classification MLP models
  - Add iris dataset test cases for MLPClassifier
  - Update MNIST examples to use MLPClassifier instead of MLPRegressor
If predict_function is identity we don't apply any softmax
It is not used anymore

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants