|
25 | 25 |
|
26 | 26 | from absl import app |
27 | 27 |
|
28 | | -import numpy as np |
| 28 | + |
29 | 29 | import optax |
30 | 30 |
|
31 | 31 | import pathwaysutils # pylint: disable=unused-import |
@@ -632,6 +632,117 @@ def eval_step(model, config, state, data, dropout_rng=None): |
632 | 632 | return metrics |
633 | 633 |
|
634 | 634 |
|
| 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 | + |
635 | 746 | def train_loop(config, recorder, state=None): |
636 | 747 | """Main Training loop.""" |
637 | 748 | ( |
@@ -704,74 +815,64 @@ def train_loop(config, recorder, state=None): |
704 | 815 |
|
705 | 816 | elastic_utils.record_elastic_reinit_end() |
706 | 817 |
|
| 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 | + |
707 | 861 | _job_completed_gracefully = False |
708 | 862 | 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 |
739 | 869 |
|
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"]: |
774 | 874 | checkpointing.maybe_save_checkpoint(checkpoint_manager, state, config, data_iterator) |
| 875 | + |
775 | 876 | if checkpoint_manager is not None: |
776 | 877 | # in case the last checkpoint_period checkpoint is still in progress |
777 | 878 | checkpoint_manager.wait_until_finished() |
|
0 commit comments