ray.rllib.utils.metrics.metrics_logger.MetricsLogger.log_value#
- MetricsLogger.log_value(key: str | Tuple[str, ...], value: Any, *, reduce: str | None = 'mean', window: int | float | None = None, ema_coeff: float | None = None, percentiles: List[int] | bool = False, clear_on_reduce: bool = False, with_throughput: bool = False, throughput_ema_coeff: float | None = None, reduce_per_index_on_aggregate: bool = False) None[source]#
Logs a new value under a (possibly nested) key to the logger.
from ray.rllib.utils.metrics.metrics_logger import MetricsLogger from ray.rllib.utils.test_utils import check logger = MetricsLogger(root=True) # Log n simple float values under the "loss" key. By default, all logged # values under that key are averaged, once `reduce()` is called. logger.log_value("loss", 0.01, window=10) logger.log_value("loss", 0.02, window=10) logger.log_value("loss", 0.03, window=10) # Peek at the current (reduced) value. # Note that in the underlying structure, the internal values list still # contains all logged values (0.01, 0.02, and 0.03). check(logger.peek("loss"), 0.02) # Log 10x (window size) the same value. for _ in range(10): logger.log_value("loss", 0.05, window=10) check(logger.peek("loss"), 0.05) # Internals check (note that users should not be concerned with accessing # these). Len should always be 10, since the underlying struct is a # `deque(max_len=10)`. check(len(logger.stats["loss"].values), 10) # Only, when we call `reduce` does the underlying structure get "cleaned # up". In this case, the list is shortened to 10 items (window size). results = logger.reduce() check(results, {"loss": 0.05}) check(len(logger.stats["loss"].values), 10) # Log a value under a deeper nested key. logger.log_value(("some", "nested", "key"), -1.0) check(logger.peek(("some", "nested", "key")), -1.0) # Log n values without reducing them (we want to just collect some items). logger.log_value("some_items", 5.0, reduce=None) logger.log_value("some_items", 6.0, reduce=None) logger.log_value("some_items", 7.0, reduce=None) # Peeking at these returns the full list of items (no reduction set up). check(logger.peek("some_items"), [5.0, 6.0, 7.0]) # If you don't want the internal list to grow indefinitely, you should set # `clear_on_reduce=True`: logger.log_value("some_more_items", -5.0, reduce=None, clear_on_reduce=True) logger.log_value("some_more_items", -6.0, reduce=None, clear_on_reduce=True) logger.log_value("some_more_items", -7.0, reduce=None, clear_on_reduce=True ) # Peeking at these returns the full list of items (no reduction set up). check(logger.peek("some_more_items"), [-5.0, -6.0, -7.0]) # Reducing everything (and return plain values, not `Stats` objects). results = logger.reduce() check(results, { "loss": 0.05, "some": { "nested": { "key": -1.0, }, }, "some_items": [5.0, 6.0, 7.0], # reduce=None; list as-is "some_more_items": [-5.0, -6.0, -7.0], # reduce=None; list as-is }) # However, the `reduce()` call did empty the `some_more_items` list # (b/c we set `clear_on_reduce=True`). check(logger.peek("some_more_items"), []) # ... but not the "some_items" list (b/c `clear_on_reduce=False`). check(logger.peek("some_items"), [])
- Parameters:
key – The key (or nested key-tuple) to log the
valueunder.value – The value to log. This should be a numeric value.
reduce – The reduction method to apply, once
self.reduce()is called. If None, will collect all logged values underkeyin a list (and also return that list upon callingself.reduce()).window – An optional window size to reduce over. If not None, then the reduction operation is only applied to the most recent
windowitems, and - after reduction - the internal values list underkeyis shortened to hold at mostwindowitems (the most recent ones). Must be None ifema_coeffis provided. If None (andema_coeffis None), reduction must not be “mean”.ema_coeff – An optional EMA coefficient to use if
reduceis “mean” and nowindowis provided. Note that if bothwindowandema_coeffare provided, an error is thrown. Also, ifema_coeffis provided,reducemust be “mean”. The reduction formula for EMA is: EMA(t1) = (1.0 - ema_coeff) * EMA(t0) + ema_coeff * new_valuepercentiles – If reduce is
None, we can compute the percentiles of the values list given bypercentiles. Defaults to [0, 0.5, 0.75, 0.9, 0.95, 0.99, 1] if set to True. When using percentiles, a window must be provided. This window should be chosen carefully. RLlib computes exact percentiles and the computational complexity is O(m*n*log(n/m)) where n is the window size and m is the number of parallel metrics loggers involved (for example, m EnvRunners).clear_on_reduce – If True, all values under
keywill be emptied afterself.reduce()is called. Setting this to True is useful for cases, in which the internal values list would otherwise grow indefinitely, for example if reduce is None and there is nowindowprovided.with_throughput – Whether to track a throughput estimate together with this metric. This is only supported for
reduce=sumandclear_on_reduce=Falsemetrics (aka. “lifetime counts”). TheStatsobject under the logged key then keeps track of the time passed between two consecutive calls toreduce()and update its throughput estimate. The current throughput estimate of a key can be obtained through: <MetricsLogger>.peek(key, throughput=True).throughput_ema_coeff – The EMA coefficient to use for throughput tracking. Only used if with_throughput=True. Defaults to 0.05 if with_throughput is True.
reduce_per_index_on_aggregate – If True, when merging Stats objects in parallel, we reduce incoming values per index such that the new value at index
nwill be the reduced value of all incoming values at indexn. If False, when reducingnStats, the firstnmerged values will be the reduced value of all incoming values at index0, the nextnmerged values will be the reduced values of all incoming values at index1, etc.