3434__all__ = ['MLFlowLogger' ]
3535
3636DEFAULT_MLFLOW_EXPERIMENT_NAME = 'my-mlflow-experiment'
37+ LOG_DUPLICATED_METRIC_VALUE_PER_N_STEPS = 100
38+ LOG_DUPLICATED_METRIC_VALUE_PER_N_MILLIS = 600000
3739
3840
3941class MlflowMonitorProcess (multiprocessing .Process ):
@@ -118,6 +120,11 @@ class MLFlowLogger(LoggerDestination):
118120 logging_buffer_seconds (int, optional): The amount of time, in seconds, that MLflow
119121 waits before sending logs to the MLflow tracking server. Metrics/params/tags logged
120122 within this buffer time will be grouped in batches before being sent to the backend.
123+ log_duplicated_metric_every_n_steps (int, optional): The number of steps to wait before
124+ logging the duplicated metric value. Duplicated metric value means the new step has the
125+ same value as the previous step. (default: ``100``)
126+ log_duplicated_metric_every_n_millis (int, optional): The number of milliseconds to wait
127+ before logging the duplicated metric value. (default: ``600000``)
121128 """
122129
123130 def __init__ (
@@ -138,6 +145,8 @@ def __init__(
138145 run_group : Optional [str ] = None ,
139146 resume : bool = False ,
140147 logging_buffer_seconds : Optional [int ] = 10 ,
148+ log_duplicated_metric_every_n_steps : int = 100 ,
149+ log_duplicated_metric_every_n_millis : int = 600000 ,
141150 ) -> None :
142151 try :
143152 import mlflow
@@ -179,6 +188,10 @@ def __init__(
179188 mlflow .set_system_metrics_samples_before_logging (6 )
180189 mlflow .set_system_metrics_sampling_interval (5 )
181190
191+ self .log_duplicated_metric_every_n_steps = log_duplicated_metric_every_n_steps
192+ self .log_duplicated_metric_every_n_millis = log_duplicated_metric_every_n_millis
193+ self ._metrics_cache = {}
194+
182195 self ._rank_zero_only = rank_zero_only
183196 self ._last_flush_time = time .time ()
184197 self ._flush_interval = flush_interval
@@ -385,18 +398,37 @@ def rename(self, key: str):
385398 def log_metrics (self , metrics : dict [str , Any ], step : Optional [int ] = None ) -> None :
386399 from mlflow import log_metrics
387400
388- if self ._enabled :
389- # Convert all metrics to floats to placate mlflow.
390- metrics = {
391- self .rename (k ): float (v )
392- for k , v in metrics .items ()
393- if not any (fnmatch .fnmatch (k , pattern ) for pattern in self .ignore_metrics )
394- }
395- log_metrics (
396- metrics = metrics ,
397- step = step ,
398- synchronous = self .synchronous ,
399- )
401+ if not self ._enabled :
402+ return
403+
404+ metrics_to_log = {}
405+ step = step or 0
406+ current_time_millis = int (time .time () * 1000 )
407+ for k , v in metrics .items ():
408+ if any (fnmatch .fnmatch (k , pattern ) for pattern in self .ignore_metrics ):
409+ continue
410+ if k in self ._metrics_cache :
411+ value , last_step , last_time = self ._metrics_cache [k ]
412+ if value == v and step < last_step + self .log_duplicated_metric_every_n_steps and current_time_millis < last_time + self .log_duplicated_metric_every_n_millis :
413+ # Skip logging the metric if it has the same value as the last step and it's
414+ # within the step and time window.
415+ continue
416+ else :
417+ # Log the metric if it has a different value or it's outside the step and time
418+ # window, and update the metrics cache.
419+ self ._metrics_cache [k ] = (v , step , current_time_millis )
420+ metrics_to_log [self .rename (k )] = float (v )
421+ else :
422+ # Log the metric if it's the first time it's being logged, and update the metrics
423+ # cache.
424+ self ._metrics_cache [k ] = (v , step , current_time_millis )
425+ metrics_to_log [self .rename (k )] = float (v )
426+
427+ log_metrics (
428+ metrics = metrics_to_log ,
429+ step = step ,
430+ synchronous = self .synchronous ,
431+ )
400432
401433 def log_hyperparameters (self , hyperparameters : dict [str , Any ]):
402434 from mlflow import log_params
0 commit comments