Driftmanagement und Bias-Korrektur im SolarForecast KI-Prognosesystem
Driftmanagement und Bias-Korrektur im SolarForecast KI-Prognosesystem
Diese Seite erläutert, wie SolarForecast die Qualität der neuronalen Verbrauchs- und Ertragsprognosen (AI::FANN) im laufenden Betrieb überwacht und automatisch nachjustiert. Zwei eng verzahnte Mechanismen sind dafür verantwortlich:
- Die Bias-Korrektur (
_aiFannApplyBiasCorrection), die bei jeder einzelnen Prognoseabfrage (aiFannConInfer) angewendet wird und den rohen Netzwerk-Output in Echtzeit korrigiert. - Das Driftmanagement (
aiFannDetectDrift), das einmal pro volle Stunde die Prognosequalität der jüngsten Vergangenheit analysiert, die Korrekturparameter nachführt (Rekalibrierung) und bei Bedarf ein Retraining empfiehlt.
Beide Mechanismen arbeiten zusammen, ersetzen aber nicht das eigentliche Training – sie kompensieren die unvermeidliche Alterung eines einmal trainierten Modells zwischen zwei Trainingsläufen.
Warum überhaupt Drift- und Bias-Management?
Ein neuronales Netz lernt beim Training einen statischen Zusammenhang zwischen Eingangsgrößen (PV-Ertrag, Temperatur, Uhrzeit, Anwesenheit, Lag-Features usw.) und dem Zielwert (Verbrauch). Dieser gelernte Zusammenhang ist jedoch nur eine Momentaufnahme:
- Saisonale Verschiebungen (Heizverhalten im Winter, Klimatisierung im Sommer)
- Verhaltensänderungen der Bewohner (neue Geräte, geänderte Homeoffice-Tage, Urlaub)
- Strukturelle Änderungen am Haushalt (neuer Verbraucher, BEV-Anschaffung, WP-Umbau)
- Sensor-/API-Störungen (fehlerhafte Wetterdaten, Zählerausfälle)
führen dazu, dass die Vorhersagequalität mit der Zeit sinkt – das reale Verhalten "driftet" vom gelernten Modellzustand weg. In der ML-Literatur unterscheidet man dabei:
- Concept Drift: Der tatsächliche Zusammenhang zwischen Features und Zielgröße ändert sich (z. B. weil ein E-Auto angeschafft wurde und nun nachts geladen wird).
- Data Drift / Covariate Shift: Die Verteilung der Eingangsgrößen ändert sich, der zugrunde liegende Zusammenhang bleibt aber gleich.
Ein vollständiges Neu-Training bei jeder kleinen Abweichung ist weder praktikabel (Rechenzeit, Datenmenge) noch für den Anwender komfortabel. SolarForecast verfolgt daher einen zweistufigen Ansatz:
- Kurzfristig: Eine leichte additive/multiplikative Korrektur pro Prognosestunde (Bias-Korrektur), die auf zuletzt gemessenen Fehlerkennzahlen basiert.
- Mittelfristig: Eine stündliche, statistisch abgesicherte Nachführung der Korrekturreferenzwerte (Drift-Rekalibrierung) sowie eine Retraining-Empfehlung, wenn die Drift strukturell und nicht mehr kompensierbar ist.
Grundbegriffe
Bias und Slope
Für ein Modell, das reale Werte <math>y</math> aus Vorhersagen <math>\hat{y}</math> möglichst gut trifft, sind zwei Fehlerarten zu unterscheiden:
- Bias (additiver Fehler): systematischer Versatz, z. B. das Modell sagt im Mittel 430 Wh zu wenig voraus. Berechnet als
bias = mean(y - ŷ). - Slope (multiplikativer Fehler): Steigung der linearen Regression
ŷ ~ y. Ein Slope < 1 bedeutet, dass das Modell hohe Werte tendenziell unterschätzt und niedrige Werte tendenziell überschätzt (Regression-to-the-mean-Effekt bei stochastischen, schwer vorhersagbaren Haushalten).
Diese beiden Größen werden im Code an mehreren Stellen getrennt geführt:
- Statische Werte aus dem Training:
ModelBias,ModelSlope,Mae,RmseRel(einmalig beim Training bestimmt, siehe Trainingsmodul). - Dynamische, laufend nachgeführte Referenzwerte:
DriftRefBias,DriftRefSlope(werden bei Rekalibrierung überschrieben und sind dann maßgeblich –_aiFannApplyBiasCorrectionbevorzugt sie explizit, sofern definiert). - Aktuelle Live-Abweichung zur Referenz:
DriftBias,DriftSlope(wie weit ist die aktuelle Stunde von der zuletzt kalibrierten Referenz entfernt).
Der strukturelle Zusammenhang Bias ≈ mean(y) × (1 − Slope) erklärt, warum bei stochastischen Haushalten (schwer vorhersagbares Verbrauchsverhalten) auch ein "gutes" Modell einen strukturellen Bias von mehreren hundert Wh aufweisen kann, ohne dass ein Modellfehler vorliegt.
Baseline vs. Peak
Ein zentrales Entwurfsprinzip beider Mechanismen ist der Peak-Schutz: Additive und multiplikative Korrekturen werden nur auf die Grundlast (Baseline) angewendet, niemals auf Verbrauchsspitzen. Grund: Eine Korrektur, die im Mittel passt, würde bei einem punktuellen Peak (z. B. Backofen, Wallbox-Ladevorgang) den Vorhersagefehler eher vergrößern als verkleinern. Die Baseline-Erkennung erfolgt über das 30 %-Quantil des jeweiligen Prognosetyps (CircularVal ($name, '99', $fanntyp.'_quantile30', 0)): Liegt der (bereits driftkorrigierte) Vorhersagewert nicht mehr als 20 % über diesem Quantil, gilt er als Grundlast.
Ablauf einer Prognose (aiFannConInfer)

aiFannConInfer wird für jede der MAXNEXTHOURS zukünftigen Stunden aufgerufen und durchläuft je Stunde folgende Kette:
- Feature-Vektor aus
NextHours/Historyaufbauen (Lag-Features, zyklische Kodierung, BEV-/WP-Aggregate usw. – siehe separate Wiki-Seite zur Feature-Registry). - Netzwerk-Inferenz:
_aiFannPredictlässt das FANN-Modell laufen und denormalisiert den Output anhand der beim Training gespeichertenMinVal/MaxVal. - Bias-/Drift-Korrektur:
_aiFannApplyBiasCorrectionwandelt den rohen Modell-Output$denorm_valin den korrigierten Wert$predictionum (Details siehe unten). - Horizont-Blending: Für weiter in der Zukunft liegende Stunden wird die reine Modellprognose zunehmend mit einem historischen Referenzwert gemischt (
_aiFannGetHistoricalReference, Mittelwert derselben Stunde der letzten 7 Tage). Der Blend-Anteilblend_alphasteigt mit der Anzahl der Stunden in die Zukunft auf maximal 80 %, weil die Modellprognose mit wachsendem Horizont zunehmend unsicherer wird und ein saisonaler Mittelwert stabiler ist. - Hybridisierung mit der Legacy-Prognose:
confc_final = alpha × prediction + (1 − alpha) × legacyconfc, gesteuert über das ReadingaiConAlpha. So kann der Anwender das Vertrauen in das KI-Modell gegenüber der klassischen Prognose stufenlos einstellen. - Speicherung der Zwischenwerte (
conaifc,confc,conbiascorr) in Circular- und History-Speicher zur späteren Auswertung durch das Driftmanagement.
Die Bias-Korrektur im Detail (_aiFannApplyBiasCorrection)
Diese Funktion wird pro Prognosestunde aufgerufen und führt in dieser Reihenfolge vier Korrekturschritte aus: Drift-Level-Korrektur → Drift-Bias-Korrektur → statische Trainingskalibrierung → additive Bias-Zonenkorrektur.
Schritt 1: Drift-Slope-Korrektur (Level-Skalierung)
Der laufend aktualisierte DriftSlope (Verhältnis der aktuellen Live-Regressionssteigung zur Referenzsteigung, siehe unten) wird zunächst auf den Bereich [0.80, 1.10] geklemmt ($ds_min/$ds_max). Anschließend wird eine adaptive Gewichtung berechnet, damit kleine, verrauschte Abweichungen nicht voll durchschlagen:
slope_dev = |1.0 − DriftSlope| rmse_dev = ln(1 + max(0, DriftRmseRelRatio − 1)) mae_scale = min(1.0, Mae / 200) drift_weight = min(1.0, 0.4·slope_dev + 0.1·rmse_dev + 0.1·mae_scale) ds_adapted = 1.0 + (ds − 1.0) · drift_weight
Der so gedämpfte Faktor ds_adapted wird danach nochmals zonenabhängig skaliert – je nachdem, wie stark und wie zuverlässig der aktuelle Drift ist:
| Drift-Zone | Bedingung | Wirkung auf ds_adapted |
|---|---|---|
| 1 (stabil) | DriftSlope ∈ [0.85, 1.15] und DriftRmseRelRatio < 1.5 |
nur 10 % der Abweichung wirksam |
| 2 (leichte Drift) | DriftSlope ∈ [0.70, 1.30] und DriftRmseRelRatio < 2.5 |
40 % der Abweichung wirksam |
| 3 (starke Drift) | sonst | 70 % der Abweichung wirksam |
Nach der Zonenskalierung erfolgt ein finales Clamping auf [0.70, 1.10]. Ist die Drift-Korrektur aktuell deaktiviert (siehe nächster Absatz), wird ds_adapted = 1.0 gesetzt und keine Korrektur angewendet. Der rohe Vorhersagewert wird dann multiplikativ skaliert: res = val_predict × ds_adapted.
Deaktivierungsbedingungen ($drift_enabled = 0):
- Modellalter
ModelAgeHours < AIMODELMINAGE– ein frisches Modell hat noch keine belastbare Live-Fehlerstatistik. - Nachtstunden
hod < 7– nachts ist die Grundlast so niedrig und variabel (Standby-Verbräuche), dass eine Driftkorrektur hier eher schadet als nützt.
Schritt 2: Drift-Bias (additiver Versatz)
Der aktuell gemessene DriftBias (Differenz zwischen Live-Bias und Referenz-Bias, siehe Driftanalyse) wird auf maximal ±1.0 × Mae geklemmt und – nur wenn die Vorhersage als Grundlast (is_baseline) erkannt wurde – additiv aufaddiert: res += clamped_drift_bias. Ist die Driftkorrektur deaktiviert, wird auch dieser Anteil auf 0 gesetzt.
Schritt 3: Statische Trainingskalibrierung (OLS, Peak-geschützt)
Falls beim letzten Training eine strukturelle Kalibrierung ermittelt wurde (CalSlope/CalBias im Modell-Datensatz, per Ordinary-Least-Squares-Regression bestimmt), wird sie – wiederum ausschließlich auf Grundlast-Werte – angewendet:
cal_val = CalSlope · res + CalBias osl_delta = cal_val − res max_osl_delta = 0.15 · Mae # Korrektur auf max. 15 % des MAE begrenzt res = clamp(res + osl_delta, 0, MaxVal)
Der Grund für die enge Deckelung: CalSlope korrigiert einen strukturellen Steigungsfehler aus dem Training pauschal für den gesamten Wertebereich. Ohne Deckelung würde diese Korrektur bei Peaks (die per Definition außerhalb der Baseline-Prüfung liegen dürften, aber am Übergang) überkorrigieren. Kommt diese Kalibrierung zur Anwendung, wird die nachfolgende additive Bias-Zonenkorrektur (Schritt 4) übersprungen (bias_zone = 3, Kennzeichnung +OSL im Reading), um eine Doppelkorrektur zu vermeiden.
Schritt 4: Additive Bias-Zonenkorrektur
Nur falls Grundlast und keine OLS-Kalibrierung gegriffen hat, wird der geklemmte statische Bias (clamped_bias, max. 50 % des Mae) je nach Modellgüte anteilig aufaddiert. Die Modellgüte wird über drei Kennzahlen bewertet: ModelSlope, bias_ratio = |bias| / max(Mae, 0.1) und RmseRel.
| Zone | Farbe | Bedingung | Korrekturanteil |
|---|---|---|---|
| 1 | grün | Slope ∈ [0.9, 1.1], bias_ratio ≤ 1.0, RmseRel ≤ 25 % |
70 % des Bias |
| 2 | gelb | Slope ∈ [0.7, 0.9), bias_ratio ≤ 2.0, RmseRel ≤ 40 % |
50 % des Bias |
| 2b | (profilabhängig) | Slope ≥ z2_slope_min, bias_ratio ≤ z2_bias_max, RmseRel ≤ z2_rmse_max (Schwellen aus %profileweights{$profile}) |
25 % des Bias |
| 3 | rot | keine der obigen Bedingungen erfüllt | keine Korrektur |
Die Zone-2b-Schwellen sind bewusst pro Profil konfigurierbar (%profileweights), da stochastische Haushalte (viele Einzelverbraucher, unregelmäßiges Verhalten) strukturell schlechtere Slope-/RMSE-Werte aufweisen als reguläre Haushalte, ohne dass dies ein Qualitätsmangel des Modells ist (siehe Bias-≈-mean×(1−Slope)-Zusammenhang oben). Ohne die Zone-2b-Ausnahme würden solche Profile dauerhaft in der roten Zone landen und nie eine Korrektur erhalten.
Die Funktion liefert am Ende ($res, $corr_val, $bias_zone, $drift_zone) zurück, wobei $corr_val = $res − $val_predict die insgesamt angewendete Korrektur in Wh ist. Diese Werte werden pro Stunde als conbiascorr, conaifc und confc historisiert und stehen damit der nachfolgenden Driftanalyse als Trainings-/Prüfdaten zur Verfügung.
Die stündliche Driftanalyse (aiFannDetectDrift)
Diese Funktion wird einmal pro volle Stunde und pro Prognosetyp (fanntyp, z. B. con) aufgerufen und darf nicht häufiger laufen, da sie zustandsbehaftete EMA-Glättungen (siehe unten) fortschreibt, die bei Mehrfachaufruf verfälscht würden.

1. Adaptive Fenstergröße (_aiFannSelectWindow)
Bevor irgendwelche Kennzahlen gelöscht werden, wird die Fenstergröße für die nachfolgende Analyse bestimmt – sie muss vor dem Löschen ermittelt werden, weil sie selbst auf zuvor gespeicherten Kennzahlen (ModelAgeHours, DriftScore, DriftSemRatio) aufbaut. Grundprinzip: Peaks bzw. seltene Ausreißer sollen das Fenster vergrößern (verwässern), während dauerhafte, breit gestreute Drift das Fenster verkleinern soll (schnellere Reaktion auf neue Verhältnisse):
| Regel | Bedingung | Fenstergröße |
|---|---|---|
| Peak, breit gestreut | DriftScore > 2.5 und SemRatio > 0.7 | 120 h |
| Seltene extreme Peaks | DriftScore > 2.0 und SemRatio < 0.4 | 120 h |
| Dauerhafte Drift | DriftScore > 2.0, SemRatio ≥ 0.4, Alter > 72 h | 48 h |
| Schleichende Drift | 1.5 < DriftScore ≤ 2.0, SemRatio < 0.4, Alter > 48 h | 72 h |
| Stabiles Modell | DriftScore < 1.2, Alter > 72 h | 144 h |
| (keine Regel greift / fehlende Werte) | – | 96 h (Default) |
2. Modellalter und Fresh-Model-Reset
Der Zeitstempel des letzten Trainingsabschlusses wird aus CircularVal(..., 99, $fanntyp.'NNTrainLastFinishTs') gelesen; die Differenz zum jüngsten verfügbaren Rohdatensatz ergibt ModelAgeHours. Ist das Modell jünger als AIMODELMINAGE Stunden, greift ein harter Reset: Die Drift-Historie wird geleert, DriftBias = 0, DriftSlope = 1 gesetzt, und die Referenzwerte DriftRefBias/DriftRefSlope werden auf den Modellzustand aus dem Training gesetzt (ModelBias/ModelSlope) – außer es ist bereits eine statische Kalibrierung (CalSlope/CalBias) aktiv; in diesem Fall werden die Referenzen auf 0/1 gesetzt, um die in Schritt 3 der Bias-Korrektur bereits erfolgende OLS-Korrektur nicht doppelt zu berücksichtigen. Die Funktion kehrt danach sofort mit dem Flag fresh_model zurück – es findet noch keine Drift-Bewertung statt.
3. Leckage-Schutz: nur Daten des aktuellen Modells
Aus der Rohhistorie ($data{$name}{aidectree}{airaw}) werden ausschließlich Datensätze berücksichtigt, deren Zeitstempel nach dem Trainingsabschluss liegen (post_train_idx). Damit wird verhindert, dass die Drift-Bewertung durch Prognosen des vorherigen Modells verfälscht wird. Sind weniger als AIMODELMINAGE solcher Datensätze vorhanden, bricht die Analyse mit insufficient_data ab. Aus den verbleibenden Datensätzen wird das jüngste Fenster der Größe $window (tail_idx) für die eigentliche Analyse verwendet.
4. Stündliche Fehlerberechnung und Glättung
Für jede Stunde im Analysefenster werden realer Wert ($fanntyp, z. B. con) und Prognosewert (${fanntyp}aifc) gelesen, auf Gültigkeit geprüft (definiert, numerisch, ≥ 0) und daraus:
slope_list: Verhältnisp/aje Stunde (für spätere Varianzberechnung)bias_hour = a − p, geklemmt auf±3 × DriftRefMae(Ausreißerschutz), anschließend exponentiell geglättet (EMA,alpha = 0.3):bias_smooth = 0.3·bias_hour + 0.7·bias_smooth_prev
gebildet. Für die Bias-Varianz wird nur das letzte 24-h-Fenster verwendet (bias_last24), damit einzelne Peaks über ein 96-h-Fenster die Varianzschätzung nicht dominieren.
5. Fehlermetriken (_aiFannErrorMetrics)
Auf Basis von @targets/@preds im Analysefenster werden auf Originalskala (Wh) berechnet:
- MAE (Mean Absolute Error): mittlerer absoluter Fehler
- RMSE und RMSErel (RMSE relativ zum Median der Zielwerte, robuster als Mittelwert-Bezug bei schiefen Verteilungen)
- MedAE (Median Absolute Error, ausreißerrobust)
- MAPE / MdAPE (mittlerer/medianer prozentualer Fehler)
- Bias-Kennzahlen (signed):
bias_mean,bias_median,bias_abs_mean,bias_abs_median
Daraus: drift_score = mae_live / DriftRefMae – das zentrale Verhältnis "wie viel schlechter ist die aktuelle Fehlerlage gegenüber dem Referenzzustand".
6. Regression Live (_aiFannSlopeBias, OLS)
Mittels gewöhnlicher kleinster Quadrate (Ordinary Least Squares) wird die lineare Regression Prognose ~ Realwert über das Analysefenster berechnet:
slope = (n·Σxy − Σx·Σy) / (n·Σx² − (Σx)²) bias = (Σy − slope·Σx) / n
mit x = Realwerte, y = Prognosewerte. Sonderfälle werden explizit behandelt: zu wenige Datenpunkte (n < 2), unterschiedliche Array-Längen (Truncation) sowie Null-Varianz in den Zielwerten (alle x identisch – dann ist die Steigung nicht bestimmbar, slope = 0, bias = ȳ als Fallback). Der Nenner wird gegen einen skalierten Epsilon-Wert statt gegen exakt 0 geprüft, um numerische Instabilität bei sehr kleinen, aber nicht exakt verschwindenden Nennern zu vermeiden.
Der resultierende bias_live wird nochmals per EMA mit dem vorherigen Wert geglättet (0.7 × neu + 0.3 × alt), bevor er als DriftBiasLive gespeichert wird – zusätzlich zur stundenweisen EMA aus Schritt 4. Diese doppelte Glättung dient dazu, sowohl kurzfristige (stundenweise) als auch mittelfristige (fensterweise) Sprünge zu dämpfen.
7. Drift-Kennzahlen relativ zur Referenz
slope_drift = slope_live / DriftRefSlope bias_drift = bias_live − DriftRefBias rmse_rel_ratio = rmse_rel_live / DriftRefRmse bias_drift_norm = |bias_drift| / DriftRefMae slope_rel_drift = |slope_drift − 1|
8. Semantik- und Peak-Anteil
Zusätzlich zu den globalen Fehlermaßen wird geprüft, wie verbreitet der Fehler im Fenster ist:
sem_ratio: Anteil der Stunden, bei denen der absolute Fehler die Schwelle0.5 × Mae_modelüberschreitet. Hoch (>0.7) deutet auf flächendeckende, dauerhafte Drift hin; niedrig (<0.4) auf vereinzelte Ausreißer.peak_ratio: Anteil der Stunden mit Realwert oberhalbMedian + 2×Mae_model.
Diese beiden Kennzahlen fließen sowohl in die Fenstergrößen-Heuristik (siehe oben) als auch in die Sicherheitslogik (siehe unten) ein.
9. Der Drift-Index und die Ampel-Flags
Aus den bisherigen Größen wird ein gewichteter Gesamtindex gebildet:
slope_penalty = slope_rel_drift < 0.3
? min(2.0, slope_rel_drift) # linear bei kleiner Abweichung
: min(2.0, slope_rel_drift + slope_rel_drift²) # quadratisch bei großer Abweichung
slope_boost = slope_rel_drift > 0.4 ? 0.25 : 0.0 # zusätzlicher Booster bei starkem Dynamikverlust
drift_index = 0.40 · min(3.0, drift_score)
+ 0.30 · min(3.0, rmse_rel_ratio)
+ 0.20 · min(2.0, slope_penalty)
+ 0.10 · min(2.0, bias_drift_norm)
+ slope_boost
Die Gewichtung spiegelt die praktische Relevanz wider: der reine Fehleranstieg (drift_score) und die RMSE-Relation dominieren mit zusammen 70 %, echte Dynamikverluste (Slope) mit 20 % plus Booster, reine additive Verschiebung (Bias) nur mit 10 %, da Bias durch die separate additive Korrektur ohnehin laufend adressiert wird.
| Drift-Index | Flag |
|---|---|
| > 3.0 | severe
|
| > 2.0 | moderate
|
| > 1.5 | mild
|
| > 1.1 | low
|
| > 1.02 | very_low
|
| ≤ 1.02 | stable
|
10. Rekalibrierung
Das Flag der jeweiligen Stunde wird in DriftZoneHistory protokolliert (auf die letzten 20 Einträge begrenzt). Ein Zähler DriftZone3Hours erfasst, wie viele Stunden in Folge der Drift-Index über der "mild"-Schwelle (1.5) lag; er wird zurückgesetzt, sobald der Index wieder darunter fällt.
Bevor eine Rekalibrierung stattfinden darf, prüft _aiFannDriftSafetyBlocked eine Reihe von Plausibilitätsbedingungen (siehe nächster Abschnitt). Ist keine geblockt, und hat DriftZone3Hours die Schwelle erreicht (4 Stunden bei severe, sonst DRIFTHZN3TH = 8 Stunden), wird rekalibriert:
bias_drift_effective = clamp(0.5·bias_drift + 0.5·(mae_live − DriftRefMae), ±2·DriftRefMae) new_bias = DriftRefBias + 0.4 · bias_drift_effective # sanfte 40%-Anpassung slope_error = slope_live − DriftRefSlope slope_drift_effective = 0.6·slope_error + 0.4·(rmse_rel_ratio − 1.0)·0.1 new_slope = clamp(DriftRefSlope + slope_drift_effective, 0.85, 1.15)
DriftRefBias und DriftRefSlope werden mit den neuen Werten überschrieben, DriftBias/DriftSlope relativ dazu neu berechnet (sollten danach nahe 0 bzw. 1 liegen), DriftZone3Hours auf 0 zurückgesetzt und DriftRefMae/DriftRefRmse auf die aktuellen Live-Werte gesetzt – das neue Referenzniveau für die nächste Analyseperiode. Das Flag wird auf recalibrated gesetzt.
Wichtig: Die Rekalibrierung passiert bewusst nur in kleinen Schritten (40 % bzw. 60/40-Mischung), nicht als vollständiger Sprung auf die Live-Werte, um Überreaktionen auf kurzfristiges Rauschen zu vermeiden.
11. Retrain-Empfehlung (_aiFannRetrainRecommended)
Wurde in diesem Durchlauf rekalibriert, wird die Empfehlung auf none (Grund just_recalibrated) gesetzt, da die Rekalibrierung das Problem bereits adressiert hat. Andernfalls wird anhand von vier unabhängigen Signalen aus den letzten 12 protokollierten Flags (DriftZoneHistory) ein Score gebildet:
| Signal | Bedingung |
|---|---|
structural_block |
Blockgrund ist slope_critical, negative_slope_drift oder model_bad_but_stable und DriftIndex > 1.8
|
persistent_drift |
DriftIndex > 2.0 und mindestens 8 der letzten 12 Flags moderate/severe
|
severe_drift |
DriftIndex > 2.5 und DriftScore > 2.5 |
context_block |
Blockgrund ist slope_implausible/rmse_anomaly/unstable_slope/unstable_bias und persistent (≥10 von 12) und DriftIndex > 2.0
|
Bewusst nicht gewertet werden reine Datenfehler-Blocks wie bias_implausible oder low_load_phase – diese deuten auf Sensor-/Datenprobleme statt auf Modellprobleme hin und sollen kein Retraining auslösen. Score ≥ 2 → urgent, Score = 1 → advised, sonst none.
Sicherheitslogik gegen Fehlrekalibrierung (_aiFannDriftSafetyBlocked)
Da eine fehlerhafte Rekalibrierung das Modell dauerhaft "verbiegen" würde, prüft diese Funktion vor jeder Rekalibrierung eine Kette von Plausibilitätskriterien und liefert bei Verdacht einen sprechenden Blockgrund statt 0:
| Blockgrund | Erkennt … |
|---|---|
no_data |
zu wenige Datenpunkte im Fenster (≤ 6) |
negative_slope_drift |
invertierte Dynamik (Slope-Drift oder Live-Slope negativ) – klares Datenproblem |
slope_critical |
slope_live| < 0.25) bei gleichzeitig weit verbreitetem Fehler (sem_ratio > 0.75)
|
low_load_phase |
dynamischer Nacht-Detektor: mindestens 5 der letzten 6 Stunden liegen nahe am 30 %-Quantil, kaum Peaks, kaum Semantik-Fehler → typische Grundlast-/Nachtphase, keine Rekalibrierung nötig |
slope_implausible |
extreme Slope-Werte kombiniert mit hoher Varianz oder breitem Fehleranteil, aber wenig Peaks → deutet auf API-/Sensorfehler statt echter Drift |
rmse_anomaly |
RMSE-Verhältnis überschreitet eine dynamische Grenze, die sich aus Peak-Anteil, Semantik-Anteil und Slope-Varianz ableitet (Grundlast → niedrigere Grenze, viele Peaks/Varianz → höhere Toleranz) |
bias_implausible |
Live-Bias überschreitet eine aus Quantil30/Quantil90/Medianlast abgeleitete Plausibilitätsgrenze bei gleichzeitig wenig Peaks → typisches Zeichen für Sensor-/API-Ausfälle |
model_bad_but_stable |
Modell ist zwar schlecht, aber nicht driftend (moderate, aber nicht wachsende Abweichungen) → Rekalibrierung würde nichts verbessern, eher Retraining nötig |
unstable_slope |
Slope-Varianz über dem dynamischen, lastabhängigen Grenzwert → zu instabil für eine belastbare Rekalibrierung |
unstable_bias |
hohes RMSE-Verhältnis und hohe normierte Bias-Varianz gleichzeitig |
Erst wenn keine dieser Bedingungen zutrifft, wird die Rekalibrierung freigegeben.
Zusammenspiel: Beispielablauf
- Jede Prognosestunde (
aiFannConInfer): Rohprognose →_aiFannApplyBiasCorrectionwendet die zuletzt bekannten Referenzwerte (DriftRefBias/DriftRefSlopebzw. Trainingswerte, falls noch keine Rekalibrierung stattfand) an → korrigierter Wert wird gespeichert und historisiert. - Einmal pro volle Stunde (
aiFannDetectDrift): Die zuletzt historisierten Prognose-/Realwertpaare werden ausgewertet, ein Drift-Index gebildet, ein Ampel-Flag gesetzt. - Bei anhaltender, plausibler Drift über mehrere Stunden (Zone3Hours-Schwelle erreicht, keine Sicherheitsblockade):
DriftRefBias/DriftRefSlopewerden sanft nachgeführt – ab der nächsten Prognosestunde wirkt die neue Referenz in_aiFannApplyBiasCorrection. - Bei struktureller, nicht kompensierbarer Drift (persistente moderate/severe-Flags über 12 Stunden, oder strukturelle Blockgründe): Die Retrain-Empfehlung wird auf
advisedbzw.urgentgesetzt – dies ist ein Hinweis an den Anwender, ein neues Training anzustoßen, da die laufende Korrektur an ihre Grenzen stößt.
Damit ergibt sich eine Kaskade dreier Zeitskalen: Prognose (jede Stunde neu berechnet, sofort korrigiert) → Drift-Rekalibrierung (Stunden bis Tage, sanfte Nachführung) → Retraining (Wochen bis Monate, vollständige Neuanpassung).
Wichtigste Kennziffern im Überblick
| Reading | Bedeutung |
|---|---|
ModelBias / ModelSlope |
statische Werte aus dem letzten Training |
DriftRefBias / DriftRefSlope |
aktuell gültige, ggf. rekalibrierte Referenzwerte (haben Vorrang vor den Modellwerten) |
DriftBias / DriftSlope |
aktuelle Abweichung der Live-Fehlerlage von der Referenz |
DriftBiasLive / DriftSlopeLive |
geglättete Live-Regressionskennzahlen des Analysefensters |
DriftScore |
Verhältnis Live-MAE zu Referenz-MAE |
DriftIndex |
gewichteter Gesamt-Driftindikator (Basis der Ampel-Flags) |
DriftRmseRelRatio |
Verhältnis Live-RMSErel zu Referenz-RMSErel |
DriftSemRatio |
Anteil der Stunden mit signifikantem Fehler (Verbreitungsgrad der Drift) |
DriftFlag |
aktuelle Ampel/Status (stable … severe, recalibrated, fresh_model, oder recalibration blocked: …)
|
DriftZoneHistory |
Protokoll der letzten 20 Flags |
DriftZone3Hours |
Anzahl aufeinanderfolgender Stunden über der "mild"-Schwelle |
DriftLastRecalTime |
Zeitpunkt der letzten Rekalibrierung |
ModelAgeHours |
Alter des aktuellen Modells seit Trainingsabschluss |
RetrainRecommendation / DriftRetrainReason |
Empfehlung none/advised/urgent mit Begründung
|
conbiascorr |
pro Stunde tatsächlich angewendete Bias-/Drift-Korrektur in Wh (corr_val aus _aiFannApplyBiasCorrection)
|
Praxishinweise für Anwender
DriftFlag = stable/very_low/low: Kein Handlungsbedarf, das System korrigiert im Rahmen der normalen Bias-Korrektur.DriftFlag = mild/moderateüber längere Zeit: Das System rekalibriert automatisch, sobald die Sicherheitsprüfung dies zulässt – meist kein Eingreifen nötig, kann aber beobachtet werden.DriftFlag = recalibration blocked: …über viele Stunden: Der Blockgrund gibt einen konkreten Hinweis (z. B.low_load_phaseist unkritisch,slope_implausible/bias_implausibledeuten dagegen auf Sensor- oder API-Probleme hin, die geprüft werden sollten).RetrainRecommendation = advisedoderurgent: Ein neues Training des betreffenden Modells (fanntyp) sollte zeitnah angestoßen werden, da die laufende Korrektur die strukturelle Abweichung nicht mehr ausgleichen kann.DriftFlag = fresh_model: Normal direkt nach einem Training – die Driftanalyse startet erst nachAIMODELMINAGEStunden mit belastbaren Werten.