PyTorch Conference North America 2026

Scaling PyTorch on Intel XPU

Field Notes from AI for Science on Aurora

Sam Foreman · Panagiotis Kourdis · Tanima Dey

Scaling PyTorch on Intel XPU

Field notes from AI for Science on Aurora

Sam Foreman · Argonne National LaboratoryPanagiotis Kourdis · IntelTanima Dey · Intel
PyTorch Conference · October 21, 2026 — San Jose
Interactive version: live diagrams + linksQR code linking to samf.sh/talks/2026/10/21samf.sh/talks/2026/10/21

Aurora at ALCF

ALCFArgonne Leadership Computing Facility at Argonne National Lab: DOE open science on Aurora + Polaris
Aurora10,624 nodes · 127,488 XPUs · system paper
This talkRunning PyTorch on Aurora: backend fixes, training, and recovery
Aurora's HPE Cray EX racks at the Argonne Leadership Computing Facility
Aurora at the ALCF. Photo: Argonne / ALCF.
Here, XPU = one GPU tile exposed as a torch.xpu device in FLAT mode. 12 XPUs per node.

Talk outline

PartQuestionImplementation
A · NeededWhat does it take to build a GPU that runs PyTorch?
What about 100,000 of them, together?
IPEX (legacy) · torch-xpu-ops · XCCL / torch-ccl
oneAPI · oneCCL · SYCL
B · AccomplishedHow do you run AI for Science campaigns at scale?
On a brand-new, rapidly evolving software stack?
ezpz · Megatron-DeepSpeed · torchtitan/ezpz
DTensor · FSDP2
C · RemainsWhat keeps a 14-day job alive at 60k → 120k XPUs?Nobody knows!
Best bets: ezpz checkpoint-restart · watchdog · node exclusion · scheduler resubmit

Scientific AI on Aurora

WorkloadWhenScale / result
GenSLM: viral genomesSC22 · Gordon Bell Prize1Polaris + Cerebras
MProt-DPO: protein designSC24 · Gordon Bell finalist38,400 ranks · 4.11 EFLOP/s at 3,200 nodes
AERIS: weather diffusionSC25 · Gordon Bell finalist10,080 nodes · 10.21 EFLOP/s · 90-day stable rollouts
AuroraGPT: foundation LLMongoing7.77T-token MDS reference → torchtitan

I co-led MProt-DPO and AERIS, and co-lead AuroraGPT.

ezpz: same training program on Intel, NVIDIA, AMD.2

PyTorch XPU and Aurora timeline

2023IPEX before native XPU · Aurora installation complete · GenSLM Gordon Bell
2024PyTorch 2.4 XPU prototype → 2.5 native Intel GPU · Aurora reaches exascale
2025PyTorch eager/compile parity and XCCL ProcessGroup · Aurora enters production · AERIS at 10k nodes
2026PyTorch 2.10 + XPU · AuroraGPT on torchtitan/ezpz
%%{init: {'themeCSS': '.titleText{font-size:1.1rem!important;font-weight:700}.taskText{font-size:1.2rem!important;font-weight:600}.taskTextOutsideRight,.taskTextOutsideLeft{font-size:1.2rem!important}.sectionTitle{font-size:1.2rem!important;font-weight:700}.tick text{font-size:1.5rem!important;font-weight:600}.grid .tick line{stroke:var(--background3)!important;opacity:0.6}.section0{fill:color-mix(in oklch,var(--background1) 72%,transparent)!important}.section1{fill:color-mix(in oklch,var(--blue) 38%,transparent)!important}.done,.active{fill:color-mix(in srgb,var(--blue) 72%,white 28%)!important;stroke:var(--blue)!important}.crit{fill:var(--red)!important;stroke:var(--red)!important}.task.crit text{fill:#fff!important}.task.crit + text,.task.critText{fill:#fff!important}.milestone{fill:var(--red)!important;stroke:var(--red)!important}'}}%% gantt title Intel PyTorch and Aurora milestones dateFormat YYYY-MM-DD axisFormat %Y todayMarker off section Intel and PyTorch IPEX — before native XPU :i1, 2023-01-01, 2024-03-27 PyTorch Fdn Premier (Intel) :milestone, i2, 2023-08-15, 1d PT 2.4 XPU prototype :milestone, i3, 2024-07-24, 1d PT 2.5 native Intel GPU :milestone, i4, 2024-10-17, 1d PT 2.7 eager/compile parity :milestone, i5, 2025-04-23, 1d PT 2.8 XCCL ProcessGroup :milestone, i6, 2025-08-06, 1d IPEX EOL :crit, i7, 2024-03-31, 1d PT 2.9 :milestone, i8, 2025-10-15, 1d PT 2.10 + PTC talk :milestone, crit, i9, 2026-01-15, 1d section Aurora and science Install complete 10624 nodes :milestone, a1e, 2023-06-22, 1d GenSLM 32B Gordon Bell :milestone, a3, 2023-11-15, 1d Exascale 1.01 EF on HPL :crit, a4, 2024-05-13, 1d MProt-DPO 38k 4.1 EFLOP/s :milestone, a5, 2024-10-15, 1d Aurora in production :milestone, a6, 2025-01-27, 1d Megatron-DeepSpeed :a7, 2024-08-01, 2025-03-15 torchtitan/ezpz :crit, a8, 2025-04-06, 2026-01-15 AERIS 10k nodes 10 EFLOP/s :milestone, a9, 2025-09-15, 1d AuroraGPT on torchtitan :milestone, a10, 2026-01-10, 1d
  • Intel and PyTorch: IPEX → PT 2.4–2.10+XPU (4 releases)
  • Aurora and science: 10k nodes → 120k-XPU workloads

From ezpz: distributed PyTorch across any hardware plus verified Aurora dates.

PyTorch XPU backend components

%%{init: {'themeCSS': '.nodeLabel{font-size:1.05rem!important} .edgeLabel{font-size:0.85rem!important}'}}%% flowchart LR TRAIN["torchtitan step"] --> DEVICE["torch.xpu<br/>device API"] DEVICE --> KERNELS["ops + XPU kernels"] KERNELS --> RUNTIME["oneAPI runtime"] RUNTIME --> GPU["Intel XPUs"] TRAIN --> DIST["torch.distributed"] DIST --> PARALLEL["DTensor<br/>FSDP2"] PARALLEL --> XCCL["XCCL (torch-ccl)<br/>ProcessGroup"] XCCL --> COLLECTIVE["oneCCL collectives<br/>fabric"] COLLECTIVE --> GPU
%%{init: {'themeCSS': '.nodeLabel{font-size:0.95rem!important} .edgeLabel{font-size:0.78rem!important}'}}%% flowchart TB TRAIN["torchtitan step"] --> DEVICE["torch.xpu device API"] DEVICE --> KERNELS["ops + XPU kernels"] KERNELS --> RUNTIME["oneAPI runtime"] RUNTIME --> GPU["Intel XPUs"] TRAIN --> DIST["torch.distributed"] DIST --> PARALLEL["DTensor / FSDP2"] PARALLEL --> XCCL["XCCL (torch-ccl) ProcessGroup"] XCCL --> COLLECTIVE["oneCCL collectives / fabric"] COLLECTIVE --> GPU

Test the device API, kernels, and collectives together. IPEX shims → native torch.xpu + torch-ccl/XCCL + oneCCL

XPU integration issues

SymptomRoot causeWhat we run now
torch 2.13: expected DTensor, got plain tensor on FSDP wrapMissing pytorch#181519Fixed in 2.14.0+xpu
DeviceMesh → does not support splittingProcessGroupXCCL inherits supportsSplitting() == false (see pytorch#186548)Local shim · pytorch#186548
train_timeout_seconds is a no-op_set_pg_timeout has no xpu branch: XCCL stores the timeout, never arms itWatchdog heartbeat (Act C) + two-PR upstream

The CUDA path worked. The XPU path inherited defaults that needed fixing.

From Megatron-DeepSpeed to torchtitan

Megatron-DeepSpeed fork3torchtitan + DTensor + FSDP2
2B trained to 7.77T tokens (Aug talk)Same run continues on torchtitan: 4.67T at 256→512 nodes
Parallelism baked into the forkDTensor + FSDP2 as composable primitives
Every PT release → rebase + patch auditXPU integration in separate layers · torchtitan/ezpz

The fork trained the 2B model to 7.77T tokens. Each PyTorch upgrade required another rebase and patch audit.

One training program across vendors

Hello world:

# example.py
import torch
import ezpz
rank = ezpz.setup_torch()
world_size = ezpz.get_world_size()
dev = ezpz.get_torch_device()      # {xpu, cuda, cpu, ...}
# FSDP2 by default — accepts DeviceMesh
model = ezpz.wrap_model(torch.nn.Linear(128, 10).to(dev))
print(f"Hello from {rank}/{world_size}!")
$ ezpz launch python3 example.py
Hello from rank 0/24!
Hello from rank 1/24!
# ... etc
Other examples
# your own script — no changes needed
ezpz launch python3 your_training_script.py
# full HF model + dataset via ezpz examples
ezpz launch python3 -m ezpz.examples.fsdp_tp \
    --dataset=allenai/olmo-mix-1124
    --model=meta-models/Muse-Spark-Open-816B-A42B \
    --local-batch-size=1
    # ...etc

Same command on every machine: ezpz picks the backend.

%%{init: {'themeVariables': {'fontSize': '22px'}, 'flowchart': {'nodeSpacing': 40, 'rankSpacing': 36, 'padding': 10}}}%% flowchart LR EZ{"<span style='font-weight:700'>ezpz launch</span>"} EZ --> AURORA["<i>PBS · Intel</i><br/><span style='font-weight:700'>Aurora</span>"] EZ --> POLARIS["<i>PBS · NVIDIA</i><br/><span style='font-weight:700'>Polaris</span>"] EZ --> PM["<i>SLURM · NVIDIA</i><br/><span style='font-weight:700'>Perlmutter</span>"] EZ --> FRONTIER["<i>SLURM · AMD</i><br/><span style='font-weight:700'>Frontier</span>"] EZ --> MAC["<span style='font-weight:700'>Multi-CPU</span>"] EZ --> MPS["<i>MPS · Apple</i><br/><span style='font-weight:700'>Multi-MPS*</span>"] classDef hub fill:none,stroke:#ee4c2c,color:#181716,stroke-width:1.8px linkStyle default stroke:#ee4c2c,stroke-width:1.8px classDef aurora fill:#3b82f608,stroke:#3b82f6,color:#3b82f6,stroke-width:1.5px classDef polaris fill:#10b98108,stroke:#10b981,color:#10b981,stroke-width:1.5px classDef perlmutter fill:#06b6d408,stroke:#06b6d4,color:#06b6d4,stroke-width:1.5px classDef frontier fill:#ef444408,stroke:#ef4444,color:#ef4444,stroke-width:1.5px classDef mac fill:#a78bfa08,stroke:#a78bfa,color:#a78bfa,stroke-width:1.5px classDef mps fill:#f59e0b08,stroke:#f59e0b,color:#d97706,stroke-width:1.5px class EZ hub class AURORA aurora class POLARIS polaris class PM perlmutter class FRONTIER frontier class MAC mac class MPS mps

*mccl (mps-ddp/mccl): MPS on Apple silicon, so ezpz launch works even on a laptop.

Benchmark the training step

  1. Fix the build, model, batch size, precision, and node count.
  2. Run the same training step on each backend.
  3. Measure step time, tokens/s, collective time, and memory.
  4. Increase node count. Rerun after kernel or collective changes.

An op test can pass while the distributed training step hangs.

Check loss and throughput at each node count. Test timeout and recovery behavior separately.4

Changes in the torchtitan training stack

LayerBefore (MDS fork + ezpz)After (torchtitan/ezpz)
ParallelismCustom tensor-parallel + pipeline in forkFSDP2 + DTensor sharding
CollectivesDeepSpeed’s NCCL assumptionsXCCL (torch-ccl) → oneCCL
KernelsFork-local fused kernelsXPU kernels via torch.xpu: layernorm+residual moved; attn/MLP/optimizer remain5
LaunchAlready ezpz: scheduler → nodes → MPISame ezpz6: launch + checkpoint-restart
CheckpointDeepSpeed engine saveDCP (torch.distributed.checkpoint)

ezpz stayed in place. Parallelism, collectives, and checkpoints moved out of the fork.

Testing at every layer

LayerGateLink
Numerics50-step loss: ±0.10 on final + last-10 meanProduction loss figure
CollectivesXCCL ladder 48 → 768 ranks, value-checkedezpz/test_dist.py
ParallelismTP1 / TP2 / MoE on Aurora; parity on Sunspotexperiments/ezpz
PortabilityOne gate on Aurora + Sunspot + Polaris + Perlmutterezpz
OrchestrationFailover harness: 9 fixturesFailover writeup

The streaming loader contributes ~0.05 loss variation from shuffle order. The 50-step check uses a ±0.10 tolerance.

AuroraGPT: production training progress

AuroraGPT 2B training loss over cumulative tokens: MDS reference, stages 1 and 2 at 256 and 512 nodes
Shown tokens / raw loss2B MDS reference7.771T / 2.0332B 256N stage 14.674T / 2.6522B 512N stage 14.674T / 2.6872B 256N stage 26.085T / 2.4692B 512N stage 26.927T / 2.481Solid: 256 nodes · dashed: 512 nodes. Training mixes differ.

Stage 2: 6.927T cumulative tokens on 512 nodes · 6.085T on 256 nodes.

Production runs and training logs · Paper forthcoming at the TPC workshop, SC26.

Detecting and recovering from stalled jobs

Job 8505298: step 37, then silence. No traceback. Watchdog at 30 min (exit 124), wrapper swapped a node, relaunched. Attempt 2 reached step 296.

flowchart LR TRAIN["step 37"] -->|"stdout idle 30 min"| WATCH["watchdog<br/>exit 124"] WATCH --> TRACE{"bad host in log?"} TRACE -->|yes| EXCLUDE["exclude host"] TRACE -->|no| SWAP["blind swap<br/>1 spare"] EXCLUDE --> RETRY["retry from ckpt"] SWAP --> RETRY RETRY -->|"step 296"| DONE["recovered"]
Step 37Training output stops for 30 minutes.
WatchdogExits with code 124.
Check the logBad host found → exclude it. No bad host → swap in one spare.
RetryResume from the checkpoint.
RecoveredAttempt 2 reaches step 296.

_set_pg_timeout has no xpu branch: timeout is stored, never enforced.7

Failure modes at ~120k XPUs

ModeSignalWhat helpsWhat doesn’t
Silent hangStdout stalls, no errorWatchdog on log progress_set_pg_timeout (xpu never arms)
Lost collectiveRank times out in XCCLNode exclude + retryRetrying on the same host
Crash / OOMTraceback + exit codeProcess restart from ckptScheduler resubmit alone
Stale FS / DCPCheckpoint read stallsAsync save + local stagingSync save on shared FS at 10k ranks

Test node exclusion, checkpoint reload, and scheduler resubmission before a long run.8

Process, node, and allocation restarts

LayerScopeTriggerCost of being wrong
Process1 rankCrash / OOMTokens since last ckpt
Node12 XPUsHang on one host1 node’s work + re-shard
Allocation10k nodesBad FS / schedulerWhole-job walltime

ezpz handles node and allocation restarts: checkpoint-restart + node exclude + scheduler resubmit. DCP writes the checkpoints.

Test each restart path before committing a full allocation.

%%{init: {'flowchart': {'nodeSpacing': 22, 'rankSpacing': 70, 'padding': 14}}}%% flowchart LR LAUNCH["ezpz launch<br/>--auto-retry"] -->|run + monitor| CLASSIFY{"Classify exit"} CLASSIFY -->|rc = 0| DONE["Done"] CLASSIFY -->|bad node + spare available| SWAP["Swap spare<br/>+ retry"] SWAP -.-> LAUNCH CLASSIFY -->|no retry possible| STOP["Stop<br/>spares exhausted /<br/>stuck before training"] class DONE retry-done class STOP retry-stop
%%{init: {'flowchart': {'nodeSpacing': 30, 'rankSpacing': 42, 'padding': 14}}}%% flowchart TB LAUNCH["ezpz launch<br/>--auto-retry"] -->|run + monitor| CLASSIFY{"Classify exit"} CLASSIFY -->|rc = 0| DONE["Done"] CLASSIFY -->|bad node + spare available| SWAP["Swap spare<br/>+ retry"] SWAP -.-> LAUNCH CLASSIFY -->|no retry possible| STOP["Stop<br/>spares exhausted /<br/>stuck before training"] class DONE retry-done class STOP retry-stop
Exit trailer + crash patterns + idle watchdog (exit 124) determine the next action.

Remaining XPU gaps

LayerGapWhat’s needed
KernelsFused attn + MLP + optimizer across XPUComposable kernels compatible with torch.compile
CollectivesTuning, diagnostics, real timeoutsXCCL timeout enforcement + DTensor split fix upstream
CheckpointsAsync DCP at 10k ranks without FS collapseLocal staging → async flush
OperationsDetect bad nodes during the runHeartbeat at the ProcessGroup level, not stdout grep

Run the training step, save a checkpoint, interrupt the job, and resume it.

Bringing up the next accelerator

  1. Test compute and collectives together.
  2. Use the same training program on each machine.
  3. Compare loss against the reference run.
  4. Measure full training steps at scale.
  5. Interrupt, restart, and check the resumed loss.

Acknowledgements

This work used resources of the Argonne Leadership Computing Facility, a DOE Office of Science user facility at Argonne National Laboratory, supported under contract DE-AC02-06CH11357.

Aurora was built in partnership with HPE and Intel: Intel Max 1550 XPU (PVC), oneAPI / oneCCL / XCCL, and the upstream torch.xpu work tracked in Act A. Thanks to the ALCF operations and support teams, the PyTorch and torchtitan maintainers, and the science teams behind GenSLM, MProt-DPO, AERIS, and AuroraGPT.

FacilityALCF · Aurora · Polaris
PartnersHPE · Intel (Max 1550 / oneAPI / oneCCL) · PyTorch Foundation
TeamsGenSLM · MProt-DPO · AERIS · AuroraGPT — see Links for papers

Aurora allocation programs

Anyone (!) can apply for time on any of the ALCF systems, including our AI Testbed!

ProgramBest forCadence
INCITELarge, peer-reviewed science campaignsAnnual
ALCCDOE-mission-aligned projectsAnnual
Director’s Discretionary (DD)Porting, benchmarking, getting started — start hereRolling, weeks

For a DD proposal, find me after the talk: [email protected] / @saforem2.

Next at ALCF: Solstice and Equinox

Announced with NVIDIA and Oracle:

SystemPlanned accelerators
Equinox10,000 NVIDIA Blackwell GPUs
Solstice100,000 NVIDIA Blackwell GPUs

The hardware, fabrics, launchers, networks, and file systems keep changing.

The same training code still needs to launch, communicate, checkpoint, and recover at scale.

Backup: inside an Aurora node

CPU socket 0Xeon CPU Max · 3 GPUs · 4 Slingshot NICs
CPU socket 1Xeon CPU Max · 3 GPUs · 4 Slingshot NICs

Each GPU has 2 tiles and 128 GiB HBM. The six GPUs connect through Xe Link; the CPUs connect through UPI.

%%{init: {'flowchart': {'nodeSpacing': 20, 'rankSpacing': 28, 'padding': 12}}}%% flowchart TB subgraph S0["CPU socket 0"] C0["Xeon CPU Max · 52 cores<br/>64 GiB HBM + 512 GiB DDR5"] G0["GPU 0 · 128 GiB HBM<br/>Tile A | Tile B"] G1["GPU 1 · 128 GiB HBM<br/>Tile A | Tile B"] G2["GPU 2 · 128 GiB HBM<br/>Tile A | Tile B"] C0 ---|PCIe 5| G0 C0 --- G1 C0 --- G2 P0["PCIe switch"] N0["4 Slingshot 11 NICs"] C0 --- P0 P0 ---|PCIe 4| N0 end subgraph S1["CPU socket 1"] C1["Xeon CPU Max · 52 cores<br/>64 GiB HBM + 512 GiB DDR5"] G3["GPU 3 · 128 GiB HBM<br/>Tile A | Tile B"] G4["GPU 4 · 128 GiB HBM<br/>Tile A | Tile B"] G5["GPU 5 · 128 GiB HBM<br/>Tile A | Tile B"] C1 ---|PCIe 5| G3 C1 --- G4 C1 --- G5 P1["PCIe switch"] N1["4 Slingshot 11 NICs"] C1 --- P1 P1 ---|PCIe 4| N1 end UPI["UPI · CPU interconnect"] --- C0 UPI --- C1 G0 -.- XE["Xe Link · all-to-all among 6 GPUs"] G1 -.- XE G2 -.- XE G3 -.- XE G4 -.- XE G5 -.- XE N0 --- NET["Slingshot network · Dragonfly topology"] N1 --- NET

6 GPUs × 2 tiles = 12 torch.xpu devices in FLAT mode. GPU Max 1550 (PVC), 768 GiB GPU HBM per node.

Logical schematic, not a wiring diagram. Xe Link connections grouped. ALCF node topology · Aurora system paper · Machine overview · PyTorch tile configuration

Session feedback

Scan to share feedback with us and the organizers.

QR code for feedback on Scaling PyTorch on Intel XPU

Footnotes

  1. The ACM Gordon Bell Prize is awarded each year at SC for outstanding achievement in high-performance computing. GenSLM won the 2022 Special Prize for HPC-Based COVID-19 Research. MProt-DPO was a 2024 finalist; AERIS was a 2025 finalist for the Special Prize for Climate Modeling. ↩

  2. ALCF Aurora · ALCF PyTorch tile-as-device configuration · ALCF support: Aurora · torchtitan/ezpz · AuroraGPT companion. ↩

  3. Megatron-DeepSpeed · torchtitan upstream · AuroraGPT companion: MDS training. ↩

  4. PyTorch profiler (torch.profiler) · PyTorch torch.xpu ↩

  5. layernorm+residual landed in torch.xpu; attn/MLP/optimizer remain — composable kernels must survive torch.compile. ↩

  6. ezpz is the cross-workload launcher: qsub/sbatch → node list → MPI on Aurora+Sunspot/Polaris. Same before and after the framework switch. ↩

  7. Failover incident: 8505298 ↩

  8. Failover incident: 8505298 · ezpz docs ↩

1
1
 Slides
Theme
▣ Deck
 Font
 Code Font
 Table of Contents
    Keybinds
    j / →Next slide / fragment k / ←Previous slide / fragment SpaceAdvance (fragments first) g / GFirst / last slide Ctrl+.Open speaker notes window EscToggle overview / close dialog fFullscreen pPrint / export to PDF ? / : / mThis dialog