-
Notifications
You must be signed in to change notification settings - Fork 0
26 integrate modular anns #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
PatrickHenkel1
wants to merge
64
commits into
main
Choose a base branch
from
26-integrate-modular-anns
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
64 commits
Select commit
Hold shift + click to select a range
037e816
Working progress
PatrickHenkel 1daa46a
Updated inits
PatrickHenkel 14ed7cb
Updated Modular Networks, Added Keywords for PreprocessingData init
PatrickHenkel 0d5120c
Added new Modular Features
PatrickHenkel 8f1797d
Added test for modular ANN and bug fix
PatrickHenkel df60c01
Updated
PatrickHenkel e06bbbf
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel 488eab5
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel f5aec51
Merge branch '26-integrate-modular-anns' of https://github.com/RWTH-E…
PatrickHenkel 6f9266f
Removed non backwards compatible changes in init
PatrickHenkel fd9ea25
Update coverage badge [skip ci]
actions-user fe765c5
Updated
PatrickHenkel a14e651
Update coverage badge [skip ci]
actions-user 67140fc
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel dc0bd9a
Merge branch 'main' into 26-integrate-modular-anns
PatrickHenkel1 42a8cda
Bug fix
PatrickHenkel 350ac20
Merge branch '26-integrate-modular-anns' of https://github.com/RWTH-E…
PatrickHenkel c92ae5e
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel f8dca2c
Update coverage badge [skip ci]
actions-user 99b80b9
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel 095208a
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel d4111ab
Merge branch '26-integrate-modular-anns' of https://github.com/RWTH-E…
PatrickHenkel 5060b9e
Small bug fix
PatrickHenkel ecb9e23
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel d4305e4
Update coverage badge [skip ci]
actions-user 2866780
Small bug fixes
PatrickHenkel 262b3dc
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel 5a7d0dc
Added scaling
PatrickHenkel e36b0e3
Update coverage badge [skip ci]
actions-user 648e7ad
Better normalization
PatrickHenkel bec6ed7
Merge branch '26-integrate-modular-anns' of https://github.com/RWTH-E…
PatrickHenkel 0124cab
Refactoring
PatrickHenkel 6922e79
Merge branch '54-bug-fix-global-variable-saving-could-mess-up-scenari…
PatrickHenkel dca2318
Merge
PatrickHenkel 72937e7
Bug fix
PatrickHenkel 293dd28
Updated API
PatrickHenkel b29ebcd
Merge branch 'main' into 26-integrate-modular-anns
PatrickHenkel1 0394a7c
Update coverage badge [skip ci]
actions-user 9b8cf80
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel 74dac95
Merge remote-tracking branch 'remotes/origin/59-fix-residual-rbf-mode…
PatrickHenkel 920742e
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel 7bc8512
Added Montone Linear
PatrickHenkel 49090c3
Added get_config methods for modular expressions
cb9d249
Fixed error
822f0c2
Fixed testing error
940dfd7
Updated save path
780ee12
partially added from_config
4abda06
Added reversed pow
PatrickHenkel 313a8cc
added from_config for modular_ann.py
134a923
Merge branch '26-integrate-modular-anns' of https://github.com/RWTH-E…
1a53cd0
added testing of from_config methods, fixed small errors
347e2f0
corrected type hint
e51614f
updated unittests -> testing of all modular modules, fixed small errors
5d3fef0
Bug fix
PatrickHenkel 28dd559
Merge branch '26-integrate-modular-anns' of https://github.com/RWTH-E…
PatrickHenkel 13270eb
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel eeaf3c5
Update coverage badge [skip ci]
actions-user 6866397
Merge remote-tracking branch 'remotes/origin/main' into 26-integrate-…
PatrickHenkel 5361850
Added bias and logging
PatrickHenkel 8d17c6d
Added constrained regression
PatrickHenkel d00adbd
Working progress
PatrickHenkel 3e77d93
Working example of constrained regression (to be tested)
PatrickHenkel 98bdd61
Implementation improvements
PatrickHenkel 0f83de8
Updated
PatrickHenkel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| from physXAI.models.modular.modular_ann import ModularANN, ModularModel | ||
| from physXAI.preprocessing.preprocessing import PreprocessingSingleStep | ||
| from physXAI.preprocessing.constructed import Feature | ||
| from physXAI.models.ann.ann_design import ClassicalANNModel | ||
| from physXAI.utils.logging import Logger | ||
|
|
||
|
|
||
| """ | ||
| Creates modular models to predict the power of the heat pump using the Boptest data. | ||
| """ | ||
|
|
||
| Logger.setup_logger(folder_name='P_hp_modular', override=True) | ||
|
|
||
| file_path = r"data/bestest_hydronic_heat_pump/pid_data.csv" | ||
|
|
||
| inputs = ['oveHeaPumY_u', 'Func(logistic)', 'weaSta_reaWeaTDryBul_y', 'reaTZon_y'] | ||
| output = 'reaPHeaPum_y' | ||
|
|
||
| oveHeaPumY_u = Feature('oveHeaPumY_u') | ||
| func_logistic = Feature('Func(logistic)') | ||
| TDryBul = Feature('weaSta_reaWeaTDryBul_y') | ||
| TZon = Feature('reaTZon_y') | ||
|
|
||
| prep = PreprocessingSingleStep(inputs=inputs, output=output) | ||
| td = prep.pipeline(file_path) | ||
|
|
||
| """Example usages of modular models""" | ||
| y = ModularModel( | ||
| model=ClassicalANNModel(), | ||
| inputs=[oveHeaPumY_u.input() / func_logistic.input(), func_logistic.input() ** 2, TDryBul.input(), TZon.input()] | ||
| ) | ||
| m = ModularANN(architecture=y, rescale_output=True) | ||
|
|
||
| # Training pipeline | ||
| model = m.pipeline(td) | ||
|
|
||
|
|
||
| # Log setup of preprocessing and model as json | ||
| Logger.log_setup(prep, m) | ||
| # Log training data as pickle | ||
| Logger.save_training_data(td) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| import math | ||
| import casadi as ca | ||
| import numpy as np | ||
| import matplotlib.pyplot as plt | ||
| from itertools import combinations_with_replacement | ||
| import pandas as pd | ||
|
|
||
| class CasadiConstrainedFit: | ||
| def __init__(self, degree=3): | ||
| self.degree = degree | ||
| self.opti = ca.Opti() | ||
| self.weights_val = None | ||
| self.term_names = [] # Zum Speichern der Namen (z.B. "x0*x1^2") | ||
|
|
||
| def fit(self, X, y, monotonic_features=[], convex_features=[]): | ||
| if X.ndim == 1: X = X[:, None] | ||
| N, n_features = X.shape | ||
|
|
||
| # --- 1. Symbolisches Modell --- | ||
| w_sym_list = [] | ||
| x_sym = ca.MX.sym('x', n_features) | ||
| y_sym = 0 | ||
| self.term_names = [] | ||
|
|
||
| # Iteriere über alle Polynom-Grade | ||
| for d in range(self.degree + 1): | ||
| for indices in combinations_with_replacement(range(n_features), d): | ||
| w_i = self.opti.variable() | ||
|
|
||
| # Term bauen und Namen speichern | ||
| term = 1 | ||
| name_parts = [] | ||
| for idx in indices: | ||
| term *= x_sym[idx] | ||
| name_parts.append(f"x{idx}") | ||
|
|
||
| term_name = "*".join(name_parts) if name_parts else "Bias" | ||
| self.term_names.append(term_name) | ||
|
|
||
| y_sym += w_i * term | ||
| w_sym_list.append(w_i) | ||
|
|
||
| w_vec = ca.vertcat(*w_sym_list) | ||
|
|
||
| # --- 2. Ableitungen (Wichtig: gradient statt jacobian) --- | ||
| grad_sym = ca.gradient(y_sym, x_sym) | ||
| hess_sym, _ = ca.hessian(y_sym, x_sym) | ||
|
|
||
| f_pred = ca.Function('f_pred', [x_sym, w_vec], [y_sym]) | ||
| f_grad = ca.Function('f_grad', [x_sym, w_vec], [grad_sym]) | ||
| f_hess = ca.Function('f_hess', [x_sym, w_vec], [ca.diag(hess_sym)]) | ||
|
|
||
| # --- 3. Zielfunktion --- | ||
| y_pred_all = f_pred.map(N)(X.T, ca.repmat(w_vec, 1, N)) | ||
| error = y_pred_all - y.reshape(1, N) | ||
| obj = ca.mtimes(error, error.T) | ||
| self.opti.minimize(obj) | ||
|
|
||
| # --- 4. Constraints --- | ||
| if monotonic_features: | ||
| grad_all = f_grad.map(N)(X.T, ca.repmat(w_vec, 1, N)) | ||
| for feat_idx in monotonic_features: | ||
| self.opti.subject_to(grad_all[feat_idx, :].T >= 0) | ||
|
|
||
| if convex_features: | ||
| hess_all = f_hess.map(N)(X.T, ca.repmat(w_vec, 1, N)) | ||
| for feat_idx in convex_features: | ||
| self.opti.subject_to(hess_all[feat_idx, :].T >= 0) | ||
|
|
||
| # --- 5. Lösen --- | ||
| opts = {'ipopt.print_level': 0, 'print_time': 0, 'expand': True} | ||
| self.opti.solver('ipopt', opts) | ||
|
|
||
| try: | ||
| sol = self.opti.solve() | ||
| self.weights_val = sol.value(w_vec) | ||
| except: | ||
| self.weights_val = self.opti.debug.value(w_vec) | ||
|
|
||
| self.predict_fn = f_pred | ||
| self.grad_fn = f_grad | ||
|
|
||
| def predict(self, X): | ||
| if X.ndim == 1: X = X[:, None] | ||
| N = X.shape[0] | ||
| res = self.predict_fn.map(N)(X.T, ca.repmat(self.weights_val, 1, N)) | ||
| return res.full().flatten() | ||
|
|
||
| def predict_derivative(self, X, feature_idx): | ||
| if X.ndim == 1: X = X[:, None] | ||
| N = X.shape[0] | ||
| grad = self.grad_fn.map(N)(X.T, ca.repmat(self.weights_val, 1, N)) | ||
| return grad.full()[feature_idx, :].flatten() | ||
|
|
||
| def inspect_weights(self): | ||
| """Zeigt die gelernten Gewichte tabellarisch an.""" | ||
| df = pd.DataFrame({ | ||
| 'Term': self.term_names, | ||
| 'Weight': self.weights_val | ||
| }) | ||
| # Filtere kleine Gewichte raus für Übersichtlichkeit | ||
| print("\n--- Gelernte Gewichte (Top Beiträge) ---") | ||
| print(df[df['Weight'].abs() > 1e-4]) | ||
| print("----------------------------------------\n") | ||
|
|
||
| # --- ANWENDUNG --- | ||
|
|
||
| np.random.seed(42) | ||
| N = 100 | ||
|
|
||
| x1 = np.linspace(0, 3, N) | ||
| x2 = np.random.uniform(0, 3, N) | ||
|
|
||
| X_train = np.column_stack([x1, x2]) | ||
|
|
||
| # Wahre Funktion | ||
| y_true = x1 ** 3 + x2 * x1 ** 2 | ||
| y_noise = y_true | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| # Fitting | ||
| model = CasadiConstrainedFit(degree=3) | ||
| model.fit(X_train, y_noise, monotonic_features=[], convex_features=[]) | ||
|
|
||
| # Gewichte prüfen - schauen Sie, ob x0*x0 (also x1^2) ein hohes Gewicht hat! | ||
| model.inspect_weights() | ||
|
|
||
| # Plots | ||
| y_pred = model.predict(X_train) | ||
| dy_dx1 = model.predict_derivative(X_train, feature_idx=0) | ||
|
|
||
| fig, ax = plt.subplots(1, 2, figsize=(14, 6)) | ||
|
|
||
| # Plot 1: Regression | ||
| # Wir sortieren für den Plot, sonst sieht es bei zufälligem x2 wüst aus | ||
| sort_idx = np.argsort(x1) | ||
| ax[0].scatter(x1, y_noise, color='gray', alpha=0.3, label='Daten') | ||
| ax[0].plot(x1[sort_idx], y_pred[sort_idx], 'r-', linewidth=2, label='CasADi Fit') | ||
| ax[0].set_title('Fit (y vs x1)') | ||
| ax[0].legend() | ||
|
|
||
| # Plot 2: Ableitung | ||
| # Da x2 zufällig ist, wackelt die Ableitung dy/dx1 leicht (wegen Interaktionstermen), | ||
| # aber der Trend (lineares Ansteigen, da Funktion quadratisch) muss sichtbar sein. | ||
| ax[1].plot(x1[sort_idx], dy_dx1[sort_idx], 'b.', markersize=2, label="dy/dx1 (Punktwolke)") | ||
| # Trendlinie der Ableitung | ||
| ax[1].plot(x1[sort_idx], np.poly1d(np.polyfit(x1, dy_dx1, 2))(x1[sort_idx]), 'b-', alpha=0.3) | ||
| ax[1].axhline(0, color='red', linestyle='--', label="Monotonie-Grenze") | ||
| ax[1].set_title('Ableitung nach x1') | ||
| ax[1].legend() | ||
|
|
||
| plt.show() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +0,0 @@ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +0,0 @@ | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example shows ModularModel being used with a single submodel (ClassicalANNModel), but the comment on line 27 says "Example usages" (plural). The example could be more comprehensive by demonstrating additional modular features like ModularLinear, ModularPolynomial, ModularAverage, ModularTrainable, or combining multiple ModularModels, which would better showcase the flexibility of the modular system.