Weight the TiledLoss backward pass the way the forward does - #8587
vineethsaivs wants to merge 2 commits into
Conversation
Carry the per shard token counts through to backward, scale each shard's incoming gradient by its share of the labels, and drop the division by the shard count. Signed-off-by: Vineeth Sai <vineethsai4444@gmail.com>
|
Could you approve the CI run? Three regressions fail before, the gradient off by 0.375x to 1.5x while the forward matches. Twelve CPU tests pass after, covering a fully masked shard, uneven token counts and more shards than live tokens, against token mean cross entropy in float64. Changed-file pre-commit passes. |
|
Blast radius, since this touches the gradient every Ulysses SP run takes. The even case is provably unchanged. When every shard holds the same number of live labels, What moves is only the case the forward already treats specially: shards with different numbers of non The forward was already correct and is untouched; it agrees with plain token mean cross entropy to 1.19e-07, which is float32 eps from the loss function's own |
|
Thank you for the PR, @vineethsaivs why are you trying to use TiledLoss? I just left it there in case someone was already using it - I probably should delete everything after or perhaps mark those deprecated Any reason why you're not using one of these 3 as documented here? That is:
|
|
Honest answer: I'm not using it. I was reading through the sequence parallel loss code checking that each backward actually matches its own forward, and So if Want me to send a deprecation or removal PR instead? |
|
sure, that would be very kind of you to delete them all after that line including the line, @vineethsaivs - thank you. you can re-use this PR. I guess they were premature prototypes as I was developing this feature, so weren't well tested and you discovered proved to be buggy. |
alanhuangyoo
left a comment
There was a problem hiding this comment.
Ran your tests on an H20 since the description says CPU only: same three gradient cases fail on master, all 12 pass here.
Small one, non-blocking: good_items is a device tensor, so ctx.good_items_per_shard keeps one per shard alive until backward and the weight multiply runs on device. int(...) at the point you append would make it a plain number and the masked-shard entry would stop being the odd one out type-wise.
|
@alanhuangyoo, if you read my comment above this PR is going to change to drop this class altogether - so nothing needs to be fixed. |
|
Got it, no action needed then. Deleting it is the better fix. |
TiledLoss returns a loss whose gradient is not the derivative of that loss.
forwardtakes a token weighted average over the shards and skips fully masked ones.backwardruns autograd on each shard's own mean and divides by the shard count, so masked shards stay in the denominator and live ones lose their weights. Carry the per shard token counts through to backward, scale each shard's incoming gradient by its share of the labels, and drop the division by the shard count.Test:
TORCHDYNAMO_DISABLE=1 DS_ACCELERATOR=cpu PYTHONPATH=. python -m pytest tests/unit/ulysses_alst/test_tiled_loss.py -q. Three regressions fail before, the gradient off by 0.375x to 1.5x while the forward matches. Twelve CPU tests pass after, covering a fully masked shard, uneven token counts and more shards than live tokens, against token mean cross entropy in float64. Changed-file pre-commit passes. Executed on Apple M2 Pro CPU; no CUDA or distributed training run.