33from __future__ import annotations
44
55import time
6- from typing import Dict , List , Optional
76
87from trainpulse ._types import (
98 Alert ,
@@ -35,10 +34,10 @@ class Monitor:
3534 report = monitor.report()
3635 """
3736
38- def __init__ (self , config : Optional [ MonitorConfig ] = None ) -> None :
37+ def __init__ (self , config : MonitorConfig | None = None ) -> None :
3938 self ._config = config or MonitorConfig ()
40- self ._snapshots : Dict [str , List [MetricSnapshot ]] = {}
41- self ._alerts : List [Alert ] = []
39+ self ._snapshots : dict [str , list [MetricSnapshot ]] = {}
40+ self ._alerts : list [Alert ] = []
4241 self ._step_count = 0
4342
4443 # Detectors
@@ -64,24 +63,24 @@ def __init__(self, config: Optional[MonitorConfig] = None) -> None:
6463 )
6564
6665 # Step timer
67- self ._last_step_time : Optional [ float ] = None
66+ self ._last_step_time : float | None = None
6867
6968 @property
7069 def config (self ) -> MonitorConfig :
7170 return self ._config
7271
7372 @property
74- def alerts (self ) -> List [Alert ]:
73+ def alerts (self ) -> list [Alert ]:
7574 return list (self ._alerts )
7675
7776 @property
78- def snapshots (self ) -> Dict [str , List [MetricSnapshot ]]:
77+ def snapshots (self ) -> dict [str , list [MetricSnapshot ]]:
7978 return dict (self ._snapshots )
8079
81- def log (self , name : str , step : int , value : float , ** metadata : object ) -> List [Alert ]:
80+ def log (self , name : str , step : int , value : float , ** metadata : object ) -> list [Alert ]:
8281 """Log a metric value. Returns any alerts triggered."""
8382 self ._step_count = max (self ._step_count , step + 1 )
84- new_alerts : List [Alert ] = []
83+ new_alerts : list [Alert ] = []
8584
8685 # NaN/Inf check
8786 if self ._nan_detector is not None :
@@ -134,7 +133,7 @@ def step_start(self) -> None:
134133 """Mark the beginning of a training step for timing."""
135134 self ._last_step_time = time .monotonic ()
136135
137- def step_end (self , step : int ) -> List [Alert ]:
136+ def step_end (self , step : int ) -> list [Alert ]:
138137 """Mark the end of a training step and log the duration."""
139138 if self ._last_step_time is None :
140139 return []
@@ -144,7 +143,7 @@ def step_end(self, step: int) -> List[Alert]:
144143
145144 def report (self ) -> TrainingReport :
146145 """Generate a training health report."""
147- metrics_summary : Dict [str , Dict [str , float ]] = {}
146+ metrics_summary : dict [str , dict [str , float ]] = {}
148147 for name , snaps in self ._snapshots .items ():
149148 vals = [s .value for s in snaps ]
150149 finite = [v for v in vals if _is_finite (v )]
@@ -191,7 +190,7 @@ def _infer_metric_type(name: str) -> MetricType:
191190 return MetricType .LOSS
192191 if "grad" in low and ("norm" in low or "magnitude" in low ):
193192 return MetricType .GRADIENT_NORM
194- if low in ("lr" , "learning_rate" ) or "lr" == low :
193+ if low in ("lr" , "learning_rate" ) or low == "lr" :
195194 return MetricType .LEARNING_RATE
196195 if "step_time" in low or "iteration_time" in low :
197196 return MetricType .STEP_TIME
@@ -206,7 +205,7 @@ def _is_finite(v: float) -> bool:
206205 return not (math .isnan (v ) or math .isinf (v ))
207206
208207
209- def _compute_health_score (alerts : List [Alert ], total_steps : int ) -> float :
208+ def _compute_health_score (alerts : list [Alert ], total_steps : int ) -> float :
210209 """Compute a 0-1 health score based on alerts."""
211210 if total_steps == 0 :
212211 return 1.0
0 commit comments