feat(input): Megatron MMap Data Formats for MaxText Grain - #4625
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Hi reviewers, just an FYI that this PR is from a forked repo. Due to secret key limitations, the Gemini review couldn't be triggered. |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
c6f8f49 to
e59b0cb
Compare
e59b0cb to
97af29f
Compare
aireenmei
left a comment
There was a problem hiding this comment.
Thanks for the detailed PR description, and also update documentations! LGTM in general. Just minor comments:
For the new unit tests, could we consolidate them for easier maintenance?
My suggestion is to use two main new test modules:
mmap_data_processing_test.py: mmap/mmap_npy datasource behavior, file parsing, sharding, multiprocessing, Grain integration, EOD semantics, and checkpoint behavior.megatron_mmap_compatibility_test.py: index construction, splitting, blending, CLI behavior, host-order reconstruction, and comparisons with megatron.core.
The smaller tests could extend existing modules:
- Move MegatronSplitInputsTargets, GenerateDocSegmentIds, and segment-merging tests into
input_pipeline_utils_test.py. - Move mmap configuration default/validation tests into
configs_value_test.py. - Keep
mmap_test_utils.pyas a shared non-collected helper.
Thanks for the suggestion! I consolidated the tests into the two proposed modules, moved the smaller transform/config tests into the existing modules, and kept Validation passed: |
8a92a0e to
cf9a05f
Compare
eb7b094 to
350a7ff
Compare
|
I see this error Could you help squash all 7 commits into one? |
350a7ff to
63fcddd
Compare
Done! Squashed all 7 commits into one and force-pushed. The diff is identical to before, just cleaner history now. |
|
Hi @Yitrus now the process is failing because there is no license string in the header of the newly added files: |
63fcddd to
4c7b3ac
Compare
Thanks for pointing this out. I’ve added the standard Apache 2.0 license header to all seven newly added files. |
|
Hi @igorts-git I tried 2 times of CI/CD rer-run, and pathway unit tests seem down due to connection. |
|
The CI problems are now fixed on main, the PR needs to be rebased. Sorry about that. |
|
The fix is in #4991 Could you rebase the PR? We will help merge from internal codebase. |
4c7b3ac to
34bd817
Compare
Thanks! I’ve rebased the PR onto the latest main, which includes the fix from #4991. The Pathways CI and all required tests are now passing. |
|
Hi @aireenmei @igorts-git @RissyRan, just a friendly follow-up on this PR. It now has the required approvals, and the only remaining failure is the "Track Test Performance" check, which failed with Could one of you please help rerun this check and proceed with the internal merge at your convenience? Please let me know if anything else is needed from my side. Thanks! |
Working on it |
1. Summary
This proposal adds
mmapandmmap_npydata formats to MaxText's Grain input pipeline so training can consume Megatron-LM text-preprocessing.bin/.idxdatasets directly.mmapis a simpler Grain-native reader;mmap_npyuses Megatron-style indices to reproduce document shuffle, fixed-length sample construction, sample shuffle, and multi-dataset blending order.The goal of
mmap_npyis element-by-element equivalence to MegatronGPTDatasetfor rawL + 1token samples. It does not introduce a separate training runtime: data still reaches the JAX model through Grain transforms, batching, andMultiHostDataLoadIterator.Indices can be built offline with a CLI or automatically on the first training run. The runtime cache is keyed by an epoch bucket; on a cache miss every host deterministically computes indices in memory while only host 0 atomically persists the shared cache, so no barrier is required.
2. Motivation and scope
Megatron-LM is widely used for large-scale pretraining, and users often already own
.bin/.idxdata assets. Without a direct reader, moving to MaxText requires data conversion or accepting a different sample order, which confounds convergence, throughput, and numerical comparisons.This design covers Megatron text indexed datasets only. Input data must contain EOD tokens written during preprocessing with
--append-eod; runtime code does not insert EOD again. ArrayRecord, TFRecord, Parquet, HF, TFDS, and other existing training paths remain unchanged.3. User-facing formats and configuration
3.1 Select a format
The implementation continues to use
dataset_type=grainand addsgrain_file_type=mmapandgrain_file_type=mmap_npy.mmapreads.bin/.idxand uses EOD-aware Grain transforms; it is suitable for simple training or exploration but does not promise complete MegatronGPTDatasetsample-order parity.mmap_npyreads the same data format and loads or builds three.npyindices to provide Megatron sample-order compatibility.3.2 Configure mmap/mmap_npy
The table below lists the configuration needed to use mmap/mmap_npy.
grain_file_typesrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::GrainDatasetmmap: direct.bin/.idxreader.mmap_npy: Megatron-style indexed reader.mmap_npyis the compatibility path for Megatron GPT sample order;mmapis the simpler path.grain_train_filesgrain_eval_filessrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::GrainDatasetmmap: a prefix/directory, or weighted entries separated by;.mmap_npy:npy_dir|bin_prefix_or_directory; weighted entries use,weightand;.Path strings and dimensionless weights.
npy_dircontains only index files; the.bin/.idxprefix or directory contains tokens. Mixture weights must be non-negative and have a positive total.max_target_lengthsrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MaxTextConfigL, in tokens.mmap_npyreadsL+1raw tokens and emits length-Lmodel fields. It must match the intended Megatron sequence length.mmap_eod_idsrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDataset0.--append-eod. It replaced the earlierpad_idname because EOD and padding differ semantically;bos_idis not used by this path.mmap_split_sentencessrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDatasetfalse.trueonly when the indexed dataset was produced with Megatron--split-sentences; otherwise the reader reports a layout mismatch.mmap_npy_splitsrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDatasetComma-separated ratios such as
99,1or98,1,1enable splitting.mmap_npy. Training uses split 0; evaluation uses split 1 when a split is configured. Boundaries use Megatron-compatible rounding and document indices retain global document IDs.blend_cache_dirsrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDatasetOtherwise a writable directory path.
mmap_npyblending. It stores runtime-generated global blend dispatch indices; cache-write failure falls back to in-memory indices.blend_index_dirsrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDatasetOtherwise a directory containing
dataset_index.npyanddataset_sample_index.npy, or one uniquely identifiable equivalent pair.mmap_npyblending and takes precedence overblend_cache_dir. The pair must match dataset order and requested size; invalid files fall back to a rebuilt dispatch.reset_attention_masksrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDatasettrue.truestarts a new attention segment after EOD and restarts the next position at 0;falsekeeps one continuous segment and positions. The standard Grain pretraining path does not read this field.eod_mask_losssrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDatasetfalse.truemasks positions whose input token is EOD;falsekeeps them in loss. It is independent of attention reset. The simplemmappath has a ShiftData limitation that still masks EOD-related loss when this field isfalse; usemmap_npyfor strict Megatron loss semantics.packing_max_segments_per_samplesrc/maxtext/configs/base.ymlsrc/maxtext/configs/types.py::MMapDataset25.<=0disables short-segment merging.max_target_length // packing_max_segments_per_sampletokens. EOD-derived boundaries at or below the threshold are merged; this is independent of Grain packing itself. Set<=0to retain every EOD boundary.3.3 Prepare and run a dataset
The following is a single-dataset example that strictly preserves Megatron GPT next-token, EOD, and index-order semantics.
The offline tool
tools/data_processing/mmap_index_builder.pyis a CLI wrapper around the core library. It is not a required training prerequisite: a runtime cache miss builds the same indices automatically. Offline construction is useful when users want to inspect artifacts before training, publish indices to a read-only directory, or avoid index computation during first-job startup.The following single-dataset command corresponds to the YAML above.
Multi-dataset offline construction uses the
blendsubcommand.python3 tools/data_processing/mmap_index_builder.py blend \ --datasets '/data/wiki_text_document,0.7;/data/code_text_document,0.3' \ --output-dir /cache/wiki_code_blend \ --seq-length 2048 \ --total-samples 1024000 \ --seed 1234 \ --margin 0.5 \ --add-extra-token 1Offline blend artifacts require both child-index directories and the root dispatch directory; add the following snippet to the same experiment YAML.
4. Compatibility contract
4.1 model batches
For ordinary pretraining, optional features can add
dataset_id, image, or SFT/DPO fields, but both standard Grain andmmap_npydeliver the following six core fields to the model.The following example uses
L=4,PAD=0,EOD=99,reset_attention_mask=True, andeod_mask_loss=False. The rawL+1tokens are[10, 11, 99, 20, 21], where99is the EOD boundary between two documents.Standard Grain without packing does not treat EOD as a document boundary: valid tokens are in segment 1, padding is in segment 0, and positions increase continuously.
ShiftDataleft-shifts targets and pads the tail and a zero loss mask at the last position.Packing is a separate feature: it places multiple short, independent samples into one fixed-length sequence to reduce padding. Each original sample restarts positions at 0, and segment boundaries are defined by the Grain packer's sample-concatenation points rather than automatically by EOD.
mmap_npyforms next-token pairs directly from realL+1tokens:inputs=tokens[:-1]andtargets=tokens[1:],whereasmmap_npyretains a real final target and computes its loss. With reset enabled, EOD still belongs to the preceding document; the following20starts a new attention segment and position resets to 0. Witheod_mask_loss=False, every target contributes to supervision.Consequently, standard Grain has a padded final target, The ordinary standard-Grain pretraining path does not read
reset_attention_maskoreod_mask_loss, and it neither resets positions nor increments input segments at EOD.Both simple
mmapandmmap_npyuse EOD-aware attention/position transforms; their main difference is next-token sample construction.mmapstill usesShiftDataafterwards, so witheod_mask_loss=Falseit masks EOD-related loss becausemmap_eod_idalso acts as an ignored ID; usemmap_npywhen strict Megatron loss semantics are required.4.2 Megatron parity boundary
mmap_npypromises MegatronGPTDatasetdata-consumption semantics: with the same data, configuration, and random seed, each position in the global sample stream reads the same raw tokens and constructs semantically corresponding model fields.This promise requires
grain_file_type=mmap_npyand matching.bin/.idx, EOD ID, sequence length, shuffle seed, split/blend configuration, and requested sample count. Conventional Megatron GPT EOD semantics additionally requirereset_attention_mask=true,eod_mask_loss=false, andpacking_max_segments_per_sample=0.5. Architecture and runtime behavior
5.1 Dataloader placement
The diagram shows where the new logic belongs: offline preprocessing ends at
.bin/.idx;mmap_npygenerates or loads Megatron indices before the Grain runtime, then joins the existing Grain transforms, batching, and multi-host loader. The optional offline CLI only produces indices; training can still rebuild them when the cache is absent.5.2 Megatron-parity implementation map
.bin/.idxformat and relies on the EOD token written during preprocessing.MMapIndexedDatasetin_mmap_datasource.pyparses the index and performs token reads. Runtime does not insert EOD.L+1sample construction, and sample shuffle.build_indices()in_mmap_index_utils.pyimplements these three steps and produces the document, sample, and shuffle indices.MegatronNpyDataSourceconsumes the resulting arrays for random access.mmap_npy_splitto select the documents for a split and writes their global IDs intodocument_index.npy.MegatronNpyDataSourceuses those IDs to read the corresponding documents from the original.bin/.idxdataset.build_blending_indices()andMegatronBlendedDataSourcein_megatron_blending.py; offline/cache dispatch files are an optional MaxText delivery mechanism.GenerateDocSegmentIdsandMegatronSplitInputsTargetsininput_pipeline_utils.pyconstruct the six model fields._mmap_pretrain_pipeline()andmake_grain_train_iterator()attach the source to Grain;MultiHostDataLoadIteratortransfers local batches to the JAX global mesh. This runtime is MaxText-specific rather than a Megatron dataloader replica.6. Validation, robustness, and tests
6.1 Unit tests
Unit tests cover reader format and corrupted-input checks, offline and runtime indices, data sources, EOD transforms, and alignment with real Megatron helpers/GPTDataset. The table below describes the primary purpose of each test file.
mmap_data_processing_test.pyinput_pipeline_utils_test.pymegatron_mmap_compatibility_test.pyconfigs_value_test.pymmap_test_utils.py6.2 End-to-end checkpoint restoration smoke test
resume_file_type_test.shis a single-process TPU-VMmmap_npycheckpoint-restoration smoke test. It validates the smaller but critical end-to-end path in which MaxText saves a Grain iterator state, restores it from the same training directory in a subsequent process, and continues training successfully.The script requires a TPU-VM checkout on the target branch and caller-provided
GRAIN_TRAIN_FILES,MMAP_EOD_ID,TOKENIZER_PATH, andVOCAB_SIZE. It fixesgrain_file_type=mmap_npy, disables the elastic iterator, and runs two trainings with the samerun_nameand output directory: Run A trains forSTEPS_Aand saves a final checkpoint, after which the script confirms that a single-process Grain iterator state exists. Run B raises the total step count toSTEPS_B, verifies from the logs that the checkpoint and iterator state were restored from the same run directory, and confirms that training continues. The script rejects a pre-existing checkpoint directory to avoid accidentally consuming stale state.This is a functional restoration smoke test, not a determinism test.
stepscontributes to themmap_npysample count and may change the derived epoch bucket, final-epoch handling, and cached indices.Checklist