From ee081d5fa0142300d46cb30653fe98948cd0a86b Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Tue, 10 Mar 2026 18:36:06 +0000 Subject: [PATCH 01/26] add trackio integration Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 318 +++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 python/ray/air/integrations/trackio.py diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py new file mode 100644 index 000000000000..93ba2f33be9c --- /dev/null +++ b/python/ray/air/integrations/trackio.py @@ -0,0 +1,318 @@ +from typing import Dict, Optional, List +import numpy as np + +try: + import trackio +except ImportError: + trackio = None + +from ray.train._internal.session import get_session +from ray.tune.logger import LoggerCallback +from ray.tune.utils import flatten_dict +from ray.tune.experiment import Trial +from ray.util import PublicAPI + + +# ------------------------------------------------------------ +# setup_trackio() +# ------------------------------------------------------------ + +@PublicAPI(stability="alpha") +def setup_trackio( + config: Optional[Dict] = None, + project: Optional[str] = None, + name: Optional[str] = None, + group: Optional[str] = None, + auto_log_gpu: bool = False, + gpu_log_interval: float = 10.0, + dataset_id: Optional[str] = None, + space_id: Optional[str] = None, + rank_zero_only: bool = True, +): + """ + Set up a Trackio experiment run. + + This function initializes a Trackio run for experiment tracking within + Ray Train training loops. Trackio is a lightweight experiment tracking + system that logs metrics, configuration parameters, and system statistics + during model training. + + By default, the run name is derived from the Ray trial name and the run + group corresponds to the Ray experiment name. These values can be overridden + by explicitly passing ``name`` and ``group``. + + In distributed training with Ray Train, only the worker with rank 0 will + initialize the Trackio run by default. This prevents duplicate logging from + multiple workers. If ``rank_zero_only=False`` is specified, every worker + will initialize its own Trackio run. + + Trackio supports additional features such as GPU utilization logging, + remote experiment logging via Hugging Face datasets, and remote dashboards + hosted on Hugging Face Spaces. + + Args: + config: Configuration dictionary to log as part of the experiment + metadata. This typically contains hyperparameters or training + configuration values. + project: Name of the Trackio project under which runs are grouped. + Defaults to ``"ray-train"`` if not provided. + name: Optional name of the Trackio run. Defaults to the Ray trial name. + group: Optional grouping identifier for runs. Defaults to the Ray + experiment name. + auto_log_gpu: If True, Trackio automatically records GPU utilization + metrics during training. + gpu_log_interval: Interval (in seconds) between GPU metric samples. + dataset_id: Optional Hugging Face dataset ID where experiment logs + should be uploaded. + space_id: Optional Hugging Face Space ID used for hosting the Trackio + dashboard remotely. + rank_zero_only: If True, only the rank 0 worker in distributed training + will initialize Trackio. If False, all workers will create runs. + + Returns: + A Trackio run object returned by ``trackio.init()``. + + Example: + + .. code-block:: python + + from ray.air.integrations.trackio import setup_trackio + + def training_loop(config): + run = setup_trackio(config=config, project="my-project") + + for step in range(10): + loss = train_step() + trackio.log({"loss": loss}, step=step) + + run.finish() + """ + + if trackio is None: + raise RuntimeError( + "Trackio was not found. Install with `pip install trackio`." + ) + + session = get_session() + + trial_name = None + experiment_name = None + + if session: + + if rank_zero_only and session.world_rank is not None and session.world_rank != 0: + return None + + trial_name = session.trial_name + experiment_name = session.experiment_name + + name = name or trial_name + group = group or experiment_name + + run = trackio.init( + project=project or "ray-train", + name=name, + group=group, + config=config, + auto_log_gpu=auto_log_gpu, + gpu_log_interval=gpu_log_interval, + dataset_id=dataset_id, + space_id=space_id, + ) + + return run + + +# ------------------------------------------------------------ +# TrackioLoggerCallback +# ------------------------------------------------------------ + +@PublicAPI(stability="alpha") +class TrackioLoggerCallback(LoggerCallback): + """ + Logger callback that logs Ray Tune experiment results to Trackio. + + This callback integrates Trackio experiment tracking with Ray Tune. + Each Ray Tune trial corresponds to a Trackio run. Metrics reported by + the training function are automatically logged to Trackio. + + Trackio supports additional capabilities such as GPU telemetry logging, + remote experiment logging through Hugging Face datasets, and remote + dashboards hosted on Hugging Face Spaces. + + Example: + + .. code-block:: python + + from ray import tune + from ray.air.integrations.trackio import TrackioLoggerCallback + + def train_fn(config): + for step in range(10): + loss = 1 / (step + 1) + tune.report({"loss": loss}) + + tuner = tune.Tuner( + train_fn, + param_space={"lr": tune.grid_search([0.001, 0.01])}, + run_config=tune.RunConfig( + callbacks=[ + TrackioLoggerCallback( + project="ray-experiments", + auto_log_gpu=True + ) + ] + ), + ) + + tuner.fit() + + Args: + project: Name of the Trackio project. + group: Optional grouping identifier for runs. + log_config: If True, Ray trial configuration parameters will be logged. + auto_log_gpu: If True, GPU utilization metrics will be logged. + gpu_log_interval: Interval (seconds) between GPU metric samples. + dataset_id: Optional Hugging Face dataset ID used for remote logging. + space_id: Optional Hugging Face Space used to host the Trackio dashboard. + excludes: List of metric keys that should not be logged. + """ + + _exclude_results = ["done", "should_checkpoint"] + + def __init__( + self, + project: str, + group: Optional[str] = None, + log_config: bool = True, + auto_log_gpu: bool = False, + gpu_log_interval: float = 10.0, + dataset_id: Optional[str] = None, + space_id: Optional[str] = None, + excludes: Optional[List[str]] = None, + ): + + if trackio is None: + raise RuntimeError( + "Trackio was not found. Install with `pip install trackio`." + ) + + self.project = project + self.group = group + self.log_config = log_config + + self.auto_log_gpu = auto_log_gpu + self.gpu_log_interval = gpu_log_interval + self.dataset_id = dataset_id + self.space_id = space_id + + self.excludes = excludes or [] + + self._trial_runs: Dict[Trial, object] = {} + + # -------------------------------------------------------- + + def log_trial_start(self, trial: Trial): + """Initialize a Trackio run when a Ray Tune trial starts.""" + + config = trial.config.copy() + + if not self.log_config: + config = {} + + run = trackio.init( + project=self.project, + name=str(trial), + group=self.group or trial.experiment_dir_name, + config=config, + auto_log_gpu=self.auto_log_gpu, + gpu_log_interval=self.gpu_log_interval, + dataset_id=self.dataset_id, + space_id=self.space_id, + ) + + self._trial_runs[trial] = run + + # -------------------------------------------------------- + + def log_trial_result( + self, + iteration: int, + trial: Trial, + result: Dict, + ): + """Log metrics from a Ray Tune training iteration to Trackio.""" + + run = self._trial_runs.get(trial) + + if not run: + return + + flat = flatten_dict(result) + + metrics = {} + + for key, value in flat.items(): + + if key in self._exclude_results: + continue + + if key in self.excludes: + continue + + if isinstance(value, np.ndarray): + value = value.tolist() + + if isinstance(value, np.generic): + value = value.item() + + if isinstance(value, (int, float)): + metrics[key] = value + + if metrics: + trackio.log(metrics, step=iteration) + + # -------------------------------------------------------- + + def log_trial_save(self, trial: Trial): + """Log checkpoint metadata when a Ray Tune trial checkpoint is saved.""" + + checkpoint = trial.checkpoint + + if checkpoint: + try: + path = checkpoint.path + trackio.log({"checkpoint_path": path}) + except Exception: + pass + + # -------------------------------------------------------- + + def log_trial_end(self, trial: Trial, failed: bool = False): + """Finalize the Trackio run when a Ray Tune trial finishes.""" + + run = self._trial_runs.get(trial) + + if run: + run.finish() + + self._trial_runs.pop(trial, None) + + # -------------------------------------------------------- + + def on_experiment_end(self, trials, **info): + """Finalize all Trackio runs after the Ray Tune experiment completes.""" + + for trial in list(self._trial_runs.keys()): + + run = self._trial_runs.get(trial) + + if run: + run.finish() + + self._trial_runs.clear() + + try: + trackio.finish() + except Exception: + pass \ No newline at end of file From 0b5849af761afc8f4047fa49a4655d35ca727d3b Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 00:34:34 +0530 Subject: [PATCH 02/26] Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 93ba2f33be9c..3b3b121e5338 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -85,7 +85,7 @@ def training_loop(config): loss = train_step() trackio.log({"loss": loss}, step=step) - run.finish() + run and run.finish() """ if trackio is None: @@ -283,8 +283,8 @@ def log_trial_save(self, trial: Trial): try: path = checkpoint.path trackio.log({"checkpoint_path": path}) - except Exception: - pass + except Exception as e: + logger.warning(f"trackio: Failed to log checkpoint path: {e}") # -------------------------------------------------------- @@ -314,5 +314,5 @@ def on_experiment_end(self, trials, **info): try: trackio.finish() - except Exception: - pass \ No newline at end of file + except Exception as e: + logger.warning(f"trackio: `trackio.finish()` failed: {e}") \ No newline at end of file From 274a4df2270710c9ca97baac8b0b309ba1919fbc Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 08:47:57 +0000 Subject: [PATCH 03/26] add missing logger import and clean up comments Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 36 +++++++++----------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 3b3b121e5338..446004b24cb8 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -1,4 +1,6 @@ -from typing import Dict, Optional, List +import logging +from typing import Dict, List, Optional + import numpy as np try: @@ -7,15 +9,13 @@ trackio = None from ray.train._internal.session import get_session +from ray.tune.experiment import Trial from ray.tune.logger import LoggerCallback from ray.tune.utils import flatten_dict -from ray.tune.experiment import Trial from ray.util import PublicAPI +logger = logging.getLogger(__name__) -# ------------------------------------------------------------ -# setup_trackio() -# ------------------------------------------------------------ @PublicAPI(stability="alpha") def setup_trackio( @@ -89,9 +89,7 @@ def training_loop(config): """ if trackio is None: - raise RuntimeError( - "Trackio was not found. Install with `pip install trackio`." - ) + raise RuntimeError("Trackio was not found. Install with `pip install trackio`.") session = get_session() @@ -100,7 +98,11 @@ def training_loop(config): if session: - if rank_zero_only and session.world_rank is not None and session.world_rank != 0: + if ( + rank_zero_only + and session.world_rank is not None + and session.world_rank != 0 + ): return None trial_name = session.trial_name @@ -123,10 +125,6 @@ def training_loop(config): return run -# ------------------------------------------------------------ -# TrackioLoggerCallback -# ------------------------------------------------------------ - @PublicAPI(stability="alpha") class TrackioLoggerCallback(LoggerCallback): """ @@ -210,8 +208,6 @@ def __init__( self._trial_runs: Dict[Trial, object] = {} - # -------------------------------------------------------- - def log_trial_start(self, trial: Trial): """Initialize a Trackio run when a Ray Tune trial starts.""" @@ -233,8 +229,6 @@ def log_trial_start(self, trial: Trial): self._trial_runs[trial] = run - # -------------------------------------------------------- - def log_trial_result( self, iteration: int, @@ -272,8 +266,6 @@ def log_trial_result( if metrics: trackio.log(metrics, step=iteration) - # -------------------------------------------------------- - def log_trial_save(self, trial: Trial): """Log checkpoint metadata when a Ray Tune trial checkpoint is saved.""" @@ -286,8 +278,6 @@ def log_trial_save(self, trial: Trial): except Exception as e: logger.warning(f"trackio: Failed to log checkpoint path: {e}") - # -------------------------------------------------------- - def log_trial_end(self, trial: Trial, failed: bool = False): """Finalize the Trackio run when a Ray Tune trial finishes.""" @@ -298,8 +288,6 @@ def log_trial_end(self, trial: Trial, failed: bool = False): self._trial_runs.pop(trial, None) - # -------------------------------------------------------- - def on_experiment_end(self, trials, **info): """Finalize all Trackio runs after the Ray Tune experiment completes.""" @@ -315,4 +303,4 @@ def on_experiment_end(self, trials, **info): try: trackio.finish() except Exception as e: - logger.warning(f"trackio: `trackio.finish()` failed: {e}") \ No newline at end of file + logger.warning(f"trackio: `trackio.finish()` failed: {e}") From b876fdfdc2cda78a3fd84ea59d3581ec0e5dabae Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 09:05:27 +0000 Subject: [PATCH 04/26] fix race condition in logging Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 446004b24cb8..6d5bb53f8429 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -83,7 +83,7 @@ def training_loop(config): for step in range(10): loss = train_step() - trackio.log({"loss": loss}, step=step) + run.log({"loss": loss}, step=step) run and run.finish() """ @@ -131,8 +131,9 @@ class TrackioLoggerCallback(LoggerCallback): Logger callback that logs Ray Tune experiment results to Trackio. This callback integrates Trackio experiment tracking with Ray Tune. - Each Ray Tune trial corresponds to a Trackio run. Metrics reported by - the training function are automatically logged to Trackio. + Each Ray Tune trial corresponds to a Trackio run.Each Ray Tune trial + corresponds to a separate Trackio run. Metrics reported by the training + function are logged to the corresponding run. Trackio supports additional capabilities such as GPU telemetry logging, remote experiment logging through Hugging Face datasets, and remote @@ -264,7 +265,7 @@ def log_trial_result( metrics[key] = value if metrics: - trackio.log(metrics, step=iteration) + run.log(metrics, step=iteration) def log_trial_save(self, trial: Trial): """Log checkpoint metadata when a Ray Tune trial checkpoint is saved.""" @@ -274,7 +275,9 @@ def log_trial_save(self, trial: Trial): if checkpoint: try: path = checkpoint.path - trackio.log({"checkpoint_path": path}) + run = self._trial_runs.get(trial) + if run: + run.log({"checkpoint_path": path}) except Exception as e: logger.warning(f"trackio: Failed to log checkpoint path: {e}") From ab199c1ad383cf8bb706f63e2284d7a0ae7c0320 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 09:23:11 +0000 Subject: [PATCH 05/26] fix more issues with trial saving Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 6d5bb53f8429..8bd1f7d8e569 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -212,6 +212,10 @@ def __init__( def log_trial_start(self, trial: Trial): """Initialize a Trackio run when a Ray Tune trial starts.""" + # Prevent duplicate runs during trial recovery + if trial in self._trial_runs: + return + config = trial.config.copy() if not self.log_config: @@ -240,6 +244,11 @@ def log_trial_result( run = self._trial_runs.get(trial) + # Lazy initialization after experiment restore + if run is None: + self.log_trial_start(trial) + run = self._trial_runs.get(trial) + if not run: return @@ -255,12 +264,14 @@ def log_trial_result( if key in self.excludes: continue + # Convert numpy arrays and scalar types if isinstance(value, np.ndarray): value = value.tolist() if isinstance(value, np.generic): value = value.item() + # Only log supported metric types if isinstance(value, (int, float)): metrics[key] = value @@ -272,6 +283,9 @@ def log_trial_save(self, trial: Trial): checkpoint = trial.checkpoint + if not checkpoint: + return + if checkpoint: try: path = checkpoint.path From 9d21b1547ae9ab0280e052248dcb5f616dd76aec Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 16:03:14 +0000 Subject: [PATCH 06/26] refactor to fix issues Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 8bd1f7d8e569..f6ec61af94b8 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -286,12 +286,14 @@ def log_trial_save(self, trial: Trial): if not checkpoint: return - if checkpoint: + run = self._trial_runs.get(trial) + + if run is None: + self.log_trial_start(trial) + run = self._trial_runs.get(trial) + try: - path = checkpoint.path - run = self._trial_runs.get(trial) - if run: - run.log({"checkpoint_path": path}) + run.log({"checkpoint_saved": 1}) except Exception as e: logger.warning(f"trackio: Failed to log checkpoint path: {e}") From 8e88700467cf00f16b5c3edb44b04e79ff918ac4 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 16:23:56 +0000 Subject: [PATCH 07/26] fix issue to make cursor happy Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index f6ec61af94b8..92d52ed59485 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -292,10 +292,11 @@ def log_trial_save(self, trial: Trial): self.log_trial_start(trial) run = self._trial_runs.get(trial) + if run: try: run.log({"checkpoint_saved": 1}) except Exception as e: - logger.warning(f"trackio: Failed to log checkpoint path: {e}") + logger.warning(f"trackio: Failed to log checkpoint: {e}") def log_trial_end(self, trial: Trial, failed: bool = False): """Finalize the Trackio run when a Ray Tune trial finishes.""" From 7831ef3a66c00349a58a5e47c95dd11cc405bf03 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 17:50:21 +0000 Subject: [PATCH 08/26] enhance integration to fix issues Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 92d52ed59485..b89b5048213d 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -11,6 +11,7 @@ from ray.train._internal.session import get_session from ray.tune.experiment import Trial from ray.tune.logger import LoggerCallback +from ray.tune.result import TRAINING_ITERATION from ray.tune.utils import flatten_dict from ray.util import PublicAPI @@ -220,6 +221,8 @@ def log_trial_start(self, trial: Trial): if not self.log_config: config = {} + else: + config.pop("callbacks", None) run = trackio.init( project=self.project, @@ -276,7 +279,8 @@ def log_trial_result( metrics[key] = value if metrics: - run.log(metrics, step=iteration) + training_step = result.get(TRAINING_ITERATION, iteration) + run.log(metrics, step=training_step) def log_trial_save(self, trial: Trial): """Log checkpoint metadata when a Ray Tune trial checkpoint is saved.""" From 0b3d1adb1be3dd3e4504ef27489c7292690bcfeb Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 11 Mar 2026 18:04:12 +0000 Subject: [PATCH 09/26] fix leaking configs Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index b89b5048213d..f88385f5b44f 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -210,6 +210,10 @@ def __init__( self._trial_runs: Dict[Trial, object] = {} + self._effective_excludes = list(self._exclude_results) + if not self.log_config: + self._effective_excludes.append("config") + def log_trial_start(self, trial: Trial): """Initialize a Trackio run when a Ray Tune trial starts.""" @@ -261,7 +265,7 @@ def log_trial_result( for key, value in flat.items(): - if key in self._exclude_results: + if key in self._effective_excludes: continue if key in self.excludes: From 1efb158dd6243696d8b93478e590fb89470067ec Mon Sep 17 00:00:00 2001 From: Mark Towers Date: Wed, 25 Mar 2026 21:25:42 +0000 Subject: [PATCH 10/26] Update trackio.py Signed-off-by: Mark Towers --- python/ray/air/integrations/trackio.py | 65 +++++++------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index f88385f5b44f..b56e862ac077 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -8,10 +8,10 @@ except ImportError: trackio = None +from ray.air.constants import TRAINING_ITERATION from ray.train._internal.session import get_session from ray.tune.experiment import Trial from ray.tune.logger import LoggerCallback -from ray.tune.result import TRAINING_ITERATION from ray.tune.utils import flatten_dict from ray.util import PublicAPI @@ -30,8 +30,7 @@ def setup_trackio( space_id: Optional[str] = None, rank_zero_only: bool = True, ): - """ - Set up a Trackio experiment run. + """Set up a Trackio experiment run. This function initializes a Trackio run for experiment tracking within Ray Train training loops. Trackio is a lightweight experiment tracking @@ -86,19 +85,17 @@ def training_loop(config): loss = train_step() run.log({"loss": loss}, step=step) - run and run.finish() + if run: + run.finish() """ - if trackio is None: raise RuntimeError("Trackio was not found. Install with `pip install trackio`.") - session = get_session() - trial_name = None experiment_name = None + session = get_session() if session: - if ( rank_zero_only and session.world_rank is not None @@ -122,19 +119,16 @@ def training_loop(config): dataset_id=dataset_id, space_id=space_id, ) - return run @PublicAPI(stability="alpha") class TrackioLoggerCallback(LoggerCallback): - """ - Logger callback that logs Ray Tune experiment results to Trackio. + """Logger callback that logs Ray Tune experiment results to Trackio. This callback integrates Trackio experiment tracking with Ray Tune. - Each Ray Tune trial corresponds to a Trackio run.Each Ray Tune trial - corresponds to a separate Trackio run. Metrics reported by the training - function are logged to the corresponding run. + Each Ray Tune trial corresponds to a separate Trackio run. Metrics + reported by the training function are logged to the corresponding run. Trackio supports additional capabilities such as GPU telemetry logging, remote experiment logging through Hugging Face datasets, and remote @@ -162,7 +156,7 @@ def train_fn(config): auto_log_gpu=True ) ] - ), + ) ) tuner.fit() @@ -191,7 +185,6 @@ def __init__( space_id: Optional[str] = None, excludes: Optional[List[str]] = None, ): - if trackio is None: raise RuntimeError( "Trackio was not found. Install with `pip install trackio`." @@ -207,28 +200,25 @@ def __init__( self.space_id = space_id self.excludes = excludes or [] - - self._trial_runs: Dict[Trial, object] = {} - self._effective_excludes = list(self._exclude_results) if not self.log_config: self._effective_excludes.append("config") + self._trial_runs: Dict[Trial, trackio.Run] = {} + def log_trial_start(self, trial: Trial): """Initialize a Trackio run when a Ray Tune trial starts.""" - # Prevent duplicate runs during trial recovery if trial in self._trial_runs: return config = trial.config.copy() - if not self.log_config: config = {} else: config.pop("callbacks", None) - run = trackio.init( + self._trial_runs[trial] = trackio.init( project=self.project, name=str(trial), group=self.group or trial.experiment_dir_name, @@ -239,8 +229,6 @@ def log_trial_start(self, trial: Trial): space_id=self.space_id, ) - self._trial_runs[trial] = run - def log_trial_result( self, iteration: int, @@ -248,7 +236,6 @@ def log_trial_result( result: Dict, ): """Log metrics from a Ray Tune training iteration to Trackio.""" - run = self._trial_runs.get(trial) # Lazy initialization after experiment restore @@ -256,28 +243,17 @@ def log_trial_result( self.log_trial_start(trial) run = self._trial_runs.get(trial) - if not run: - return - flat = flatten_dict(result) - metrics = {} - for key, value in flat.items(): - - if key in self._effective_excludes: - continue - - if key in self.excludes: + if key in self._effective_excludes or key in self.excludes: continue # Convert numpy arrays and scalar types if isinstance(value, np.ndarray): value = value.tolist() - if isinstance(value, np.generic): value = value.item() - # Only log supported metric types if isinstance(value, (int, float)): metrics[key] = value @@ -288,14 +264,11 @@ def log_trial_result( def log_trial_save(self, trial: Trial): """Log checkpoint metadata when a Ray Tune trial checkpoint is saved.""" - checkpoint = trial.checkpoint - if not checkpoint: return run = self._trial_runs.get(trial) - if run is None: self.log_trial_start(trial) run = self._trial_runs.get(trial) @@ -308,21 +281,19 @@ def log_trial_save(self, trial: Trial): def log_trial_end(self, trial: Trial, failed: bool = False): """Finalize the Trackio run when a Ray Tune trial finishes.""" - run = self._trial_runs.get(trial) - if run: run.finish() self._trial_runs.pop(trial, None) def on_experiment_end(self, trials, **info): - """Finalize all Trackio runs after the Ray Tune experiment completes.""" - - for trial in list(self._trial_runs.keys()): - - run = self._trial_runs.get(trial) + """Finalize any remaining Trackio runs after the Ray Tune experiment ends. + ``log_trial_end`` handles normal trial cleanup. This method catches + runs that were never properly ended due to interruption or failure. + """ + for trial, run in self._trial_runs.items(): if run: run.finish() From 82bed2f96e274ae703996606cfed8c02d05d9704 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Fri, 27 Mar 2026 10:37:39 +0000 Subject: [PATCH 11/26] address reviewer comments and add initial set of tests Signed-off-by: Parag Ekbote --- doc/source/tune/examples/tune_trackio.ipynb | 10 + python/ray/air/integrations/trackio.py | 37 ++- .../ray/air/tests/test_integration_trackio.py | 277 ++++++++++++++++++ 3 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 doc/source/tune/examples/tune_trackio.ipynb create mode 100644 python/ray/air/tests/test_integration_trackio.py diff --git a/doc/source/tune/examples/tune_trackio.ipynb b/doc/source/tune/examples/tune_trackio.ipynb new file mode 100644 index 000000000000..c55a2876b3f9 --- /dev/null +++ b/doc/source/tune/examples/tune_trackio.ipynb @@ -0,0 +1,10 @@ +{ + "cells": [], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index b56e862ac077..d6b0404bc5d6 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -12,11 +12,24 @@ from ray.train._internal.session import get_session from ray.tune.experiment import Trial from ray.tune.logger import LoggerCallback -from ray.tune.utils import flatten_dict from ray.util import PublicAPI logger = logging.getLogger(__name__) +def _flatten_dict(d: Dict, parent_key: str = "", sep: str = "/") -> Dict: + """Flatten a nested dictionary.""" + + items = [] + + for k, v in d.items(): + new_key = f"{parent_key}{sep}{k}" if parent_key else k + + if isinstance(v, dict): + items.extend(_flatten_dict(v, new_key, sep=sep).items()) + else: + items.append((new_key, v)) + + return dict(items) @PublicAPI(stability="alpha") def setup_trackio( @@ -199,13 +212,19 @@ def __init__( self.dataset_id = dataset_id self.space_id = space_id + self._warned_unsupported_keys = set() self.excludes = excludes or [] - self._effective_excludes = list(self._exclude_results) + self._effective_excludes = set(self._exclude_results) + + if excludes: + self._effective_excludes.update(excludes) + if not self.log_config: - self._effective_excludes.append("config") + self._effective_excludes.add("config") self._trial_runs: Dict[Trial, trackio.Run] = {} + def log_trial_start(self, trial: Trial): """Initialize a Trackio run when a Ray Tune trial starts.""" # Prevent duplicate runs during trial recovery @@ -243,10 +262,10 @@ def log_trial_result( self.log_trial_start(trial) run = self._trial_runs.get(trial) - flat = flatten_dict(result) + flat = _flatten_dict(result) metrics = {} for key, value in flat.items(): - if key in self._effective_excludes or key in self.excludes: + if any(key.startswith(ex) for ex in self._effective_excludes): continue # Convert numpy arrays and scalar types @@ -257,6 +276,14 @@ def log_trial_result( # Only log supported metric types if isinstance(value, (int, float)): metrics[key] = value + else: + # Warn once per key + if key not in self._warned_unsupported_keys: + logger.warning( + f"trackio: Dropping unsupported metric '{key}' " + f"(type={type(value).__name__}). Only int/float supported." + ) + self._warned_unsupported_keys.add(key) if metrics: training_step = result.get(TRAINING_ITERATION, iteration) diff --git a/python/ray/air/tests/test_integration_trackio.py b/python/ray/air/tests/test_integration_trackio.py new file mode 100644 index 000000000000..61e02f70b984 --- /dev/null +++ b/python/ray/air/tests/test_integration_trackio.py @@ -0,0 +1,277 @@ +import numpy as np +import pytest +from unittest.mock import MagicMock + +from ray.air.integrations.trackio import ( + TrackioLoggerCallback, + setup_trackio, +) + + +# ------------------------- +# Mock Objects +# ------------------------- + +class MockTrial: + def __init__(self): + self.config = {"lr": 0.01, "callbacks": "remove_me"} + self.experiment_dir_name = "exp_group" + self.checkpoint = None + + def __str__(self): + return "mock_trial" + + +class MockRun: + def __init__(self): + self.logged = [] + self.finished = False + + def log(self, metrics, step=None): + self.logged.append((metrics, step)) + + def finish(self): + self.finished = True + + +# ------------------------- +# Fixtures +# ------------------------- + +@pytest.fixture +def mock_trackio(mocker): + mock_run = MockRun() + + mock_init = mocker.patch( + "ray.air.integrations.trackio.trackio.init", + return_value=mock_run, + ) + + return mock_init, mock_run + + +# ------------------------- +# Tests: TrackioLoggerCallback +# ------------------------- + +def test_log_trial_start_initializes_run(mock_trackio): + mock_init, _ = mock_trackio + + cb = TrackioLoggerCallback(project="test_project") + trial = MockTrial() + + cb.log_trial_start(trial) + + assert trial in cb._trial_runs + mock_init.assert_called_once() + + _, kwargs = mock_init.call_args + assert kwargs["project"] == "test_project" + assert kwargs["name"] == "mock_trial" + assert kwargs["group"] == "exp_group" + + # callbacks removed + assert "callbacks" not in kwargs["config"] + + +def test_log_trial_result_basic_metrics(mock_trackio): + _, mock_run = mock_trackio + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_start(trial) + + result = { + "loss": 0.5, + "accuracy": 0.9, + "training_iteration": 3, + } + + cb.log_trial_result(1, trial, result) + + assert len(mock_run.logged) == 1 + metrics, step = mock_run.logged[0] + + assert metrics == {"loss": 0.5, "accuracy": 0.9} + assert step == 3 + + +def test_flatten_dict_logging(mock_trackio): + _, mock_run = mock_trackio + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_start(trial) + + result = { + "metrics": { + "loss": 0.1, + "acc": 0.95, + } + } + + cb.log_trial_result(1, trial, result) + + metrics, _ = mock_run.logged[0] + + assert metrics["metrics/loss"] == 0.1 + assert metrics["metrics/acc"] == 0.95 + + +def test_numpy_conversion_and_filtering(mock_trackio): + _, mock_run = mock_trackio + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_start(trial) + + result = { + "loss": np.float32(0.25), + "arr": np.array([1, 2, 3]), # dropped + } + + cb.log_trial_result(1, trial, result) + + metrics, _ = mock_run.logged[0] + + assert metrics["loss"] == 0.25 + assert "arr" not in metrics + + +def test_warning_logged_once_per_key(mock_trackio, mocker): + mocker.patch("ray.air.integrations.trackio.logger.warning") + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_start(trial) + + result = {"bad_metric": "string"} + + cb.log_trial_result(1, trial, result) + cb.log_trial_result(2, trial, result) + + logger_mock = pytest.importorskip( + "ray.air.integrations.trackio" + ).logger.warning + + assert logger_mock.call_count == 1 + + +def test_excludes_filtering(mock_trackio): + _, mock_run = mock_trackio + + cb = TrackioLoggerCallback( + project="test", + excludes=["loss"], + ) + + trial = MockTrial() + cb.log_trial_start(trial) + + result = { + "loss": 0.5, + "accuracy": 0.8, + "done": True, + } + + cb.log_trial_result(1, trial, result) + + metrics, _ = mock_run.logged[0] + + assert "loss" not in metrics + assert "done" not in metrics + assert metrics["accuracy"] == 0.8 + + +def test_lazy_initialization_on_result(mock_trackio): + mock_init, _ = mock_trackio + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_result(1, trial, {"loss": 1.0}) + + assert mock_init.called + assert trial in cb._trial_runs + + +def test_log_trial_end_finishes_run(mock_trackio): + _, mock_run = mock_trackio + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_start(trial) + cb.log_trial_end(trial) + + assert mock_run.finished is True + assert trial not in cb._trial_runs + + +def test_on_experiment_end_cleans_all_runs(mock_trackio): + _, mock_run = mock_trackio + + cb = TrackioLoggerCallback(project="test") + trial = MockTrial() + + cb.log_trial_start(trial) + + cb.on_experiment_end([]) + + assert mock_run.finished is True + assert cb._trial_runs == {} + + +# ------------------------- +# Tests: setup_trackio +# ------------------------- + +def test_setup_trackio_rank_zero_only_blocks_nonzero(mocker): + mocker.patch("ray.air.integrations.trackio.trackio.init") + + session = MagicMock() + session.world_rank = 1 + session.trial_name = "trial" + session.experiment_name = "exp" + + mocker.patch( + "ray.air.integrations.trackio.get_session", + return_value=session, + ) + + run = setup_trackio(rank_zero_only=True) + + assert run is None + + +def test_setup_trackio_initializes_on_rank_zero(mocker): + mock_run = MagicMock() + + mock_init = mocker.patch( + "ray.air.integrations.trackio.trackio.init", + return_value=mock_run, + ) + + session = MagicMock() + session.world_rank = 0 + session.trial_name = "trial_name" + session.experiment_name = "exp_name" + + mocker.patch( + "ray.air.integrations.trackio.get_session", + return_value=session, + ) + + run = setup_trackio(config={"lr": 0.1}, project="proj") + + assert run == mock_run + + _, kwargs = mock_init.call_args + assert kwargs["project"] == "proj" + assert kwargs["name"] == "trial_name" + assert kwargs["group"] == "exp_name" + assert kwargs["config"]["lr"] == 0.1 \ No newline at end of file From 056046e3d0ce6b0f984a09fbf9fbb1fafe107ad8 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Fri, 27 Mar 2026 11:44:20 +0000 Subject: [PATCH 12/26] update tests and make cursor happy Signed-off-by: Parag Ekbote --- python/ray/air/integrations/trackio.py | 18 ++++++++++++------ .../ray/air/tests/test_integration_trackio.py | 14 ++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index d6b0404bc5d6..850c58c5687b 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -16,6 +16,7 @@ logger = logging.getLogger(__name__) + def _flatten_dict(d: Dict, parent_key: str = "", sep: str = "/") -> Dict: """Flatten a nested dictionary.""" @@ -31,6 +32,7 @@ def _flatten_dict(d: Dict, parent_key: str = "", sep: str = "/") -> Dict: return dict(items) + @PublicAPI(stability="alpha") def setup_trackio( config: Optional[Dict] = None, @@ -185,7 +187,7 @@ def train_fn(config): excludes: List of metric keys that should not be logged. """ - _exclude_results = ["done", "should_checkpoint"] + _exclude_results = ["done", "should_checkpoint", TRAINING_ITERATION] def __init__( self, @@ -224,7 +226,6 @@ def __init__( self._trial_runs: Dict[Trial, trackio.Run] = {} - def log_trial_start(self, trial: Trial): """Initialize a Trackio run when a Ray Tune trial starts.""" # Prevent duplicate runs during trial recovery @@ -265,7 +266,9 @@ def log_trial_result( flat = _flatten_dict(result) metrics = {} for key, value in flat.items(): - if any(key.startswith(ex) for ex in self._effective_excludes): + if any( + key == ex or key.startswith(ex + "/") for ex in self._effective_excludes + ): continue # Convert numpy arrays and scalar types @@ -277,7 +280,7 @@ def log_trial_result( if isinstance(value, (int, float)): metrics[key] = value else: - # Warn once per key + # Warn once per key if key not in self._warned_unsupported_keys: logger.warning( f"trackio: Dropping unsupported metric '{key}' " @@ -285,9 +288,12 @@ def log_trial_result( ) self._warned_unsupported_keys.add(key) - if metrics: + if metrics and run: training_step = result.get(TRAINING_ITERATION, iteration) - run.log(metrics, step=training_step) + try: + run.log(metrics, step=training_step) + except Exception as e: + logger.warning(f"trackio: Failed to log metrics: {e}") def log_trial_save(self, trial: Trial): """Log checkpoint metadata when a Ray Tune trial checkpoint is saved.""" diff --git a/python/ray/air/tests/test_integration_trackio.py b/python/ray/air/tests/test_integration_trackio.py index 61e02f70b984..09a60dac2884 100644 --- a/python/ray/air/tests/test_integration_trackio.py +++ b/python/ray/air/tests/test_integration_trackio.py @@ -1,17 +1,18 @@ +from unittest.mock import MagicMock + import numpy as np import pytest -from unittest.mock import MagicMock from ray.air.integrations.trackio import ( TrackioLoggerCallback, setup_trackio, ) - # ------------------------- # Mock Objects # ------------------------- + class MockTrial: def __init__(self): self.config = {"lr": 0.01, "callbacks": "remove_me"} @@ -38,6 +39,7 @@ def finish(self): # Fixtures # ------------------------- + @pytest.fixture def mock_trackio(mocker): mock_run = MockRun() @@ -54,6 +56,7 @@ def mock_trackio(mocker): # Tests: TrackioLoggerCallback # ------------------------- + def test_log_trial_start_initializes_run(mock_trackio): mock_init, _ = mock_trackio @@ -154,9 +157,7 @@ def test_warning_logged_once_per_key(mock_trackio, mocker): cb.log_trial_result(1, trial, result) cb.log_trial_result(2, trial, result) - logger_mock = pytest.importorskip( - "ray.air.integrations.trackio" - ).logger.warning + logger_mock = pytest.importorskip("ray.air.integrations.trackio").logger.warning assert logger_mock.call_count == 1 @@ -230,6 +231,7 @@ def test_on_experiment_end_cleans_all_runs(mock_trackio): # Tests: setup_trackio # ------------------------- + def test_setup_trackio_rank_zero_only_blocks_nonzero(mocker): mocker.patch("ray.air.integrations.trackio.trackio.init") @@ -274,4 +276,4 @@ def test_setup_trackio_initializes_on_rank_zero(mocker): assert kwargs["project"] == "proj" assert kwargs["name"] == "trial_name" assert kwargs["group"] == "exp_name" - assert kwargs["config"]["lr"] == 0.1 \ No newline at end of file + assert kwargs["config"]["lr"] == 0.1 From 2d8f990dee5fca1d7443999bbaa06d5ff72de187 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Fri, 27 Mar 2026 15:06:46 +0000 Subject: [PATCH 13/26] add trackio test to bazel and add integration dep in core-requirements.txt Signed-off-by: Parag Ekbote --- python/ray/air/BUILD.bazel | 13 +++++++++++++ python/requirements/ml/core-requirements.txt | 1 + 2 files changed, 14 insertions(+) diff --git a/python/ray/air/BUILD.bazel b/python/ray/air/BUILD.bazel index a62d409f29e4..df7da53c50a1 100644 --- a/python/ray/air/BUILD.bazel +++ b/python/ray/air/BUILD.bazel @@ -120,6 +120,19 @@ py_test( deps = [":ml_lib"], ) +py_test( + name = "test_integration_trackio", + size = "small", + srcs = ["tests/test_integration_trackio.py"], + # NOTE: This tests the Tune Trackio callback. + env = {"RAY_TRAIN_V2_ENABLED": "0"}, + tags = [ + "exclusive", + "team:ml", + ], + deps = [":ml_lib"], +) + py_test( name = "test_keras_callback", size = "medium", diff --git a/python/requirements/ml/core-requirements.txt b/python/requirements/ml/core-requirements.txt index 2b3a4b6688e3..6ce8797bb3fd 100644 --- a/python/requirements/ml/core-requirements.txt +++ b/python/requirements/ml/core-requirements.txt @@ -2,6 +2,7 @@ comet-ml==3.44.1 mlflow>=2.22.0 wandb>=0.23.1 +trackio>=0.16.0 # ML training frameworks xgboost==2.1.0 From 0dd79d06fd63a135dd64463878e120b8bfa62cce Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Fri, 27 Mar 2026 17:14:10 +0000 Subject: [PATCH 14/26] update some files and folders Signed-off-by: Parag Ekbote --- doc/source/images/trackio_logo_full.png | Bin 0 -> 158502 bytes doc/source/tune/examples/tune_trackio.ipynb | 96 +++++++++++++++++- python/ray/air/integrations/trackio.py | 3 +- .../ray/air/tests/test_integration_trackio.py | 6 ++ python/requirements/ml/core-requirements.txt | 2 +- 5 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 doc/source/images/trackio_logo_full.png diff --git a/doc/source/images/trackio_logo_full.png b/doc/source/images/trackio_logo_full.png new file mode 100644 index 0000000000000000000000000000000000000000..9a7a75b5bd14a94f76dc2fb12079b558ffda71b8 GIT binary patch literal 158502 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 cxXew+?n5@jiI)fS=#_>JGjDcE=e= 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 WZZiqa-i2@4O`l>jIewzsZ~q5aQe4Ua literal 0 HcmV?d00001 diff --git a/doc/source/tune/examples/tune_trackio.ipynb b/doc/source/tune/examples/tune_trackio.ipynb index c55a2876b3f9..a316c92fd61e 100644 --- a/doc/source/tune/examples/tune_trackio.ipynb +++ b/doc/source/tune/examples/tune_trackio.ipynb @@ -1,5 +1,99 @@ { - "cells": [], + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Trackio with Tune\n", + "\n", + "\n", + " \"try-anyscale-quickstart\"\n", + "\n", + "

\n", + "\n", + "(tune-wandb-ref)=\n", + "\n", + "[Trackio](https://huggingface.co/docs/trackio/index) is a open-source, lightweight, free experiment tracking \n", + "Python library built on top of Hugging Face Datasets and Spaces 🤗. It has a local first design and the experiments can be viewed with a Gradio dashboard locally or on\n", + "\n", + "```{image} /images/trackio_logo_full.png\n", + ":align: center\n", + ":alt: Weights & Biases\n", + ":height: 80px\n", + ":target: https://www.wandb.ai/\n", + "```\n", + "\n", + "Ray Tune currently offers two lightweight integrations for Weights & Biases.\n", + "One is the {ref}`WandbLoggerCallback `, which automatically logs\n", + "metrics reported to Tune to the Wandb API.\n", + "\n", + "The other one is the {ref}`setup_wandb() ` function, which can be\n", + "used with the function API. It automatically\n", + "initializes the Wandb API with Tune's training information. You can just use the\n", + "Wandb API like you would normally do, e.g. using `wandb.log()` to log your training\n", + "process.\n", + "\n", + "```{contents}\n", + ":backlinks: none\n", + ":local: true\n", + "```\n", + "\n", + "## Running A Trackio Example\n", + "\n", + "In the following example we're going to use both of the above methods, namely the `TrackioLoggerCallback` and\n", + "the `setup_wandb` function to log metrics.\n", + "\n", + "As the very first step, make sure you're logged in into the HF Hub on all machines you're running your training on:\n", + "\n", + " hf auth login\n", + "\n", + "We can then start with a few crucial imports:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], "metadata": { "language_info": { "name": "python" diff --git a/python/ray/air/integrations/trackio.py b/python/ray/air/integrations/trackio.py index 850c58c5687b..8bd8c96ad6b3 100644 --- a/python/ray/air/integrations/trackio.py +++ b/python/ray/air/integrations/trackio.py @@ -98,7 +98,8 @@ def training_loop(config): for step in range(10): loss = train_step() - run.log({"loss": loss}, step=step) + if run: + run.log({"loss": loss}, step=step) if run: run.finish() diff --git a/python/ray/air/tests/test_integration_trackio.py b/python/ray/air/tests/test_integration_trackio.py index 09a60dac2884..0d7330b43b16 100644 --- a/python/ray/air/tests/test_integration_trackio.py +++ b/python/ray/air/tests/test_integration_trackio.py @@ -277,3 +277,9 @@ def test_setup_trackio_initializes_on_rank_zero(mocker): assert kwargs["name"] == "trial_name" assert kwargs["group"] == "exp_name" assert kwargs["config"]["lr"] == 0.1 + + +if __name__ == "__main__": + import pytest + + pytest.main(["-v", __file__]) diff --git a/python/requirements/ml/core-requirements.txt b/python/requirements/ml/core-requirements.txt index 6ce8797bb3fd..436b2b340e8f 100644 --- a/python/requirements/ml/core-requirements.txt +++ b/python/requirements/ml/core-requirements.txt @@ -2,7 +2,7 @@ comet-ml==3.44.1 mlflow>=2.22.0 wandb>=0.23.1 -trackio>=0.16.0 +trackio # ML training frameworks xgboost==2.1.0 From 3b6a23efacf5d8ec8a3c018ca98b86390b75a1e4 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Fri, 27 Mar 2026 18:59:30 +0000 Subject: [PATCH 15/26] update to include end to end example with ray and trackio Signed-off-by: Parag Ekbote --- doc/source/tune/examples/tune_trackio.ipynb | 213 ++++++++++++++++++-- 1 file changed, 198 insertions(+), 15 deletions(-) diff --git a/doc/source/tune/examples/tune_trackio.ipynb b/doc/source/tune/examples/tune_trackio.ipynb index a316c92fd61e..98bb3f986421 100644 --- a/doc/source/tune/examples/tune_trackio.ipynb +++ b/doc/source/tune/examples/tune_trackio.ipynb @@ -11,23 +11,23 @@ "\n", "

\n", "\n", - "(tune-wandb-ref)=\n", + "(tune-trackio-ref)=\n", "\n", "[Trackio](https://huggingface.co/docs/trackio/index) is a open-source, lightweight, free experiment tracking \n", - "Python library built on top of Hugging Face Datasets and Spaces 🤗. It has a local first design and the experiments can be viewed with a Gradio dashboard locally or on\n", + "Python library built on top of Hugging Face Datasets and Spaces 🤗. It has a local first design and the experiments can be viewed with a Gradio dashboard locally or on the HF Hub\n", "\n", "```{image} /images/trackio_logo_full.png\n", ":align: center\n", - ":alt: Weights & Biases\n", + ":alt: Trackio\n", ":height: 80px\n", - ":target: https://www.wandb.ai/\n", + ":target: https://huggingface.co/docs/trackio/index/\n", "```\n", "\n", "Ray Tune currently offers two lightweight integrations for Weights & Biases.\n", - "One is the {ref}`WandbLoggerCallback `, which automatically logs\n", + "One is the {ref}`TrackioLoggerCallback `, which automatically logs\n", "metrics reported to Tune to the Wandb API.\n", "\n", - "The other one is the {ref}`setup_wandb() ` function, which can be\n", + "The other one is the {ref}`setup_trackio() ` function, which can be\n", "used with the function API. It automatically\n", "initializes the Wandb API with Tune's training information. You can just use the\n", "Wandb API like you would normally do, e.g. using `wandb.log()` to log your training\n", @@ -41,7 +41,7 @@ "## Running A Trackio Example\n", "\n", "In the following example we're going to use both of the above methods, namely the `TrackioLoggerCallback` and\n", - "the `setup_wandb` function to log metrics.\n", + "the `setup_trackio` function to log metrics.\n", "\n", "As the very first step, make sure you're logged in into the HF Hub on all machines you're running your training on:\n", "\n", @@ -54,44 +54,227 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mThe kernel failed to start due to the missing module 'packaging'. Consider installing this module.\n", + "\u001b[1;31mClick here for more info." + ] + } + ], + "source": [ + "import random\n", + "import time\n", + "\n", + "import numpy as np\n", + "import trackio\n", + "\n", + "import ray\n", + "from ray import tune\n", + "from ray.air.integrations.trackio import (\n", + " TrackioLoggerCallback,\n", + " setup_trackio,\n", + ")\n", + "from ray.train import RunConfig, ScalingConfig\n", + "from ray.train.torch import TorchTrainer\n", + "\n", + "PROJECT_NAME = \"trackio-ray-example\"\n", + "\n", + "HF_DATASET_ID = \"hfusername/your_dataset_name\"\n", + "HF_SPACE_ID = \"hfusername/your_space_name\"\n", + "\n", + "NUM_STEPS = 15" + ] }, { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "## Tracking Ray Tune Experiments with Trackio\n", + "\n", + "This example demonstrates how to integrate Trackio with Ray Tune using `TrackioLoggerCallback`. The callback automatically captures:\n", + "\n", + "- Metrics reported via `tune.report`\n", + "- GPU utilization and system telemetry\n", + "- Trial configuration and metadata\n", + "\n", + "All trials are logged under a single project, enabling structured comparison across hyperparameter configurations. Results can be persisted to a dataset or space for analysis and sharing with the community." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def tune_trainable(config):\n", + "\n", + " for step in range(NUM_STEPS):\n", + "\n", + " loss = (config[\"lr\"] * 10) / (step + 1) + random.random()\n", + " accuracy = 1 / (loss + 1e-3)\n", + "\n", + " # Example artifact\n", + " image = np.random.rand(64, 64, 3)\n", + "\n", + " tune.report(\n", + " {\n", + " \"loss\": loss,\n", + " \"accuracy\": accuracy,\n", + " \"image_mean\": float(image.mean()),\n", + " \"step\": step,\n", + " }\n", + " )\n", + "\n", + " time.sleep(0.2)" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "def run_tune_example():\n", + "\n", + " tuner = tune.Tuner(\n", + " tune_trainable,\n", + " param_space={\n", + " \"lr\": tune.grid_search([0.001, 0.01, 0.1]),\n", + " },\n", + " run_config=tune.RunConfig(\n", + " name=\"trackio-ray-tune-demo\",\n", + " callbacks=[\n", + " TrackioLoggerCallback(\n", + " project=PROJECT_NAME,\n", + " auto_log_gpu=True,\n", + " gpu_log_interval=5,\n", + " dataset_id=HF_DATASET_ID,\n", + " space_id=HF_SPACE_ID,\n", + " )\n", + " ],\n", + " ),\n", + " )\n", + "\n", + " results = tuner.fit()\n", + "\n", + " print(\"\\nTune finished\\n\")\n", + " print(results)" + ] }, { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "## Applying Ray Train with Trackio\n", + "\n", + "This example demonstrates how to integrate Trackio with Ray Train using setup_trackio, enabling manual logging within a training loop.\n", + "\n", + "Here, we simulate the training loop which logs the scalar metrics such as loss and throughput\n", + "Step-wise progress for time-series tracking\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def train_loop(config):\n", + "\n", + " run = setup_trackio(\n", + " config=config,\n", + " project=PROJECT_NAME,\n", + " auto_log_gpu=True,\n", + " gpu_log_interval=5,\n", + " dataset_id=HF_DATASET_ID,\n", + " space_id=HF_SPACE_ID,\n", + " )\n", + "\n", + " for step in range(NUM_STEPS):\n", + "\n", + " loss = 5 / (step + 1) + random.random()\n", + " throughput = random.uniform(50, 150)\n", + "\n", + " if run:\n", + " run.log(\n", + " {\n", + " \"loss\": loss,\n", + " \"throughput\": throughput,\n", + " \"step\": step,\n", + " },\n", + " step=step,\n", + " )\n", + "\n", + " sample_image = np.random.rand(64, 64, 3)\n", + "\n", + " if run:\n", + " run.log(\n", + " {\n", + " \"image_mean\": float(sample_image.mean()),\n", + " \"image_std\": float(sample_image.std()),\n", + " }\n", + " )\n", + "\n", + " time.sleep(0.2)\n", + "\n", + " if run:\n", + " run.finish()" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "def run_train_example():\n", + "\n", + " trainer = TorchTrainer(\n", + " train_loop_per_worker=train_loop,\n", + " train_loop_config={\"lr\": 0.01},\n", + " scaling_config=ScalingConfig(num_workers=1),\n", + " run_config=RunConfig(name=\"trackio-ray-train-demo\"),\n", + " )\n", + "\n", + " trainer.fit()" + ] }, { "cell_type": "markdown", "metadata": {}, - "source": [] + "source": [ + "## Execute the example\n", + "\n" + ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "ray.init()\n", + "\n", + "print(\"\\nRunning Ray Tune experiment\\n\")\n", + "run_tune_example()\n", + "\n", + "print(\"\\nRunning Ray Train experiment\\n\")\n", + "run_train_example()\n", + "\n", + "print(\"\\nOpening dashboard\\n\")\n", + "print(\"Run manually if needed:\")\n", + "print('trackio show --project \"trackio-ray-demo\"')\n", + "\n", + "trackio.finish()\n", + "ray.shutdown()\n", + "\n", + "print(\"\\nExecution completed\\n\")" + ] } ], "metadata": { From e2c1caf5bae6503e535acf9ba4a54b0e66210f24 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Sat, 28 Mar 2026 06:35:43 +0000 Subject: [PATCH 16/26] add executed notebook with all the cells Signed-off-by: Parag Ekbote --- doc/source/tune/examples/tune_trackio.ipynb | 244 ++++++++++++++++++-- 1 file changed, 223 insertions(+), 21 deletions(-) diff --git a/doc/source/tune/examples/tune_trackio.ipynb b/doc/source/tune/examples/tune_trackio.ipynb index 98bb3f986421..61914439e2e7 100644 --- a/doc/source/tune/examples/tune_trackio.ipynb +++ b/doc/source/tune/examples/tune_trackio.ipynb @@ -52,19 +52,9 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mThe kernel failed to start due to the missing module 'packaging'. Consider installing this module.\n", - "\u001b[1;31mClick here for more info." - ] - } - ], + "outputs": [], "source": [ "import random\n", "import time\n", @@ -83,8 +73,8 @@ "\n", "PROJECT_NAME = \"trackio-ray-example\"\n", "\n", - "HF_DATASET_ID = \"hfusername/your_dataset_name\"\n", - "HF_SPACE_ID = \"hfusername/your_space_name\"\n", + "HF_DATASET_ID = \"AINovice2005/ray-trackio-experiments\"\n", + "HF_SPACE_ID = \"AINovice2005/ray-trackio-dashboard\"\n", "\n", "NUM_STEPS = 15" ] @@ -106,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -134,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -180,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -228,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ @@ -254,11 +244,223 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "

\n", + "
\n", + "
\n", + "

Tune Status

\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
Current time:2026-03-28 06:33:09
Running for: 00:00:06.39
Memory: 6.7/15.6 GiB
\n", + "
\n", + "
\n", + "
\n", + "

System Info

\n", + " Using FIFO scheduling algorithm.
Logical resource usage: 2.0/4 CPUs, 0/0 GPUs\n", + "
\n", + " \n", + "
\n", + "
\n", + "
\n", + "

Trial Status

\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
Trial name status loc lr iter total time (s) loss accuracy image_mean
tune_trainable_f8e3d_00000TERMINATED10.128.0.146:1631170.001 15 2.824320.234139 4.25281 0.499365
tune_trainable_f8e3d_00001TERMINATED10.128.0.146:1631160.01 15 2.820960.0522363 18.7842 0.499338
tune_trainable_f8e3d_00002TERMINATED10.128.0.146:1631150.1 15 2.831490.395104 2.52459 0.500149
\n", + "
\n", + "
\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Trackio project initialized: trackio-ray-example\n", + "* Trackio metrics will be synced to Hugging Face Dataset: AINovice2005/ray-trackio-experiments\n", + "* Found existing space: https://huggingface.co/spaces/AINovice2005/ray-trackio-dashboard\n", + "* View dashboard by going to: https://AINovice2005-ray-trackio-dashboard.hf.space/\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-28 06:33:06,305\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'checkpoint_dir_name' (type=NoneType). Only int/float supported.\n", + "2026-03-28 06:33:06,306\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'trial_id' (type=str). Only int/float supported.\n", + "2026-03-28 06:33:06,307\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'date' (type=str). Only int/float supported.\n", + "2026-03-28 06:33:06,308\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'hostname' (type=str). Only int/float supported.\n", + "2026-03-28 06:33:06,309\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'node_ip' (type=str). Only int/float supported.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Created new run: tune_trainable_f8e3d_00002\n", + "* Created new run: tune_trainable_f8e3d_00001\n", + "* Created new run: tune_trainable_f8e3d_00000\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:608: UserWarning: Reserved keys renamed: ['step', 'timestamp'] → '__{key}'\n", + " warnings.warn(f\"Reserved keys renamed: {renamed_keys} → '__{{key}}'\")\n", + "/teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:735: UserWarning: * Some logs could not be sent to the Space (it may still be starting up). They have been saved locally and will be sent automatically next time you call: trackio.init(project=\"trackio-ray-example\", space_id=\"AINovice2005/ray-trackio-dashboard\")\n", + " warnings.warn(\n", + "2026-03-28 06:33:09,455\tINFO tune.py:1001 -- Wrote the latest version of all result files and experiment state to '/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo' in 0.0169s.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Run finished. Uploading logs to Trackio Space (please wait...)\n", + "* Run finished. Uploading logs to Trackio Space (please wait...)\n", + "* Run finished. Uploading logs to Trackio Space (please wait...)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-28 06:33:09,472\tINFO tune.py:1033 -- Total run time: 6.42 seconds (6.37 seconds for the tuning loop).\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Run finished. Uploading logs to Trackio Space (please wait...)\n", + "\n", + "Tune finished\n", + "\n", + "ResultGrid<[\n", + " Result(\n", + " metrics={'loss': 0.23413880737172652, 'accuracy': 4.252807144756496, 'image_mean': 0.4993654140354737, 'step': 14},\n", + " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_f8e3d_00000_0_lr=0.0010_2026-03-28_06-33-03',\n", + " filesystem='local',\n", + " checkpoint=None\n", + " ),\n", + " Result(\n", + " metrics={'loss': 0.05223626356840479, 'accuracy': 18.784188313950164, 'image_mean': 0.4993381312907767, 'step': 14},\n", + " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_f8e3d_00001_1_lr=0.0100_2026-03-28_06-33-03',\n", + " filesystem='local',\n", + " checkpoint=None\n", + " ),\n", + " Result(\n", + " metrics={'loss': 0.39510361260059845, 'accuracy': 2.52459197085972, 'image_mean': 0.5001492248008005, 'step': 14},\n", + " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_f8e3d_00002_2_lr=0.1000_2026-03-28_06-33-03',\n", + " filesystem='local',\n", + " checkpoint=None\n", + " )\n", + "]>\n", + "\n", + "Running Ray Train experiment\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[36m(TrainController pid=163866)\u001b[0m Requesting resources: {'CPU': 1} * 1\n", + "\u001b[36m(TrainController pid=163866)\u001b[0m Attempting to start training worker group of size 1 with the following resources: [{'CPU': 1}] * 1\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m Setting up process group for: env:// [rank=0, world_size=1]\n", + "\u001b[36m(TrainController pid=163866)\u001b[0m Started training worker group of size 1: \n", + "\u001b[36m(TrainController pid=163866)\u001b[0m - (ip=10.128.0.146, pid=164541) world_rank=0, local_rank=0, node_rank=0\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Trackio project initialized: trackio-ray-example\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Trackio metrics will be synced to Hugging Face Dataset: AINovice2005/ray-trackio-experiments\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Found existing space: https://huggingface.co/spaces/AINovice2005/ray-trackio-dashboard\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * View dashboard by going to: https://AINovice2005-ray-trackio-dashboard.hf.space/\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Created new run: AINovice2005-1774679604\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m /teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:608: UserWarning: Reserved keys renamed: ['step'] → '__{key}'\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m warnings.warn(f\"Reserved keys renamed: {renamed_keys} → '__{{key}}'\")\n", + "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Run finished. Uploading logs to Trackio Space (please wait...)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Opening dashboard\n", + "\n", + "Run manually if needed:\n", + "trackio show --project \"trackio-ray-demo\"\n", + "* Run finished. Uploading logs to Trackio Space (please wait...)\n", + "\n", + "Execution completed\n", + "\n" + ] + } + ], "source": [ - "ray.init()\n", + "ray.init(ignore_reinit_error=True)\n", "\n", "print(\"\\nRunning Ray Tune experiment\\n\")\n", "run_tune_example()\n", From 562a4ca8ef36ae839052db6cfa4dbd944f7c8676 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Sat, 28 Mar 2026 07:53:35 +0000 Subject: [PATCH 17/26] add ref to doc pages Signed-off-by: Parag Ekbote --- doc/source/tune/api/logging.rst | 13 +++++++++++++ doc/source/tune/examples/index.rst | 1 + 2 files changed, 14 insertions(+) diff --git a/doc/source/tune/api/logging.rst b/doc/source/tune/api/logging.rst index 2ef841929056..3c9b0018ae38 100644 --- a/doc/source/tune/api/logging.rst +++ b/doc/source/tune/api/logging.rst @@ -92,6 +92,19 @@ See the :doc:`tutorial here `. ~air.integrations.comet.CometLoggerCallback +Trackio Integration +------------------------------ + +Tune also provides a logger for `Trackio `_. +You can install Trackio via ``pip install trackio``. +See the :doc:`tutorial here `. + +.. autosummary:: + :nosignatures: + :toctree: doc/ + + ~air.integrations.trackio.TrackioLoggerCallback + Aim Integration --------------- diff --git a/doc/source/tune/examples/index.rst b/doc/source/tune/examples/index.rst index 075e5fe20ac8..7e6a0892e012 100644 --- a/doc/source/tune/examples/index.rst +++ b/doc/source/tune/examples/index.rst @@ -59,6 +59,7 @@ Experiment tracking tools MLflow Example Aim Example Comet Example + Trackio Example Ray Tune integrates with some popular Experiment tracking and management tools, such as CometML, or Weights & Biases. For how From 1dd93d47bc8bb2b949dd16ad12cd0efa6250ab20 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Sat, 28 Mar 2026 08:15:00 +0000 Subject: [PATCH 18/26] rename as per notebook convention Signed-off-by: Parag Ekbote --- ...{tune_trackio.ipynb => tune-trackio.ipynb} | 104 ++++++++++-------- 1 file changed, 57 insertions(+), 47 deletions(-) rename doc/source/tune/examples/{tune_trackio.ipynb => tune-trackio.ipynb} (72%) diff --git a/doc/source/tune/examples/tune_trackio.ipynb b/doc/source/tune/examples/tune-trackio.ipynb similarity index 72% rename from doc/source/tune/examples/tune_trackio.ipynb rename to doc/source/tune/examples/tune-trackio.ipynb index 61914439e2e7..7fb4e01cc37c 100644 --- a/doc/source/tune/examples/tune_trackio.ipynb +++ b/doc/source/tune/examples/tune-trackio.ipynb @@ -52,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -96,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -124,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -170,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -218,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -244,7 +244,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -256,16 +256,16 @@ "

Tune Status

\n", " \n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "
Current time:2026-03-28 06:33:09
Running for: 00:00:06.39
Memory: 6.7/15.6 GiB
Current time:2026-03-28 08:14:11
Running for: 00:00:07.66
Memory: 7.2/15.6 GiB
\n", " \n", "
\n", "
\n", "

System Info

\n", - " Using FIFO scheduling algorithm.
Logical resource usage: 2.0/4 CPUs, 0/0 GPUs\n", + " Using FIFO scheduling algorithm.
Logical resource usage: 3.0/4 CPUs, 0/0 GPUs\n", "
\n", " \n", " \n", @@ -274,12 +274,12 @@ "

Trial Status

\n", " \n", "\n", - "\n", + "\n", "\n", "\n", - "\n", - "\n", - "\n", + "\n", + "\n", + "\n", "\n", "
Trial name status loc lr iter total time (s) loss accuracy image_mean
Trial name status loc lr iter total time (s) loss accuracy image_mean
tune_trainable_f8e3d_00000TERMINATED10.128.0.146:1631170.001 15 2.824320.234139 4.25281 0.499365
tune_trainable_f8e3d_00001TERMINATED10.128.0.146:1631160.01 15 2.820960.0522363 18.7842 0.499338
tune_trainable_f8e3d_00002TERMINATED10.128.0.146:1631150.1 15 2.831490.395104 2.52459 0.500149
tune_trainable_15a2f_00000TERMINATED10.128.0.96:836220.001 15 2.815570.160352 6.19765 0.49986
tune_trainable_15a2f_00001TERMINATED10.128.0.96:836210.01 15 2.815530.564934 1.76699 0.502778
tune_trainable_15a2f_00002TERMINATED10.128.0.96:836200.1 15 2.820820.923933 1.08116 0.50249
\n", " \n", @@ -348,20 +348,20 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 06:33:06,305\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'checkpoint_dir_name' (type=NoneType). Only int/float supported.\n", - "2026-03-28 06:33:06,306\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'trial_id' (type=str). Only int/float supported.\n", - "2026-03-28 06:33:06,307\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'date' (type=str). Only int/float supported.\n", - "2026-03-28 06:33:06,308\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'hostname' (type=str). Only int/float supported.\n", - "2026-03-28 06:33:06,309\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'node_ip' (type=str). Only int/float supported.\n" + "2026-03-28 08:14:07,714\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'checkpoint_dir_name' (type=NoneType). Only int/float supported.\n", + "2026-03-28 08:14:07,715\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'trial_id' (type=str). Only int/float supported.\n", + "2026-03-28 08:14:07,716\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'date' (type=str). Only int/float supported.\n", + "2026-03-28 08:14:07,718\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'hostname' (type=str). Only int/float supported.\n", + "2026-03-28 08:14:07,722\tWARNING trackio.py:286 -- trackio: Dropping unsupported metric 'node_ip' (type=str). Only int/float supported.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "* Created new run: tune_trainable_f8e3d_00002\n", - "* Created new run: tune_trainable_f8e3d_00001\n", - "* Created new run: tune_trainable_f8e3d_00000\n" + "* Created new run: tune_trainable_15a2f_00002\n", + "* Created new run: tune_trainable_15a2f_00000\n", + "* Created new run: tune_trainable_15a2f_00001\n" ] }, { @@ -369,17 +369,27 @@ "output_type": "stream", "text": [ "/teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:608: UserWarning: Reserved keys renamed: ['step', 'timestamp'] → '__{key}'\n", - " warnings.warn(f\"Reserved keys renamed: {renamed_keys} → '__{{key}}'\")\n", - "/teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:735: UserWarning: * Some logs could not be sent to the Space (it may still be starting up). They have been saved locally and will be sent automatically next time you call: trackio.init(project=\"trackio-ray-example\", space_id=\"AINovice2005/ray-trackio-dashboard\")\n", - " warnings.warn(\n", - "2026-03-28 06:33:09,455\tINFO tune.py:1001 -- Wrote the latest version of all result files and experiment state to '/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo' in 0.0169s.\n" + " warnings.warn(f\"Reserved keys renamed: {renamed_keys} → '__{{key}}'\")\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Run finished. Uploading logs to Trackio Space (please wait...)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-03-28 08:14:11,946\tINFO tune.py:1001 -- Wrote the latest version of all result files and experiment state to '/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo' in 0.0084s.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "* Run finished. Uploading logs to Trackio Space (please wait...)\n", "* Run finished. Uploading logs to Trackio Space (please wait...)\n", "* Run finished. Uploading logs to Trackio Space (please wait...)\n" ] @@ -388,7 +398,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2026-03-28 06:33:09,472\tINFO tune.py:1033 -- Total run time: 6.42 seconds (6.37 seconds for the tuning loop).\n" + "2026-03-28 08:14:11,964\tINFO tune.py:1033 -- Total run time: 7.73 seconds (7.65 seconds for the tuning loop).\n" ] }, { @@ -401,20 +411,20 @@ "\n", "ResultGrid<[\n", " Result(\n", - " metrics={'loss': 0.23413880737172652, 'accuracy': 4.252807144756496, 'image_mean': 0.4993654140354737, 'step': 14},\n", - " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_f8e3d_00000_0_lr=0.0010_2026-03-28_06-33-03',\n", + " metrics={'loss': 0.16035154682514471, 'accuracy': 6.197647433053068, 'image_mean': 0.4998603843744434, 'step': 14},\n", + " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_15a2f_00000_0_lr=0.0010_2026-03-28_08-14-04',\n", " filesystem='local',\n", " checkpoint=None\n", " ),\n", " Result(\n", - " metrics={'loss': 0.05223626356840479, 'accuracy': 18.784188313950164, 'image_mean': 0.4993381312907767, 'step': 14},\n", - " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_f8e3d_00001_1_lr=0.0100_2026-03-28_06-33-03',\n", + " metrics={'loss': 0.5649336419903179, 'accuracy': 1.7669916149234828, 'image_mean': 0.5027780010222311, 'step': 14},\n", + " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_15a2f_00001_1_lr=0.0100_2026-03-28_08-14-04',\n", " filesystem='local',\n", " checkpoint=None\n", " ),\n", " Result(\n", - " metrics={'loss': 0.39510361260059845, 'accuracy': 2.52459197085972, 'image_mean': 0.5001492248008005, 'step': 14},\n", - " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_f8e3d_00002_2_lr=0.1000_2026-03-28_06-33-03',\n", + " metrics={'loss': 0.9239329737032552, 'accuracy': 1.081159422824111, 'image_mean': 0.5024897968228581, 'step': 14},\n", + " path='/teamspace/studios/this_studio/ray_results/trackio-ray-tune-demo/tune_trainable_15a2f_00002_2_lr=0.1000_2026-03-28_08-14-04',\n", " filesystem='local',\n", " checkpoint=None\n", " )\n", @@ -428,19 +438,19 @@ "name": "stderr", "output_type": "stream", "text": [ - "\u001b[36m(TrainController pid=163866)\u001b[0m Requesting resources: {'CPU': 1} * 1\n", - "\u001b[36m(TrainController pid=163866)\u001b[0m Attempting to start training worker group of size 1 with the following resources: [{'CPU': 1}] * 1\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m Setting up process group for: env:// [rank=0, world_size=1]\n", - "\u001b[36m(TrainController pid=163866)\u001b[0m Started training worker group of size 1: \n", - "\u001b[36m(TrainController pid=163866)\u001b[0m - (ip=10.128.0.146, pid=164541) world_rank=0, local_rank=0, node_rank=0\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Trackio project initialized: trackio-ray-example\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Trackio metrics will be synced to Hugging Face Dataset: AINovice2005/ray-trackio-experiments\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Found existing space: https://huggingface.co/spaces/AINovice2005/ray-trackio-dashboard\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * View dashboard by going to: https://AINovice2005-ray-trackio-dashboard.hf.space/\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Created new run: AINovice2005-1774679604\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m /teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:608: UserWarning: Reserved keys renamed: ['step'] → '__{key}'\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m warnings.warn(f\"Reserved keys renamed: {renamed_keys} → '__{{key}}'\")\n", - "\u001b[36m(RayTrainWorker pid=164541)\u001b[0m * Run finished. Uploading logs to Trackio Space (please wait...)\n" + "\u001b[36m(TrainController pid=84397)\u001b[0m Requesting resources: {'CPU': 1} * 1\n", + "\u001b[36m(TrainController pid=84397)\u001b[0m Attempting to start training worker group of size 1 with the following resources: [{'CPU': 1}] * 1\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m Setting up process group for: env:// [rank=0, world_size=1]\n", + "\u001b[36m(TrainController pid=84397)\u001b[0m Started training worker group of size 1: \n", + "\u001b[36m(TrainController pid=84397)\u001b[0m - (ip=10.128.0.96, pid=85069) world_rank=0, local_rank=0, node_rank=0\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m * Trackio project initialized: trackio-ray-example\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m * Trackio metrics will be synced to Hugging Face Dataset: AINovice2005/ray-trackio-experiments\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m * Found existing space: https://huggingface.co/spaces/AINovice2005/ray-trackio-dashboard\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m * View dashboard by going to: https://AINovice2005-ray-trackio-dashboard.hf.space/\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m * Created new run: AINovice2005-1774685667\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m /teamspace/studios/this_studio/ray/.venv/lib/python3.12/site-packages/trackio/run.py:608: UserWarning: Reserved keys renamed: ['step'] → '__{key}'\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m warnings.warn(f\"Reserved keys renamed: {renamed_keys} → '__{{key}}'\")\n", + "\u001b[36m(RayTrainWorker pid=85069)\u001b[0m * Run finished. Uploading logs to Trackio Space (please wait...)\n" ] }, { From 38e19080440607d3ee741b1dfa60ccb2b26e37af Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Mon, 30 Mar 2026 16:47:51 +0000 Subject: [PATCH 19/26] update as per reviewer comments Signed-off-by: Parag Ekbote --- doc/source/tune/examples/tune-trackio.ipynb | 5 ++--- python/ray/air/BUILD.bazel | 2 +- python/requirements/ml/core-requirements.txt | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/source/tune/examples/tune-trackio.ipynb b/doc/source/tune/examples/tune-trackio.ipynb index 7fb4e01cc37c..3434c88522e6 100644 --- a/doc/source/tune/examples/tune-trackio.ipynb +++ b/doc/source/tune/examples/tune-trackio.ipynb @@ -11,7 +11,6 @@ "\n", "

\n", "\n", - "(tune-trackio-ref)=\n", "\n", "[Trackio](https://huggingface.co/docs/trackio/index) is a open-source, lightweight, free experiment tracking \n", "Python library built on top of Hugging Face Datasets and Spaces 🤗. It has a local first design and the experiments can be viewed with a Gradio dashboard locally or on the HF Hub\n", @@ -24,10 +23,10 @@ "```\n", "\n", "Ray Tune currently offers two lightweight integrations for Weights & Biases.\n", - "One is the {ref}`TrackioLoggerCallback `, which automatically logs\n", + "One is the `TrackioLoggerCallback`, which automatically logs\n", "metrics reported to Tune to the Wandb API.\n", "\n", - "The other one is the {ref}`setup_trackio() ` function, which can be\n", + "The other one is the `setup_trackio()` function, which can be\n", "used with the function API. It automatically\n", "initializes the Wandb API with Tune's training information. You can just use the\n", "Wandb API like you would normally do, e.g. using `wandb.log()` to log your training\n", diff --git a/python/ray/air/BUILD.bazel b/python/ray/air/BUILD.bazel index df7da53c50a1..818a27afe847 100644 --- a/python/ray/air/BUILD.bazel +++ b/python/ray/air/BUILD.bazel @@ -125,7 +125,7 @@ py_test( size = "small", srcs = ["tests/test_integration_trackio.py"], # NOTE: This tests the Tune Trackio callback. - env = {"RAY_TRAIN_V2_ENABLED": "0"}, + env = {"RAY_TRAIN_V2_ENABLED": "1"}, tags = [ "exclusive", "team:ml", diff --git a/python/requirements/ml/core-requirements.txt b/python/requirements/ml/core-requirements.txt index 436b2b340e8f..fd3721a6d107 100644 --- a/python/requirements/ml/core-requirements.txt +++ b/python/requirements/ml/core-requirements.txt @@ -2,7 +2,7 @@ comet-ml==3.44.1 mlflow>=2.22.0 wandb>=0.23.1 -trackio +trackio<1.0 # ML training frameworks xgboost==2.1.0 From e70787b467e7e12a6536579e34f0b76eee03d93f Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Thu, 2 Apr 2026 06:58:13 +0000 Subject: [PATCH 20/26] Signed-off-by: Parag Ekbote update dep. --- python/requirements/ml/core-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/python/requirements/ml/core-requirements.txt b/python/requirements/ml/core-requirements.txt index fd3721a6d107..ba6b9bfc22a4 100644 --- a/python/requirements/ml/core-requirements.txt +++ b/python/requirements/ml/core-requirements.txt @@ -3,6 +3,7 @@ comet-ml==3.44.1 mlflow>=2.22.0 wandb>=0.23.1 trackio<1.0 +gradio>=6.8.0,<7.0.0 #gradio dep bump for trackio # ML training frameworks xgboost==2.1.0 From 2e2decce2c5d1325c06f4ddff5f68a2dba573876 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Thu, 2 Apr 2026 07:39:49 +0000 Subject: [PATCH 21/26] update gradio dep for trackio Signed-off-by: Parag Ekbote --- python/requirements/test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/requirements/test-requirements.txt b/python/requirements/test-requirements.txt index a51f890bf18a..fa46ddc06838 100644 --- a/python/requirements/test-requirements.txt +++ b/python/requirements/test-requirements.txt @@ -23,7 +23,7 @@ flask==2.1.3 freezegun==1.1.0 google-api-python-client==2.111.0 google-cloud-storage==2.14.0 -gradio==3.50.2; platform_system != "Windows" +gradio>=6.8.0,<7.0.0; platform_system != "Windows" graphviz==0.20.3 websockets==11.0.3 joblib==1.2.0 From 4c09e0b9ffcd40a2e4e802a04c95ca9d052b0ac0 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Wed, 22 Apr 2026 15:15:06 +0000 Subject: [PATCH 22/26] rm gradio test bump Signed-off-by: Parag Ekbote --- python/requirements/ml/core-requirements.txt | 1 - python/requirements/test-requirements.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/python/requirements/ml/core-requirements.txt b/python/requirements/ml/core-requirements.txt index ba6b9bfc22a4..fd3721a6d107 100644 --- a/python/requirements/ml/core-requirements.txt +++ b/python/requirements/ml/core-requirements.txt @@ -3,7 +3,6 @@ comet-ml==3.44.1 mlflow>=2.22.0 wandb>=0.23.1 trackio<1.0 -gradio>=6.8.0,<7.0.0 #gradio dep bump for trackio # ML training frameworks xgboost==2.1.0 diff --git a/python/requirements/test-requirements.txt b/python/requirements/test-requirements.txt index fa46ddc06838..a51f890bf18a 100644 --- a/python/requirements/test-requirements.txt +++ b/python/requirements/test-requirements.txt @@ -23,7 +23,7 @@ flask==2.1.3 freezegun==1.1.0 google-api-python-client==2.111.0 google-cloud-storage==2.14.0 -gradio>=6.8.0,<7.0.0; platform_system != "Windows" +gradio==3.50.2; platform_system != "Windows" graphviz==0.20.3 websockets==11.0.3 joblib==1.2.0 From d49c08e7ecd1282b30348ee3253c0ea7b0724c2d Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Tue, 19 May 2026 13:15:59 +0000 Subject: [PATCH 23/26] update deps Signed-off-by: Parag Ekbote --- python/requirements/ml/core-requirements.txt | 2 +- python/requirements_compiled.txt | 2 +- python/requirements_compiled_py3.13.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python/requirements/ml/core-requirements.txt b/python/requirements/ml/core-requirements.txt index fd3721a6d107..55283f2a7ec0 100644 --- a/python/requirements/ml/core-requirements.txt +++ b/python/requirements/ml/core-requirements.txt @@ -2,7 +2,7 @@ comet-ml==3.44.1 mlflow>=2.22.0 wandb>=0.23.1 -trackio<1.0 +trackio==0.25.1 # ML training frameworks xgboost==2.1.0 diff --git a/python/requirements_compiled.txt b/python/requirements_compiled.txt index b43c043ed01e..31aa3d745b57 100644 --- a/python/requirements_compiled.txt +++ b/python/requirements_compiled.txt @@ -704,7 +704,7 @@ gpytorch==1.15.2 # via botorch gradio==3.50.2 ; platform_system != "Windows" # via -r python/requirements/test-requirements.txt -gradio-client==0.6.1 +gradio-client==2.0.0 # via gradio graphemeu==0.7.2 # via alive-progress diff --git a/python/requirements_compiled_py3.13.txt b/python/requirements_compiled_py3.13.txt index 1700a9425a9e..8d689796bce9 100644 --- a/python/requirements_compiled_py3.13.txt +++ b/python/requirements_compiled_py3.13.txt @@ -713,7 +713,7 @@ gpytorch==1.15.2 # via botorch gradio==5.50.0 ; platform_system != "Windows" # via -r python/requirements/py313/test-requirements.txt -gradio-client==1.14.0 +gradio-client==2.0.0 # via gradio graphemeu==0.7.2 # via alive-progress From f709eadce904c4af3f3b4a70f13e02d17239ba7f Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Tue, 19 May 2026 13:43:35 +0000 Subject: [PATCH 24/26] update deps Signed-off-by: Parag Ekbote --- python/requirements_compiled.txt | 2 +- python/requirements_compiled_py3.13.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/requirements_compiled.txt b/python/requirements_compiled.txt index 31aa3d745b57..b43c043ed01e 100644 --- a/python/requirements_compiled.txt +++ b/python/requirements_compiled.txt @@ -704,7 +704,7 @@ gpytorch==1.15.2 # via botorch gradio==3.50.2 ; platform_system != "Windows" # via -r python/requirements/test-requirements.txt -gradio-client==2.0.0 +gradio-client==0.6.1 # via gradio graphemeu==0.7.2 # via alive-progress diff --git a/python/requirements_compiled_py3.13.txt b/python/requirements_compiled_py3.13.txt index 8d689796bce9..f4fd7f79ccf6 100644 --- a/python/requirements_compiled_py3.13.txt +++ b/python/requirements_compiled_py3.13.txt @@ -713,7 +713,7 @@ gpytorch==1.15.2 # via botorch gradio==5.50.0 ; platform_system != "Windows" # via -r python/requirements/py313/test-requirements.txt -gradio-client==2.0.0 +gradio-client==1.4.0 # via gradio graphemeu==0.7.2 # via alive-progress From 4e370f60aaa3229815eb70a0eb01773b50b1d9e9 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Tue, 19 May 2026 13:48:39 +0000 Subject: [PATCH 25/26] update deps Signed-off-by: Parag Ekbote --- python/requirements_compiled.txt | 4 +++- python/requirements_compiled_py3.13.txt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/python/requirements_compiled.txt b/python/requirements_compiled.txt index 1b3744387391..e54a77dbb4c2 100644 --- a/python/requirements_compiled.txt +++ b/python/requirements_compiled.txt @@ -706,7 +706,9 @@ googleapis-common-protos==1.61.0 gpytorch==1.15.2 # via botorch gradio==3.50.2 ; platform_system != "Windows" - # via -r python/requirements/test-requirements.txt + # via + # -r python/requirements/serve/serve-test-requirements.txt + # -r python/requirements/test-requirements.txt gradio-client==0.6.1 # via gradio graphemeu==0.7.2 diff --git a/python/requirements_compiled_py3.13.txt b/python/requirements_compiled_py3.13.txt index c9eb6815ce20..b684d565f575 100644 --- a/python/requirements_compiled_py3.13.txt +++ b/python/requirements_compiled_py3.13.txt @@ -715,7 +715,9 @@ googleapis-common-protos==1.74.0 gpytorch==1.15.2 # via botorch gradio==5.50.0 ; platform_system != "Windows" - # via -r python/requirements/py313/test-requirements.txt + # via + # -r python/requirements/py313/test-requirements.txt + # -r python/requirements/serve/serve-test-requirements.txt gradio-client==1.4.0 # via gradio graphemeu==0.7.2 From 5815cde26014781cc09e3f1515e48926164997e9 Mon Sep 17 00:00:00 2001 From: Parag Ekbote Date: Tue, 19 May 2026 13:50:15 +0000 Subject: [PATCH 26/26] update deps Signed-off-by: Parag Ekbote --- python/requirements_compiled_py3.13.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/requirements_compiled_py3.13.txt b/python/requirements_compiled_py3.13.txt index b684d565f575..b076dd295b8e 100644 --- a/python/requirements_compiled_py3.13.txt +++ b/python/requirements_compiled_py3.13.txt @@ -718,7 +718,7 @@ gradio==5.50.0 ; platform_system != "Windows" # via # -r python/requirements/py313/test-requirements.txt # -r python/requirements/serve/serve-test-requirements.txt -gradio-client==1.4.0 +gradio-client==1.14.0 # via gradio graphemeu==0.7.2 # via alive-progress