Skip to content

Commit 7151573

Browse files
Merge pull request AI-Hypercomputer#4252 from AI-Hypercomputer:sanbao/gpt
PiperOrigin-RevId: 940703754
2 parents 7538cd4 + c926b99 commit 7151573

7 files changed

Lines changed: 49 additions & 131 deletions

File tree

src/maxtext/common/goodput.py

Lines changed: 17 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -66,31 +66,18 @@ def maybe_monitor_goodput(config):
6666
enable_gcp_goodput_metrics=config.enable_gcp_goodput_metrics,
6767
enable_gcp_step_deviation_metrics=config.enable_gcp_step_deviation_metrics,
6868
)
69-
monitor_class = monitoring.GoodputMonitor
70-
71-
if config.elastic_enabled:
72-
try:
73-
from ml_goodput_measurement import monitoring_elastic # pylint: disable=import-outside-toplevel
74-
75-
monitor_class = monitoring_elastic.ElasticGoodputMonitor
76-
except ImportError:
77-
max_logging.log("Elastic monitor failed!")
78-
79-
kwargs = {
80-
"job_name": config.run_name,
81-
"logger_name": f"goodput_{config.run_name}",
82-
"tensorboard_dir": config.tensorboard_dir,
83-
"upload_interval": config.goodput_upload_interval_seconds,
84-
"monitoring_enabled": True,
85-
"include_badput_breakdown": True,
86-
"include_step_deviation": config.monitor_step_time_deviation,
87-
"step_deviation_interval_seconds": config.step_deviation_interval_seconds,
88-
"gcp_options": gcp_options,
89-
}
90-
if monitor_class == monitoring.GoodputMonitor:
91-
kwargs["pathway_enabled"] = config.enable_pathways_goodput
92-
93-
goodput_monitor = monitor_class(**kwargs)
69+
goodput_monitor = monitoring.GoodputMonitor(
70+
job_name=config.run_name,
71+
logger_name=f"goodput_{config.run_name}",
72+
tensorboard_dir=config.tensorboard_dir,
73+
upload_interval=config.goodput_upload_interval_seconds,
74+
monitoring_enabled=True,
75+
pathway_enabled=config.enable_pathways_goodput,
76+
include_badput_breakdown=True,
77+
include_step_deviation=config.monitor_step_time_deviation,
78+
step_deviation_interval_seconds=config.step_deviation_interval_seconds,
79+
gcp_options=gcp_options,
80+
)
9481
goodput_monitor.start_goodput_uploader()
9582
max_logging.log("Started Goodput upload to Tensorboard & GCM in the background!")
9683
yield
@@ -134,23 +121,8 @@ def create_goodput_recorder(config):
134121
if config.enable_goodput_recording and jax.process_index() == 0:
135122
max_logging.log("[GOODPUT NO-OP] recorder skipped (decoupled stub).")
136123
return None
137-
138-
if not config.enable_goodput_recording:
139-
return None
140-
141-
logger_name = f"goodput_{config.run_name}"
142-
143-
# Detect if we should use the elastic-aware recorder
144-
if config.elastic_enabled:
145-
try:
146-
from ml_goodput_measurement import goodput_elastic # pylint: disable=import-outside-toplevel
147-
from maxtext.utils import elastic_utils # pylint: disable=import-outside-toplevel
148-
149-
recorder = goodput_elastic.ElasticGoodputRecorder(config.run_name, logger_name, jax.process_index() == 0)
150-
elastic_utils.record_slice_state(recorder)
151-
except ImportError as e:
152-
max_logging.log(f"Could not create elastic goodput recorder: {e}")
153-
else:
154-
return recorder
155-
156-
return goodput.GoodputRecorder(config.run_name, logger_name, jax.process_index() == 0)
124+
if config.enable_goodput_recording:
125+
logger_name = f"goodput_{config.run_name}"
126+
recorder = goodput.GoodputRecorder(config.run_name, logger_name, jax.process_index() == 0)
127+
return recorder
128+
return None
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"SYSTEM_PROMPT": "You are given a problem. Think about the problem and provide your reasoning. Place it between {reasoning_start_token} and {reasoning_end_token}. Then, provide the final answer (i.e., just one numerical value) between {solution_start_token} and {solution_end_token}.",
3+
"TEMPLATE": "<|start|>system<|message|>You are ChatGPT, a large language model trained by OpenAI.\nKnowledge cutoff: 2024-06\nCurrent date: 2026-06-19\n\nReasoning: medium\n\n# Valid channels: analysis, commentary, final. Channel must be included for every message.\nCalls to these tools must go to the commentary channel: 'functions'.<|end|><|start|>user<|message|><start_of_turn>user\n{system_prompt}\n\n{question}<end_of_turn>\n<start_of_turn>model<|end|><|start|>assistant"
4+
}

src/maxtext/trainers/post_train/rl/math_verify_pool.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,9 @@ def math_verify_pool(
226226

227227
cpu_count = multiprocessing.cpu_count()
228228
if num_procs is None:
229-
num_procs = min(_DEFAULT_MAX_PROCS, len(items), cpu_count)
229+
num_procs = min(_DEFAULT_MAX_PROCS, cpu_count)
230230
else:
231-
num_procs = max(1, min(num_procs, len(items), cpu_count))
231+
num_procs = max(1, min(num_procs, cpu_count))
232232

233233
cnt = 0
234234
pool = _get_pool(num_procs)

src/maxtext/trainers/post_train/rl/train_rl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def _use_raw_prompt(x):
339339
dataset_size = int(trainer_config.num_batches * trainer_config.batch_size * trainer_config.train_fraction)
340340
train_dataset = train_dataset[:dataset_size]
341341
train_dataset = train_dataset.repeat(trainer_config.num_epoch)
342-
train_dataset = train_dataset.to_iter_dataset().batch(trainer_config.batch_size)
342+
train_dataset = train_dataset.to_iter_dataset().batch(trainer_config.batch_size, drop_remainder=True)
343343

344344
if trainer_config.num_test_batches > 0:
345345
# eval_batch_size = -1 (default) → use trainer_config.batch_size (legacy
@@ -358,7 +358,7 @@ def _use_raw_prompt(x):
358358
test_dataset = test_dataset[
359359
trainer_config.test_batch_start_index : trainer_config.num_test_batches * eval_batch_size_for_eval
360360
]
361-
test_dataset = test_dataset.to_iter_dataset().batch(eval_batch_size_for_eval)
361+
test_dataset = test_dataset.to_iter_dataset().batch(eval_batch_size_for_eval, drop_remainder=True)
362362

363363
return train_dataset, test_dataset
364364

src/maxtext/utils/elastic_utils.py

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,37 +28,13 @@
2828
pending_elastic_event_type = None
2929

3030

31-
def record_slice_state(recorder, active_slices_override: int | None = None) -> None:
32-
"""Records live slice counts and logs them to the GoodputRecorder."""
33-
if (
34-
recorder is None
35-
or not hasattr(recorder, "record_elastic_slice_counts")
36-
or not pathwaysutils.is_pathways_backend_used()
37-
or elastic_manager is None
38-
):
39-
return
40-
41-
available_slices = len(pathwaysutils.elastic.get_active_slice_indices())
42-
active_slices = (
43-
active_slices_override if active_slices_override is not None else len(elastic_manager.active_slice_indices)
44-
)
45-
total_slices = len(pathwaysutils.elastic.get_slice_to_devices(jax.devices()))
46-
47-
recorder.record_elastic_slice_counts(
48-
available_slices=available_slices,
49-
active_slices=active_slices,
50-
total_slices=total_slices,
51-
)
52-
53-
5431
def record_elastic_event_start(recorder, config) -> None:
5532
"""Records start of an elastic scale up event."""
5633
global pending_elastic_event_type
5734
event_type = "elastic_scale_up" if is_scale_up_event(config) else "elastic_slice_down"
5835
pending_elastic_event_type = event_type
5936
if recorder:
60-
recorder.record_elastic_wait_start_time(event_type=event_type)
61-
record_slice_state(recorder, active_slices_override=0)
37+
recorder.record_custom_badput_event_start_time(custom_badput_event_type=event_type)
6238

6339

6440
def record_elastic_wait_end_and_reinit_start(recorder) -> None:
@@ -69,18 +45,16 @@ def record_elastic_wait_end_and_reinit_start(recorder) -> None:
6945
event_type = pending_elastic_event_type
7046
pending_elastic_event_type = None
7147
if recorder:
72-
recorder.record_elastic_wait_end_time(event_type=event_type)
73-
recorder.record_elastic_reinit_start_time()
74-
record_slice_state(recorder)
48+
recorder.record_custom_badput_event_end_time(custom_badput_event_type=event_type)
49+
recorder.record_custom_badput_event_start_time(custom_badput_event_type="elastic_reinitialization")
7550
pending_reinit_recorder = recorder
7651

7752

7853
def record_elastic_reinit_end() -> None:
7954
"""Records end of elastic reinitialization event."""
8055
global pending_reinit_recorder
8156
if pending_reinit_recorder is not None:
82-
pending_reinit_recorder.record_elastic_reinit_end_time()
83-
record_slice_state(pending_reinit_recorder)
57+
pending_reinit_recorder.record_custom_badput_event_end_time(custom_badput_event_type="elastic_reinitialization")
8458
pending_reinit_recorder = None
8559

8660

tests/post_training/unit/train_rl_test.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ def get_filtered_data_side_effect(dataset_name, model_tokenizer, template_config
359359
data_shuffle_seed=42,
360360
max_prefill_predict_length=10,
361361
batch_size=2,
362+
eval_batch_size=1,
362363
num_batches=2,
363364
train_fraction=1.0,
364365
num_epoch=1,
@@ -422,7 +423,8 @@ def test_prepare_datasets_with_split(self, mock_load):
422423
data_template_path="maxtext/examples/chat_templates/gsm8k_rl.json",
423424
data_shuffle_seed=42,
424425
num_batches=1,
425-
batch_size=5,
426+
batch_size=2,
427+
eval_batch_size=1,
426428
train_fraction=1.0,
427429
num_epoch=1,
428430
num_test_batches=1,

tests/unit/elastic_utils_test.py

Lines changed: 17 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,6 @@ def setUp(self):
7070

7171
# Configure default behaviors if needed
7272
self.fake_pathwaysutils.is_pathways_backend_used.return_value = True
73-
self.fake_pathwaysutils.elastic = Mock()
74-
self.fake_pathwaysutils.elastic.get_active_slice_indices.return_value = [0, 1]
75-
self.fake_pathwaysutils.elastic.get_slice_to_devices.return_value = {
76-
0: [FakeDevice()],
77-
1: [FakeDevice()],
78-
}
7973
self.fake_jax.process_index.return_value = 0
8074

8175
# Inject fakes into elastic_utils namespace
@@ -103,28 +97,9 @@ def tearDown(self):
10397
elastic_utils.pending_elastic_event_type = None
10498
super().tearDown()
10599

106-
def test_record_slice_state(self):
107-
elastic_utils.elastic_manager = self.fake_manager
108-
self.fake_manager.active_slice_indices = {0}
109-
self.fake_manager.slice_to_devices = {0: [FakeDevice()], 1: [FakeDevice()]}
110-
self.fake_pathwaysutils.elastic.get_active_slice_indices.return_value = {0, 1}
111-
112-
fake_recorder = Mock()
113-
fake_recorder.record_elastic_slice_counts = Mock()
114-
115-
elastic_utils.record_slice_state(fake_recorder)
116-
117-
fake_recorder.record_elastic_slice_counts.assert_called_once_with(available_slices=2, active_slices=1, total_slices=2)
118-
119-
fake_recorder.record_elastic_slice_counts.reset_mock()
120-
elastic_utils.record_slice_state(fake_recorder, active_slices_override=0)
121-
fake_recorder.record_elastic_slice_counts.assert_called_once_with(available_slices=2, active_slices=0, total_slices=2)
122-
123100
def test_elastic_enabled(self):
124101
config = FakeConfig()
125102
self.fake_pathwaysutils.is_pathways_backend_used.return_value = True
126-
self.fake_pathwaysutils.elastic = Mock()
127-
self.fake_pathwaysutils.elastic.get_active_slice_indices.return_value = [0, 1]
128103
config.elastic_enabled = True
129104
self.assertTrue(elastic_utils.elastic_enabled(config))
130105

@@ -169,8 +144,6 @@ def test_live_devices_no_pathways(self):
169144
def test_live_devices_pathways(self):
170145
"""Tests live_devices when pathways is used."""
171146
self.fake_pathwaysutils.is_pathways_backend_used.return_value = True
172-
self.fake_pathwaysutils.elastic = Mock()
173-
self.fake_pathwaysutils.elastic.get_active_slice_indices.return_value = [0, 1]
174147
device0 = FakeDevice(slice_index=0)
175148
device1 = FakeDevice(slice_index=1)
176149
self.fake_jax.devices.return_value = [device0, device1]
@@ -195,8 +168,6 @@ def test_live_devices_disabled(self):
195168
def test_elastic_retry_disabled(self):
196169
"""Tests elastic_retry when disabled but pathways is used."""
197170
self.fake_pathwaysutils.is_pathways_backend_used.return_value = True
198-
self.fake_pathwaysutils.elastic = Mock()
199-
self.fake_pathwaysutils.elastic.get_active_slice_indices.return_value = [0, 1]
200171
config = FakeConfig()
201172
config.elastic_enabled = False
202173
msg = (
@@ -348,28 +319,28 @@ def test_record_elastic_event_start(self):
348319
"""Tests recording an elastic slice down start."""
349320
elastic_utils.elastic_manager = self.fake_manager
350321
self.fake_manager.new_slice_event.is_set.return_value = False
351-
self.fake_manager.slice_to_devices = {0: [FakeDevice()], 1: [FakeDevice()]}
352322
fake_recorder = Mock()
353323
config = FakeConfig()
354324

355325
elastic_utils.record_elastic_event_start(fake_recorder, config)
356326

357-
fake_recorder.record_elastic_wait_start_time.assert_called_once_with(event_type="elastic_slice_down")
358-
fake_recorder.record_elastic_slice_counts.assert_called_once()
327+
fake_recorder.record_custom_badput_event_start_time.assert_called_once_with(
328+
custom_badput_event_type="elastic_slice_down"
329+
)
359330
self.assertEqual(elastic_utils.pending_elastic_event_type, "elastic_slice_down")
360331

361332
def test_record_elastic_event_start_scale_up(self):
362333
"""Tests recording an elastic slice scale up start."""
363334
elastic_utils.elastic_manager = self.fake_manager
364335
self.fake_manager.new_slice_event.is_set.return_value = True
365-
self.fake_manager.slice_to_devices = {0: [FakeDevice()], 1: [FakeDevice()]}
366336
fake_recorder = Mock()
367337
config = FakeConfig()
368338

369339
elastic_utils.record_elastic_event_start(fake_recorder, config)
370340

371-
fake_recorder.record_elastic_wait_start_time.assert_called_once_with(event_type="elastic_scale_up")
372-
fake_recorder.record_elastic_slice_counts.assert_called_once()
341+
fake_recorder.record_custom_badput_event_start_time.assert_called_once_with(
342+
custom_badput_event_type="elastic_scale_up"
343+
)
373344

374345
def test_record_elastic_wait_end_and_reinit_start_noop_on_first_attempt(self):
375346
"""Tests recording elastic event end and elastic reinit start."""
@@ -378,39 +349,36 @@ def test_record_elastic_wait_end_and_reinit_start_noop_on_first_attempt(self):
378349

379350
elastic_utils.record_elastic_wait_end_and_reinit_start(fake_recorder)
380351

381-
fake_recorder.record_elastic_wait_end_time.assert_not_called()
382-
fake_recorder.record_elastic_reinit_start_time.assert_not_called()
352+
fake_recorder.record_custom_badput_event_end_time.assert_not_called()
353+
fake_recorder.record_custom_badput_event_start_time.assert_not_called()
383354
self.assertIsNone(elastic_utils.pending_reinit_recorder)
384355

385356
def test_record_elastic_wait_end_and_reinit_start(self):
386357
"""Test recording end of slice down and start of reinit."""
387358
elastic_utils.pending_elastic_event_type = "elastic_slice_down"
388-
elastic_utils.elastic_manager = self.fake_manager
389-
self.fake_manager.active_slice_indices = {0}
390-
self.fake_manager.slice_to_devices = {0: [FakeDevice()], 1: [FakeDevice()]}
391-
elastic_utils.pending_elastic_event_type = "elastic_slice_down"
392359
fake_recorder = Mock()
393360

394361
elastic_utils.record_elastic_wait_end_and_reinit_start(fake_recorder)
395362

396-
fake_recorder.record_elastic_wait_end_time.assert_called_once_with(event_type="elastic_slice_down")
397-
fake_recorder.record_elastic_reinit_start_time.assert_called_once()
398-
fake_recorder.record_elastic_slice_counts.assert_called_once()
363+
fake_recorder.record_custom_badput_event_end_time.assert_called_once_with(
364+
custom_badput_event_type="elastic_slice_down"
365+
)
366+
fake_recorder.record_custom_badput_event_start_time.assert_called_once_with(
367+
custom_badput_event_type="elastic_reinitialization"
368+
)
399369
self.assertIs(elastic_utils.pending_reinit_recorder, fake_recorder)
400370
self.assertIsNone(elastic_utils.pending_elastic_event_type)
401371

402372
def test_record_elastic_reinit_end(self):
403373
"""Tests recording end of elastic reinit."""
404374
fake_recorder = Mock()
405375
elastic_utils.pending_reinit_recorder = fake_recorder
406-
elastic_utils.elastic_manager = self.fake_manager
407-
self.fake_manager.active_slice_indices = {0}
408-
self.fake_manager.slice_to_devices = {0: [FakeDevice()], 1: [FakeDevice()]}
409376

410377
elastic_utils.record_elastic_reinit_end()
411378

412-
fake_recorder.record_elastic_reinit_end_time.assert_called_once()
413-
fake_recorder.record_elastic_slice_counts.assert_called_once()
379+
fake_recorder.record_custom_badput_event_end_time.assert_called_once_with(
380+
custom_badput_event_type="elastic_reinitialization"
381+
)
414382
self.assertIsNone(elastic_utils.pending_reinit_recorder)
415383

416384
def test_record_elastic_reinit_end_on_cold_start(self):
@@ -433,8 +401,6 @@ def __setattr__(self, name, value):
433401

434402
config = ReadOnlyConfig()
435403
self.fake_pathwaysutils.is_pathways_backend_used.return_value = True
436-
self.fake_pathwaysutils.elastic = Mock()
437-
self.fake_pathwaysutils.elastic.get_active_slice_indices.return_value = [0, 1]
438404

439405
# Should not raise ValueError
440406
elastic_utils.ensure_elastic_manager_initialized(config)

0 commit comments

Comments
 (0)