Fix DeepCompile ZeRO-3 gathered parameter ownership - #8157
Conversation
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4563ff10f8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
| for param in self.params: | ||
| depth = getattr(param, _GATHERED_PARAM_CONTEXT_DEPTH_ATTR, 0) | ||
| setattr(param, _GATHERED_PARAM_CONTEXT_DEPTH_ATTR, depth + 1) | ||
| fallback_owner = getattr(param, "_deepcompile_z3_eager_fallback_owner", None) |
There was a problem hiding this comment.
let's import and use _FALLBACK_OWNER_ATTR?
There was a problem hiding this comment.
Good catch! Fixed.
| # official CPU builds 2.8.0+cpu, 2.9.1+cpu, 2.10.0+cpu, 2.11.0+cpu, 2.12.0+cpu, and 2.13.0+cpu. | ||
| frame = sys._getframe() | ||
| while frame is not None: | ||
| if frame.f_globals.get("__name__") == "torch._dynamo.guards": |
There was a problem hiding this comment.
is "torch._dynamo.guards" prone to change e.g. when torch version changes?
There was a problem hiding this comment.
Yes, it can change. I could not find a public API for detecting guard evaluation specifically. torch.compiler.is_compiling() returns false in this path. However, it still works even we fail to find torch._dynamo.guards.
If the module path changes, this check returns false and the guard access is treated as a normal eager fallback access. That causes an unnecessary all-gather and may increase communication and memory usage, but it does not skip an all-gather required by actual eager execution.
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
85ec78f to
4db398b
Compare
pengdurice
left a comment
There was a problem hiding this comment.
General question, if some one does this:
loss = engine(input)
with GatheredParameters([W]):
log(W.norm())
engine.backward(loss)
will that cause issue since the GatheredParameters context manager already partitions the parameters when it exits?
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
|
@pengdurice Great catch! Yes, in this pattern, the parameter can be partitioned too early. I updated the PR branch to address it. Instead of transferring the ownership of the fallback and the gathered parameter, we now records claims of the ownership as a set (it is like a reference count). The parameter is partitioned only after the last claim is released. |
Signed-off-by: Masahiro Tanaka <mtanaka@anyscale.com>
Problem
DeepCompile inserts ZeRO-3 parameter all-gather and release operations into compiled graphs. When Dynamo skips a frame because of a graph break, however, that frame executes eagerly and does not run those graph operations. The eager fallback introduced in #8059 handles this case by all-gathering a partitioned parameter when the skipped frame accesses it through
ZeROOrderedDict.The fallback is enabled around
DeepSpeedEngine.forward(). Dynamo guard evaluation occurs inside that outer forward context and also resolves parameters throughZeROOrderedDict, whiletorch.compiler.is_compiling()is false. The fallback could therefore mistake a guard lookup for actual eager execution and unnecessarily all-gather the parameter.Parameters gathered by the fallback are normally partitioned after backward, but that cleanup does not run when backward is skipped. A fallback-gathered parameter may also be passed to an explicit
GatheredParameterscontext, which must keep the full tensor available until the context exits.Why it matters
These cases require different behavior:
GatheredParametersmust remain fully gathered until that context exits.Without distinguishing these cases, a full parameter can remain allocated into a later forward, or fallback cleanup can partition it while a
GatheredParametersblock is still using it.Solution
This PR:
GatheredParameters, so that context alone partitions it on exit;GatheredParametersstate even when context exit raises; andGatheredParameterscontexts that overlap on the same parameter, while continuing to allow nesting over disjoint parameter sets.