Skip to content

Commit 71c7ea9

Browse files
Merge pull request #3053 from Zephyr271828:wandb
PiperOrigin-RevId: 947955108
2 parents fa79905 + c4f751e commit 71c7ea9

4 files changed

Lines changed: 57 additions & 0 deletions

File tree

src/maxtext/common/metric_logger.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ def __init__(self, config, learning_rate_schedule):
111111
if self.config.managed_mldiagnostics:
112112
ManagedMLDiagnostics(config) # Initialize the MLRun instance.
113113

114+
if self.config.enable_wandb and jax.process_index() == 0:
115+
import wandb # pylint: disable=import-outside-toplevel # pytype: disable=import-error # lazy import: wandb is an optional dependency
116+
117+
wandb.init(
118+
project=config.wandb_project_name,
119+
name=config.wandb_run_name,
120+
resume="allow",
121+
) # Initialize wandb logger.
122+
114123
def reset_eval_metrics(self):
115124
"""Resets the cumulative metrics dictionary for a new evaluation run."""
116125
self.cumulative_eval_metrics = {"scalar": defaultdict(float)}
@@ -133,6 +142,9 @@ def write_metrics(self, metrics, step, metric_type="train"):
133142
if self.config.managed_mldiagnostics:
134143
self.write_metrics_to_managed_mldiagnostics(metrics, step)
135144

145+
if self.config.enable_wandb and jax.process_index() == 0:
146+
self.write_metrics_to_wandb(metrics, step)
147+
136148
if metric_type == "train":
137149
self._maybe_abort_after_write_metrics(metrics)
138150

@@ -333,6 +345,18 @@ def write_metrics_to_managed_mldiagnostics(self, metrics, step):
333345
mapped_metric_name = _METRICS_TO_MANAGED.get(metric_name, metric_name)
334346
mldiag.metrics.record(mapped_metric_name, value, step=int(step))
335347

348+
def write_metrics_to_wandb(self, metrics, step):
349+
"""Write metrics to weights and biases (wandb)."""
350+
import wandb # pylint: disable=import-outside-toplevel # pytype: disable=import-error # lazy import: wandb is an optional dependency
351+
352+
flat_metrics = {}
353+
for key, val in metrics.get("scalar", {}).items():
354+
flat_metrics[key] = float(val)
355+
for key, val in metrics.get("scalars", {}).items():
356+
for subkey, subval in val.items():
357+
flat_metrics[f"{key}/{subkey}"] = float(subval)
358+
wandb.log(flat_metrics, step=step)
359+
336360
def write_setup_info_to_tensorboard(self, params):
337361
"""Writes setup information like train config params, num model params, and XLA flags to TensorBoard."""
338362
num_model_parameters = max_utils.calculate_num_params_from_pytree(params)

src/maxtext/configs/base.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ metrics_file: "" # for testing, local file that stores scalar metrics. if empty,
101101
# if true save metrics such as loss and tflops to gcs in {base_output_directory}/{run_name}/metrics/
102102
gcs_metrics: false
103103

104+
enable_wandb: False
105+
wandb_project_name: "maxtext"
106+
wandb_run_name: ""
107+
104108
# if true save config to gcs in {base_output_directory}/{run_name}/
105109
save_config_to_gcs: false
106110

src/maxtext/configs/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,9 @@ class Metrics(BaseModel):
19201920
False,
19211921
description="Whether to enable Tunix-managed metrics measurement. The metrics will be uploaded to tensorboard.",
19221922
)
1923+
enable_wandb: bool = Field(False, description="Enable Weights & Biases logging.")
1924+
wandb_project_name: str = Field("maxtext", description="Weights & Biases project name.")
1925+
wandb_run_name: str = Field("", description="Weights & Biases run name. If empty, a default name is generated.")
19231926

19241927

19251928
class ManagedMLDiagnostics(BaseModel):

tests/unit/metric_logger_abort_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def _make_logger(self, abort_on_nan_loss, abort_on_inf_loss):
3636
metrics_file="/tmp/fake_metrics.jsonl",
3737
gcs_metrics=True,
3838
managed_mldiagnostics=True,
39+
enable_wandb=False,
3940
)
4041
return logger
4142

@@ -99,6 +100,31 @@ def test_abort_flags_disabled_does_not_exit(self):
99100
logger.write_metrics(self._metrics(np.nan), step=1, metric_type="train")
100101

101102

103+
class MetricLoggerWandbTest(unittest.TestCase):
104+
"""Tests for MetricLogger wandb metric writing."""
105+
106+
def test_write_metrics_to_wandb_flattens_scalars_and_scalars(self):
107+
logger = MetricLogger.__new__(MetricLogger) # skip __init__
108+
metrics = {
109+
"scalar": {"learning/loss": 1.5},
110+
"scalars": {"perf": {"step_time": 0.25, "tflops_per_device": 100.0}},
111+
}
112+
113+
fake_wandb = mock.MagicMock()
114+
# wandb is lazily imported inside write_metrics_to_wandb, so inject a fake module.
115+
with mock.patch.dict("sys.modules", {"wandb": fake_wandb}):
116+
logger.write_metrics_to_wandb(metrics, step=7)
117+
118+
fake_wandb.log.assert_called_once_with(
119+
{
120+
"learning/loss": 1.5,
121+
"perf/step_time": 0.25,
122+
"perf/tflops_per_device": 100.0,
123+
},
124+
step=7,
125+
)
126+
127+
102128
class MetricLoggerMetadataTest(unittest.TestCase):
103129
"""Tests for MetricLogger metadata and setup initialization."""
104130

0 commit comments

Comments
 (0)