Eu gostaria de utilizar o que há de melhor entre vários Projetos de Experimentos (DOEs) para prever meus dados. Para isso, utilizei um otimizador de hiperparâmetros Optuna e o programei conforme descrito no código. Ele realiza validação cruzada e, em seguida, conduz 10 iterações adicionais por etapa para fornecer um erro quadrático médio (MSE) preciso e otimizar em direção a ele. Como resultado, recebo uma camada com aproximadamente 25 neurônios. No meu modelo real, esta configuração produz bons valores MSE e R_test/R_total. No entanto, ao prever um conjunto de dados diferente, observo um desvio de mais de 50%. Anexei meu modelo e detalhes de otimização de hiperparâmetros (HPO). Eu apreciaria muito uma orientação construtiva. Meus conjuntos de dados consistem em 16 pontos de dados com 5 recursos (X) e um único valor de saída (y).
HPO:
from sklearn.model_selection import train_test_split , cross_val_score
from sklearn.neural_network import MLPRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.preprocessing import MinMaxScaler
import optuna
import numpy as np
import sqlite3
import pandas as pd
# Read data from "Versuchspläne_final.xlsx" for modeling
data_df = pd.read_excel(r"cVersuche_V01_FF.xlsx", sheet_name="Probentabelle", header=1)
# Assuming 'X' columns are ['Temperatur', 'Anteil PP505', 'Drehzahl', 'Anteil Peroxid']
X_noscalar = data_df[['M%1', 'M%2','M%3', 'Drehzahl n/min-1', 'Endzonentemperatur °C']]
y = data_df[['MVR MW']].values.ravel()
# Read scaling parameters from "alle_Werte.xlsx"
scaling_data = pd.read_excel(r"c:.xlsx", sheet_name="Probentabelle", header=1)
scaler_y = MinMaxScaler()
scaler_x = MinMaxScaler()
scaler_y.fit(scaling_data[['MVR MW']]) # Assuming 'MVR' is the target variable in alle_Werte.xlsx
scaler_x.fit(scaling_data[['M%1', 'M%2','M%3', 'Drehzahl n/min-1', 'Endzonentemperatur °C']])
# Apply the previously calculated scaling to 'X' data
X = scaler_x.transform(X_noscalar)
y_scaled = scaler_y.transform(y.reshape(-1, 1)).ravel()
num_splits = 5
shuffled_indices = [train_test_split(range(len(X)), test_size=0.2, shuffle=True) for _ in range(num_splits)]
def objective(trial):
hidden_layer_sizes = tuple([trial.suggest_int(f'n_units_layer_{i}', 1, 100) for i in range(trial.suggest_int('n_layers', 1, 2))])
alpha = trial.suggest_float('alpha', 0.0001, 0.1, log=True)
learning_rate_init = trial.suggest_float('learning_rate_init', 0.001, 0.1, log=True)
learning_rate = trial.suggest_categorical('learning_rate', ['constant', 'invscaling', 'adaptive'])
mean_mse_test = 0
mean_mse_value = 0
num_iterations = 10
for _ in range(num_iterations):
for indices in shuffled_indices:
train_indices, test_indices = indices
X_train, X_test = X[train_indices], X[test_indices]
y_train, y_test = y_scaled[train_indices], y_scaled[test_indices]
model = MLPRegressor(
hidden_layer_sizes=hidden_layer_sizes,
alpha=alpha, max_iter=1000,
learning_rate=learning_rate,
learning_rate_init=learning_rate_init,
solver='lbfgs',
early_stopping=True,
validation_fraction=0.1, # Der Anteil der Daten, der für die Validierung verwendet wird
n_iter_no_change=10, # Anzahl der Iterationen ohne Verbesserung auf der Validierungsmetrik, bevor das Training gestoppt wird
tol=1e-3, # Toleranz für frühzeitiges Stoppen, wenn die Verbesserung kleiner als die Toleranz ist
verbose=True )
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse_test = mean_squared_error(y_test, y_pred)
mean_mse_test += mse_test
mean_mse_test /= num_splits
return mean_mse_test
mean_mse_value /= num_iterations
return mean_mse_value
if __name__ == "__main__":
study = optuna.create_study(study_name="mlp_hyperparam_opt4", storage="sqlite:///mlp_optuna.db", load_if_exists=True)
study.optimize(objective, n_trials=100)
# Beste Hyperparameter und Ergebnisse anzeigen
print("Best trial:")
trial = study.best_trial
print("Value: ", trial.value)
print("Params: ")
for key, value in trial.params.items():
print(f" {key}: {value}")
if __name__ == "__main__":
study = optuna.create_study(study_name="mlp_hyperparam_opt_ff", storage="sqlite:///mlp_optuna.db", load_if_exists=True)
study.optimize(objective, n_trials=300)
# Die besten 10 Trials erhalten
top_trials = study.trials[:10]
# Die besten 10 Trials und ihre Parameter anzeigen
for i, trial in enumerate(top_trials, 1):
print(f"Top {i} trial:")
print("Value:", trial.value)
print("Params:")
for key, value in trial.params.items():
print(f" {key}: {value}")
Modelo:
from sklearn.neural_network import MLPRegressor
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
import numpy as np
import joblib
import pandas as pd
import numpy as np
# Read data from "alle_Werte.xlsx" to calculate scaling parameters
scaling_data = pd.read_excel(r"c:\Versuche_V01_gesamt.xlsx", sheet_name="Probentabelle", header=1)
scaler_y = MinMaxScaler()
scaler_x = MinMaxScaler()
scaler_y.fit(scaling_data[['MVR MW']]) # Assuming 'MVR' is the target variable in alle_Werte.xlsx
scaler_x.fit(scaling_data[['M%1', 'M%2','M%3', 'Drehzahl n/min-1', 'Endzonentemperatur °C']])
# Read data from "Versuchspläne_final.xlsx" for modeling
data_df = pd.read_excel(r"c:Versuche_V01_FF.xlsx", sheet_name="Probentabelle", header=1)
# Assuming 'X' columns are ['Temperatur', 'Anteil PP505', 'Drehzahl', 'Anteil Peroxid']
X_noscalar = data_df[['M%1', 'M%2','M%3', 'Drehzahl n/min-1', 'Endzonentemperatur °C']]
y = data_df[['MVR MW']].values.ravel()
#print(X_noscalar)
# Apply the previously calculated scaling to 'X' data from "Versuchspläne_final.xlsx"
X = scaler_x.transform(X_noscalar)
# Scale the target variable 'y' using the scaler for 'y'
y_scaled = scaler_y.transform(y.reshape(-1, 1)).ravel()
# Aufteilen der Daten in Trainings- und Testsets
X_train, X_test, y_train, y_test = train_test_split(X, y_scaled, test_size=0.2, random_state=12)
# Anzahl der Aufteilungen für die Cross-Validation
num_splits = 5
# Initialisiere Listen, um die Ergebnisse für jedes Split zu speichern
mse_scores = []
r2_test_scores = []
# Führe die Cross-Validation durch
for _ in range(num_splits):
# Aufteilen der Daten in Trainings- und Testsets
X_train, X_test, y_train, y_test = train_test_split(X, y_scaled, test_size=0.2, random_state=1) # Random_state=None für zufällige Aufteilung
# Initialize and train the MLP model
model = MLPRegressor(
hidden_layer_sizes=(3),
#max_iter=2000,
alpha=0.019149003457879503,
learning_rate='constant',
learning_rate_init=0.0451257591571734,
solver='lbfgs',
early_stopping=True,
validation_fraction=0.1, # Der Anteil der Daten, der für die Validierung verwendet wird
n_iter_no_change=10, # Anzahl der Iterationen ohne Verbesserung auf der Validierungsmetrik, bevor das Training gestoppt wird
tol=1e-3, # Toleranz für frühzeitiges Stoppen, wenn die Verbesserung kleiner als die Toleranz ist
verbose=True
)
model.fit(X_train, y_train)
# Predictions für den Testdatensatz
y_pred_test = model.predict(X_test)
y_pred_train = model.predict(X_train)
y_pred = model.predict(X)
# Berechnung des Mean Squared Error (MSE)
#mse = mean_squared_error(y_test, y_pred_test)
#mse_scores.append(mse)
# Berechnung des R2-Werts für den Testdatensatz hier mit train test
r2_test = r2_score(y_test, y_pred_test)
r2_test_scores.append(r2_test)
print('r2_test',r2_test)
r2_train = r2_score(y_train, y_pred_train)
#r2_train_scores.append(r2_train)
print('R2_train: ',r2_train)
r2 = r2_score(y_scaled, y_pred)
#r2_train_scores.append(r2_train)
print('R2: ',r2)
# Ergebnisse ausgeben
mse_scores=mean_squared_error(y_test, y_pred_test)
print("MSE Scores:", mse_scores)
# Berechnung der Durchschnittswerte für MSE und R2
mean_mse = np.mean(mse_scores)
mean_r2 = np.mean(r2_test_scores)
print("Mean MSE across splits:", mean_mse)
print("Mean R2 across splits:", mean_r2)
model_filename = "FF_test_22_1.joblib"
joblib.dump(model, model_filename)
new_df = pd.read_excel(r"c:\Users\janbu\Desktop\Bachelorarbeit\Versuchspläne_L\Versuche_V01_stat.xlsx",
sheet_name="Probentabelle", header=1)
X_new_unscaled = new_df[['M%1', 'M%2', 'M%3', 'Drehzahl n/min-1', 'Endzonentemperatur °C']]
# Skaliere die neuen Daten
X_new = scaler_x.transform(X_new_unscaled)
# Durchführung der Vorhersage für die neuen Daten
predicted_scaled_y = model.predict(X_new)
# Umkehrung der Skalierung, um den eigentlichen y-Wert zu erhalten
predicted_y = scaler_y.inverse_transform(predicted_scaled_y.reshape(-1, 1)).ravel()
print("Predicted y:", predicted_y)
new_df = pd.read_excel(r"c:\Users\janbu\Desktop\Bachelorarbeit\Versuchspläne_L\Versuche_V01_stat.xlsx",
sheet_name="Probentabelle", header=1)
# Extrahiere die tatsächlichen y-Werte der neuen Daten
actual_y_new = new_df[['MVR MW']].values.ravel()
print("Actual y:", actual_y_new)
# Skaliere die neuen Daten
X_new = scaler_x.transform(X_new_unscaled)
# Durchführung der Vorhersage für die neuen Daten
predicted_scaled_y = model.predict(X_new)
# Umkehrung der Skalierung, um den eigentlichen y-Wert zu erhalten
predicted_y = scaler_y.inverse_transform(predicted_scaled_y.reshape(-1, 1)).ravel()
# Berechnung der Abweichung zwischen den vorhergesagten Werten und den tatsächlichen Werten
#deviation = actual_y_new - predicted_y
# Hinzufügen der Abweichung zur DataFrame der neuen Daten
new_df['Predicted MVR MW'] = predicted_y
Limitação do número máximo de camadas e neurônios, loops de iteração adicionais para validação cruzada.
São poucos dados para usar uma rede neural. Você deve usar algo que tenha menos parâmetros, como uma regressão linear.
Existem outros problemas em jogo, como o fato de a validação cruzada não ser implementada corretamente:
Isso permite que um único ponto acabe no conjunto de teste para múltiplas dobras. A validação cruzada deve dividir os dados em k partes e, em seguida, escolher uma dessas k partes para ser o conjunto de teste, sem embaralhar novamente os dados entre essas partes entre cada dobra.
Isso realmente não importaria se você tivesse mais dados, mas do jeito que está, seu conjunto de dados de teste terminará com 3 pontos de dados. Com um conjunto de dados de teste tão pequeno, a sorte é muito importante.
Isso pode ser o resultado de um ajuste excessivo do modelo ou de uma mudança distributiva. É difícil dizer pelos detalhes fornecidos.