feat: TPU support via PyTorch/XLA (auto-detection, FSDP, XLA-safe merge/export) - #431
Open
instax-dutta wants to merge 1 commit into
Open
feat: TPU support via PyTorch/XLA (auto-detection, FSDP, XLA-safe merge/export)#431instax-dutta wants to merge 1 commit into
instax-dutta wants to merge 1 commit into
Conversation
…ge/export) Execution-only: adds TPU as a supported accelerator without changing what a run computes. All changes are gated behind TPU detection and are no-ops on CPU/CUDA/MPS. - system.py: torch_xla detection (detect_tpu), env-first SPMD setup for multi-chip FSDP (setting XLA_USE_SPMD after client init segfaults in PjRtComputationClient::ExecuteReplicated on torch_xla 2.8), XLA device/ core-count helpers, mark_step(wait=True) for materialized tensor data, XLA branch in empty_cache, TPU accelerator info. - fsdp_utils.py (new): FSDP wrapping over all physical cores via SPMD mesh (single-process Kaggle/Colab-style VMs), auto auto_layer_classes, output sharding for causal LM heads. - model.py: fit-based auto core selection (meta-device footprint estimate); CPU-load + FSDP shard before LoRA; bf16 forcing and quantization off; eval() before any forward to keep HLO stable (dropout RNG ops otherwise recompile per step and exhaust HBM); fixed-size sliding-window greedy decode loop (_get_responses_xla); chunked get_responses_batched (20-prompt chunks are the measured HBM ceiling at 100-token responses); direct forward-pass paths for residuals/logits with mandatory CPU offload; FSDP-tolerant LoRA target collection; XLA-safe merge (CPU reload, _orig_module key stripping, CPU-recomputed target list) so exports match base-model structure exactly; xm RNG reseed before svd_lowrank. - config.py: tpu_cores / tpu_use_fsdp / tpu_fsdp_config settings plus adjust_for_tpu validator (bfloat16, no bnb4, parallelism resolution). Excluded from serialized settings snapshots. - main.py: early TPU environment setup before any device access. - pyproject.toml: optional 'tpu' extra (torch_xla). Validated end-to-end on a Kaggle TPU v5e-8 (torch 2.8.0+cpu / torch_xla 2.8.0): full 210-trial abliteration of LiquidAI/LFM2.5-2.6B with the exact GPU recipe (same pinned commit, seed, prompt counts, response length, scorers). On CPU/GPU paths the port is byte-for-byte identical to upstream: tests/run_tests.py produces identical model.safetensors hashes from a pristine upstream/master checkout and this branch.
Author
On PR sizeFlagging this upfront: the PR is large (+1037/-79 across 6 files). If you have a size/maintainability preference for how hardware support lands, I'm happy to rework it - including splitting or slimming. Why it's this size:
If incremental landing works better for you, it decomposes cleanly:
Each stage is independently reviewable and leaves CPU/CUDA behavior byte-identical to master (verified: Or if you'd prefer a different shape entirely - thinner integration, separate package, whatever fits the project - say the word and I'll adapt. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds TPU as a supported accelerator via PyTorch/XLA. Execution-only: every change is gated behind runtime TPU detection and is a no-op on CPU/CUDA/MPS - what a run computes (response length, prompt counts, trial counts, scorers, abliteration parameters) is untouched.
Validated end-to-end on a Kaggle TPU v5e-8 (torch 2.8.0+cpu / torch_xla 2.8.0) with a full 210-trial abliteration run of
LiquidAI/LFM2.5-2.6Busing the exact GPU recipe fromreproduce/config.toml(same pinned model commit 403f92a, same seed 1552829245, train[:400] residuals, test[:100] eval, max_response_length=100,<think></think>prefix).What's included
detect_tpu), env-first SPMD setup for multi-chip FSDP (callinguse_spmd()after XLA client init segfaults inPjRtComputationClient::ExecuteReplicatedon torch_xla 2.8; settingXLA_USE_SPMD=1before any device access avoids it), core-count resolution from PJRT env vars,mark_step(wait=True)so tensor device data is materialized before use, XLA branch inempty_cache, TPU accelerator info..eval()before any forward (dropout/RNG ops in the graph change the HLO per step and exhaust HBM); fixed-size sliding-window greedy decode loop_get_responses_xla; chunkedget_responses_batched(20-prompt chunks are the measured HBM ceiling at 100-token responses; batching-only change, same responses); direct forward-pass paths for residuals/logits with mandatory CPU offload; FSDP-tolerant LoRA target collection; XLA-safe merge (materialize to CPU, strip FSDP_orig_module.key pollution, recompute LoRA targets against the CPU reload) so exported weights match base structure exactly; XM RNG reseed before randomizedsvd_lowrank.tpu_cores/tpu_use_fsdp/tpu_fsdp_configsettings +adjust_for_tpuvalidator (bfloat16, disable bnb_4bit, resolve parallelism). Excluded from settings snapshots.tpuextra (torch_xla).Verification
On CPU/GPU paths the port is byte-for-byte identical to upstream:
tests/run_tests.pyproduces identicalmodel.safetensorshashes from a pristineupstream/mastercheckout and this branch (5/5 files compared on macOS/arm64).pytest tests/test_config.pypasses.TPU parity evidence (LFM2.5-2.6B, identical recipe):
The residual gap traces to bf16-XLA vs CUDA numerics: the baseline itself differs (84-89 vs 98) under the same commit/template, so borderline refusal decisions flip and the optimizer lands on a slightly different optimum. Same computation, different floating-point substrate.
Notes
std::bad_allocinfrom_pretrainedon v5e).