Repository navigation
[trainer throughput] Carry Miles rows and log probabilities as arrays - #158
Merged
Merged
Conversation
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
from
October 28, 2026 16:29
21e4945 to
10335f7
Compare
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
from
October 28, 2026 21:43
10335f7 to
8d5d033
Compare
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
from
October 28, 2026 21:49
8d5d033 to
f23ab9a
Compare
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
from
October 28, 2026 21:50
f23ab9a to
e0109cc
Compare
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
from
October 28, 2026 21:51
e0109cc to
b653264
Compare
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
2 times, most recently
from
October 28, 2026 21:54
1e9d950 to
66a3157
Compare
micahtyong
marked this pull request as ready for review
October 28, 2026 21:56
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
2 times, most recently
from
October 28, 2026 22:00
1fccd05 to
7dd0030
Compare
Rows reach the Miles object store as numpy arrays instead of per-token Python lists, and per-datum log probabilities come back as arrays. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
micahtyong
force-pushed
the
micah/perf-4b/A1-array-rows
branch
from
October 28, 2026 22:40
7dd0030 to
f9fa0c4
Compare
Collaborator
Author
|
We'll need to upstream this to miles, but otherwise lgtm |
This was referenced Oct 28, 2026
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
Inside the trainer container, the Miles backend runs as one controller process and one actor process per GPU. For every
forwardorforward_backwardcall the controller builds the batch, puts it in the Ray object store, and each actor pulls the whole batch out and keeps its data-parallel share. When the actors finish, each sends its per-datum log probabilities back and the controller assembles the result.Until now the batch crossed that boundary as nested Python lists: one
intper token and onefloatper label weight, about 2.3 million Python objects per 128-example call for a classifier with 5 labels per position. Pickling and unpickling that many objects is slow, and it is slow by a different amount on each actor. The step-2 trace showed the cost in two places. After each actor returned, the controller spent about 0.9 s turning the returned lists into results. And at the start of everyforward_backward, rank 0 sat 0.73 s at the first collective waiting for ranks 1–3 to finish unpickling. (A collective is the point where all ranks synchronize; the first one there waits for the rest.)Arrays fix both. Numpy arrays pickle as one buffer each, Ray hands them to the actors without copying, and
torch.tensorbuilds a GPU tensor from an array without walking it in Python. So this change keeps the rows as arrays fromprepare_batchto the actors, and brings the log probabilities back as arrays.data.py:tokens,target_tokens,weights,advantagesandsampling_logprobsare arrays. Sequence alignment and data-parallel padding pad arrays.runtime.py: Miles' bridge is subclassed so loss masks go in as arrays and per-datum log probabilities come back as arrays instead of through.tolist(). Weights, advantages and sampling log probabilities are sent as CPU tensors, because Miles slices those per context-parallel rank with either list+ortorch.cat, and an array would reachtorch.cat.replay_data.py: sampling-support validation accepts array target rows.Stacks on #154, which prepared the rows with numpy but still turned them into lists at the end.
E2E results
A 4B LoRA classifier with 5 candidate labels per position on 4×H100,
max_tokens_per_gpu8192, with #157 and #152–#154 applied. Each step runs twoforwardcalls on a frozen adapter, oneforward_backwardon the trained adapter, thenoptim_step; 128 examples of about 1,630 tokens per call. Same driver and data for both rows; 34 steps, steady-state medians.Before WandB / After WandB
forward_backward(trainer)forwardcalls (trainer)forward_backwardStep-0 log probabilities are bit-identical before and after. The after run traced all four ranks; the wait is 0.000 s on every one of them.
🤖 Generated with Claude Code