Skip to content

Commit f4dda66

Browse files
Merge pull request AI-Hypercomputer#4079 from AI-Hypercomputer:lukebaumann/pretraining-refactor
PiperOrigin-RevId: 940023847
2 parents 9643733 + d718d78 commit f4dda66

2 files changed

Lines changed: 168 additions & 65 deletions

File tree

src/maxtext/trainers/pre_train/train.py

Lines changed: 166 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from absl import app
2727

28-
import numpy as np
28+
2929
import optax
3030

3131
import pathwaysutils # pylint: disable=unused-import
@@ -632,6 +632,117 @@ def eval_step(model, config, state, data, dropout_rng=None):
632632
return metrics
633633

634634

635+
def training_loop_iteration(
636+
jax_device_state: dict[str, Any],
637+
python_vars: dict[str, Any],
638+
immutable_data: dict[str, Any],
639+
):
640+
"""Executes a single iteration of the training loop."""
641+
# Unpack jax_device_state
642+
state = jax_device_state["state"]
643+
init_rng = jax_device_state["init_rng"]
644+
mesh = jax_device_state["mesh"]
645+
state_mesh_shardings = jax_device_state["state_mesh_shardings"]
646+
p_train_step = jax_device_state["p_train_step"]
647+
p_eval_step = jax_device_state["p_eval_step"]
648+
model = jax_device_state["model"]
649+
650+
# Unpack python_vars
651+
step = python_vars["step"]
652+
last_step_completion = python_vars["last_step_completion"]
653+
data_loader = python_vars["data_loader"]
654+
rampup_manager = python_vars["rampup_manager"]
655+
recorder = python_vars["recorder"]
656+
checkpoint_manager = python_vars["checkpoint_manager"]
657+
data_iterator = python_vars["data_iterator"]
658+
eval_data_iterator = python_vars["eval_data_iterator"]
659+
metric_logger_instance = python_vars["metric_logger_instance"]
660+
prof = python_vars["prof"]
661+
662+
# Unpack immutable_data
663+
config = immutable_data["config"] # for helpers
664+
logical_axis_rules = immutable_data["logical_axis_rules"]
665+
shard_optimizer_over_data = immutable_data["shard_optimizer_over_data"]
666+
shard_mode = immutable_data["shard_mode"]
667+
eval_interval = immutable_data["eval_interval"]
668+
eval_steps = immutable_data["eval_steps"]
669+
start_step = immutable_data["start_step"]
670+
671+
# HLO dump config
672+
dump_hlo = immutable_data["dump_hlo"]
673+
dump_step = immutable_data["dump_step"]
674+
dump_hlo_local_dir = immutable_data["dump_hlo_local_dir"]
675+
dump_hlo_gcs_dir = immutable_data["dump_hlo_gcs_dir"]
676+
dump_hlo_module_name = immutable_data["dump_hlo_module_name"]
677+
dump_hlo_delete_local_after = immutable_data["dump_hlo_delete_local_after"]
678+
dump_hlo_upload_all = immutable_data["dump_hlo_upload_all"]
679+
680+
prof.maybe_activate_profiler(step, state)
681+
682+
with jax.profiler.StepTraceAnnotation("train", step_num=step):
683+
example_batch = data_loader.load_next_batch(rampup_manager=rampup_manager)
684+
if isinstance(model, nn.Module):
685+
# pylint: disable=not-callable
686+
step_rng_args = (jax.jit(jax.random.fold_in)(init_rng, step),)
687+
else:
688+
step_rng_args = ()
689+
with maybe_record_goodput(recorder, GoodputEvent.STEP, step):
690+
with jax.set_mesh(mesh), nn_partitioning.axis_rules(logical_axis_rules):
691+
if shard_optimizer_over_data and isinstance(model, nn.Module):
692+
state = sharding.maybe_shard_with_name(state, state_mesh_shardings, shard_mode)
693+
state, metrics = p_train_step(state, example_batch, *step_rng_args)
694+
695+
step_time_delta = datetime.datetime.now() - last_step_completion
696+
last_step_completion = datetime.datetime.now()
697+
698+
checkpointing.maybe_save_checkpoint(checkpoint_manager, state, config, data_iterator, step)
699+
700+
if dump_hlo and step == (dump_step if dump_step >= 0 else start_step):
701+
jax.block_until_ready(state) # Ensure compilation has finished.
702+
gcs_utils.upload_dump(
703+
dump_hlo_local_dir,
704+
dump_hlo_gcs_dir,
705+
module_name=dump_hlo_module_name,
706+
delete_local_after=dump_hlo_delete_local_after,
707+
all_host_upload=dump_hlo_upload_all,
708+
)
709+
710+
if eval_interval > 0 and step > start_step and (step + 1) % eval_interval == 0:
711+
assert eval_data_iterator
712+
# Explicitly reset the eval iterator and counters before starting the eval loop
713+
eval_data_iterator.reset()
714+
metric_logger_instance.reset_eval_metrics()
715+
max_logging.log(f"Starting eval after train step {step}")
716+
717+
eval_step_count = 0
718+
last_eval_step_completion = datetime.datetime.now()
719+
# pylint: disable=not-callable
720+
for eval_batch in eval_data_iterator:
721+
# Shard input eval data
722+
eval_batch = jax.device_put(eval_batch, sharding.get_input_data_sharding(config, mesh))
723+
if 0 < eval_steps <= eval_step_count:
724+
break
725+
with jax.set_mesh(mesh), nn_partitioning.axis_rules(logical_axis_rules):
726+
eval_metrics = p_eval_step(state, eval_batch, *step_rng_args)
727+
eval_step_time_delta = datetime.datetime.now() - last_eval_step_completion
728+
last_eval_step_completion = datetime.datetime.now()
729+
metric_logger_instance.buffer_and_write_metrics(
730+
eval_metrics, eval_step_count, step_time_delta=eval_step_time_delta, is_training=False
731+
)
732+
eval_step_count += 1
733+
734+
prof.maybe_deactivate_profiler(step, state)
735+
736+
if step == start_step:
737+
max_utils.print_mem_stats("After params initialized")
738+
739+
metric_logger_instance.buffer_and_write_metrics(metrics, step, step_time_delta)
740+
741+
# Pack mutated state back to dicts
742+
jax_device_state["state"] = state
743+
python_vars["last_step_completion"] = last_step_completion
744+
745+
635746
def train_loop(config, recorder, state=None):
636747
"""Main Training loop."""
637748
(
@@ -704,74 +815,64 @@ def train_loop(config, recorder, state=None):
704815

705816
elastic_utils.record_elastic_reinit_end()
706817

818+
# Initialize dictionaries for refactored iteration
819+
jax_device_state = {
820+
"state": state,
821+
"init_rng": init_rng,
822+
"mesh": mesh,
823+
"state_mesh_shardings": state_mesh_shardings,
824+
"p_train_step": p_train_step,
825+
"p_eval_step": p_eval_step,
826+
"model": model,
827+
}
828+
829+
python_vars = {
830+
"step": start_step,
831+
"last_step_completion": datetime.datetime.now(),
832+
"data_loader": data_loader,
833+
"rampup_manager": rampup_manager,
834+
"recorder": recorder,
835+
"checkpoint_manager": checkpoint_manager,
836+
"data_iterator": data_iterator,
837+
"eval_data_iterator": eval_data_iterator,
838+
"metric_logger_instance": metric_logger_instance,
839+
"prof": prof,
840+
}
841+
842+
immutable_data = {
843+
"config": config,
844+
"logical_axis_rules": config.logical_axis_rules,
845+
"shard_optimizer_over_data": config.shard_optimizer_over_data,
846+
"shard_mode": config.shard_mode,
847+
"steps": config.steps,
848+
"eval_interval": config.eval_interval,
849+
"eval_steps": config.eval_steps,
850+
"save_checkpoint_on_completion": config.save_checkpoint_on_completion,
851+
"start_step": start_step,
852+
"dump_hlo": config.dump_hlo,
853+
"dump_step": config.dump_step,
854+
"dump_hlo_local_dir": config.dump_hlo_local_dir,
855+
"dump_hlo_gcs_dir": config.dump_hlo_gcs_dir,
856+
"dump_hlo_module_name": config.dump_hlo_module_name,
857+
"dump_hlo_delete_local_after": config.dump_hlo_delete_local_after,
858+
"dump_hlo_upload_all": config.dump_hlo_upload_all,
859+
}
860+
707861
_job_completed_gracefully = False
708862
try:
709-
last_step_completion = datetime.datetime.now()
710-
for step in np.arange(start_step, config.steps):
711-
prof.maybe_activate_profiler(step, state)
712-
713-
with jax.profiler.StepTraceAnnotation("train", step_num=step):
714-
example_batch = data_loader.load_next_batch(rampup_manager=rampup_manager)
715-
if isinstance(model, nn.Module):
716-
# pylint: disable=not-callable
717-
step_rng_args = (jax.jit(jax.random.fold_in)(init_rng, step),)
718-
else:
719-
step_rng_args = ()
720-
with maybe_record_goodput(recorder, GoodputEvent.STEP, step):
721-
with jax.set_mesh(mesh), nn_partitioning.axis_rules(config.logical_axis_rules):
722-
if config.shard_optimizer_over_data and isinstance(model, nn.Module):
723-
state = sharding.maybe_shard_with_name(state, state_mesh_shardings, config.shard_mode)
724-
state, metrics = p_train_step(state, example_batch, *step_rng_args)
725-
726-
step_time_delta = datetime.datetime.now() - last_step_completion
727-
728-
checkpointing.maybe_save_checkpoint(checkpoint_manager, state, config, data_iterator, step)
729-
730-
if config.dump_hlo and step == (config.dump_step if config.dump_step >= 0 else start_step):
731-
jax.block_until_ready(state) # Ensure compilation has finished.
732-
gcs_utils.upload_dump(
733-
config.dump_hlo_local_dir,
734-
config.dump_hlo_gcs_dir,
735-
module_name=config.dump_hlo_module_name,
736-
delete_local_after=config.dump_hlo_delete_local_after,
737-
all_host_upload=config.dump_hlo_upload_all,
738-
)
863+
python_vars["last_step_completion"] = datetime.datetime.now()
864+
865+
# Using while loop to allow for potential dynamic 'steps' adjustment in future
866+
while python_vars["step"] < immutable_data["steps"]:
867+
training_loop_iteration(jax_device_state, python_vars, immutable_data)
868+
python_vars["step"] += 1
739869

740-
eval_step_count = None
741-
if config.eval_interval > 0 and step > start_step and (step + 1) % config.eval_interval == 0:
742-
assert eval_data_iterator
743-
# Explicitly reset the eval iterator and counters before starting the eval loop
744-
eval_data_iterator.reset()
745-
metric_logger_instance.reset_eval_metrics()
746-
max_logging.log(f"Starting eval after train step {step}")
747-
748-
eval_step_count = 0
749-
last_eval_step_completion = datetime.datetime.now()
750-
# pylint: disable=not-callable
751-
for eval_batch in eval_data_iterator:
752-
# Shard input eval data
753-
eval_batch = jax.device_put(eval_batch, sharding.get_input_data_sharding(config, mesh))
754-
if config.eval_steps > 0 and eval_step_count >= config.eval_steps:
755-
break
756-
with jax.set_mesh(mesh), nn_partitioning.axis_rules(config.logical_axis_rules):
757-
eval_metrics = p_eval_step(state, eval_batch, *step_rng_args)
758-
eval_step_time_delta = datetime.datetime.now() - last_eval_step_completion
759-
last_eval_step_completion = datetime.datetime.now()
760-
metric_logger_instance.buffer_and_write_metrics(
761-
eval_metrics, eval_step_count, step_time_delta=eval_step_time_delta, is_training=False
762-
)
763-
eval_step_count += 1
764-
765-
prof.maybe_deactivate_profiler(step, state)
766-
767-
if step == start_step:
768-
max_utils.print_mem_stats("After params initialized")
769-
770-
last_step_completion = datetime.datetime.now()
771-
metric_logger_instance.buffer_and_write_metrics(metrics, step, step_time_delta)
772-
773-
if config.save_checkpoint_on_completion:
870+
# Unpack state for post-loop actions
871+
state = jax_device_state["state"]
872+
873+
if immutable_data["save_checkpoint_on_completion"]:
774874
checkpointing.maybe_save_checkpoint(checkpoint_manager, state, config, data_iterator)
875+
775876
if checkpoint_manager is not None:
776877
# in case the last checkpoint_period checkpoint is still in progress
777878
checkpoint_manager.wait_until_finished()

tests/unit/nnx_decoders_test.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,8 @@ def test_gemma4_small_decoder(self):
796796
"base_mlp_dim=256",
797797
"dtype=float32",
798798
"weight_dtype=float32",
799+
"hidden_size_per_layer_input=128",
800+
"vocab_size_per_layer_input=256",
799801
"vocab_size=256",
800802
],
801803
override_model_config=True,

0 commit comments

Comments
 (0)