Share equivalent RoPE cache storage - #4376
Conversation
|
|
||
|
|
||
| @contextlib.contextmanager | ||
| def _rope_cache_registry_context(registry: "_RoPECacheRegistry"): |
There was a problem hiding this comment.
why do we need the capability of switch "registry", instead of always only having one default
| self.config = config | ||
| self.register_buffer("cache", self._precompute_cache(), persistent=False) | ||
| self._cache_reader: RoPECacheReader | None = None | ||
| cache = self._precompute_cache() |
There was a problem hiding this comment.
although memory is saved, compute seems still wasted
There was a problem hiding this comment.
Does it cover https://github.com/pytorch/torchtitan/blob/main/torchtitan/overrides/helion_rope.py -- it looks so because cache construction code is shared.
| "MTPTransformerBlock.Config instances." | ||
| ) | ||
| self.mtp_layers.append(layer_config.build()) | ||
| with self._rope_cache_context(): |
There was a problem hiding this comment.
related to the other comment -- why MTP requires an explicit context
|
@claude Personally I like this one better since its cache management is explicit. Please review this PR. In particular
|
|
Claude finished @tianyu-l's task in 10m 22s —— View job Review: Share equivalent RoPE cache storageI read the three commits on this branch (
Do your four comments make sense? Yes, all four.1. 2. The reason compute can't be skipped today is that 3. 4. The thing I'd fix before landing: the
|
|
Can't we just keep the cache at the RoPE module level, without touching Decoder at all? |
|
Claude finished @tianyu-l's task in 1m 55s —— View job Re: "Can't we just keep the cache at the RoPE module level, without touching Decoder at all?"Short answer: not while actually saving the memory. "Cache lives on the RoPE module" and "storage is shared" pull in opposite directions, because the memory win has to survive the model lifecycle -- and the lifecycle is exactly where a naive shared reference re-duplicates. Why a per-module buffer can't share storage on its own
The identity link is broken at exactly the step that allocates the memory you were trying to save. That's why the PR resolves the slot on every So dedup requires three things, no matter where you put it: a single canonical buffer, an owner stable enough to re-materialize it once, and a scoped lookup so independent models (ref+policy in RL, PP stages, tests) don't coalesce. That trio is the registry + reader. The only real design freedom is who owns the canonical buffer. The three places the owner could live
Recommendation Keeping Decoder as the owner is the right call -- it's a stable, model-scoped container and matches the semantics of the cache. The touch on Net: the Decoder coupling is inherent to sharing storage and is the cleanest of the three owners; the complexity worth removing is the contextvar, not the Decoder.
|
|
@claude
If we reverse it, we could avoid calling Another doubt: |
|
Claude finished @tianyu-l's task in 5m 37s —— View job Re: reversing init/parallelize, and explicit cache-passing vs. Decoder ownershipTwo good questions. Short version: reversing the order does not cleanly remove the problem (and gives up the reason meta-init exists), and "pass the cache to each attention" is the right instinct but in practice collapses back into "the Decoder owns the caches and hands them down" -- the part worth deleting is the Q1: "This only happens because we meta-init then parallelize. If we reverse it, we avoid
|
I don't believe there's a lot of heterogenous rope used in the same model. It's usually at most one. In that case, how about
|
|
Claude finished @tianyu-l's task in 4m 46s —— View job Re: Decoder-owned single
|
|
@Mystri see if you agree with #4376 (comment) |
We cannot safely assert homogeneity for newer models such as deepseek-v4, which computes My proposal that fits yours best is that the |
No description provided.