Teacher-forced (parallel) TB loss recompute for recurrent estimators#526
Open
josephdviviano wants to merge 1 commit into
Open
Teacher-forced (parallel) TB loss recompute for recurrent estimators#526josephdviviano wants to merge 1 commit into
josephdviviano wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feat/kv-cache #526 +/- ##
=================================================
+ Coverage 74.49% 74.54% +0.04%
=================================================
Files 59 59
Lines 10692 10720 +28
Branches 1558 1561 +3
=================================================
+ Hits 7965 7991 +26
- Misses 2222 2223 +1
- Partials 505 506 +1
🚀 New features to boost your workflow:
|
Follow-up to the fixed-length KV-cache: with use_kv_cache=True, sampling runs
under no_grad, so gradients must come from a loss-time recompute. The existing
recompute (is_vectorized=False) re-runs the estimator per step, re-paying the
sequential rollout cost inside the loss.
This adds an opt-in teacher-forced recompute: one causal forward over the whole
committed trajectory [BOS, w0, ..., w_{L-1}], gathering per-step action log-probs.
It reuses the estimator's own full-prefix forward, so the loss-time input is built
identically to sampling; the result matches the per-step path to tolerance
(atol 1e-5) with a single grad-bearing forward and a shallow autograd graph.
- RecurrentDiscretePolicyEstimator gains teacher_forced_loss, auto-enabled by
use_kv_cache so a cached policy stays trainable (cached sampling is no_grad).
- get_trajectory_pfs takes a teacher-forced branch for recurrent estimators; the
per-step and vectorized paths are unchanged (their shared mask/scatter bookkeeping
is now factored into small helpers). Fixed-length only (guarded; see Gap-2 TODO).
- get_trajectory_pfs now fails fast, with an actionable message, when asked to reuse
detached (no_grad-sampled) log-probs under an active autograd graph — the previous
behavior was an opaque backward() error.
Together with use_kv_cache=True (recalculate_all_logprobs=True), this turns the
sampling speedup into an end-to-end training speedup; the benchmark reports both
pure-sampling and full training-step timings (~5x / ~6.8x at L=64 on CPU) and asserts
log-prob equivalence between configs.
Stacks on the KV-cache PR; stateless policies and the Sampler API are unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
josephdviviano
force-pushed
the
feat/kv-cache
branch
from
July 11, 2026 04:04
e6027f2 to
d9cfd34
Compare
josephdviviano
force-pushed
the
feat/kv-cache-teacher-forced-loss
branch
from
July 11, 2026 04:04
6cb364c to
25c24c2
Compare
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
Stacks on #525 (fixed-length KV-cache). With
use_kv_cache=True, sampling runs underno_grad, so gradients must come from a loss-time recompute. torchgfn's existing recompute for recurrent estimators (is_vectorized=False) re-runs the estimator per step, re-paying the sequential rollout cost inside the loss.This PR adds an opt-in teacher-forced (parallel) recompute: one causal forward over the whole committed trajectory
[BOS, w0, …, w_{L-1}], gathering per-step action log-probs. It reuses the estimator's own full-prefix forward, so the loss-time input is built identically to sampling; the result matches the per-step path to tolerance (atol=1e-5) with a single grad-bearing forward and a shallow autograd graph.Changes
RecurrentDiscretePolicyEstimator(teacher_forced_loss=…)— recompute PF log-probs with one parallel forward per trajectory instead of the per-step loop. Auto-enabled byuse_kv_cache, so a cached policy stays trainable out of the box (you only passrecalculate_all_logprobs=Trueat loss time).get_trajectory_pfstakes a teacher-forced branch for recurrent estimators; the per-step / vectorized paths are unchanged (their shared mask + scatter bookkeeping is now factored into small helpers). Fixed-length trajectories only (guarded; see the Gap-2TODO).get_trajectory_pfsnow raises an actionable error when asked to reuse detached (no_grad-sampled) log-probs under an active autograd graph, instead of the previous opaquebackward()failure.Result
Together with
use_kv_cache=True(recalculate_all_logprobs=True), this turns the sampling win into an end-to-end training speedup.Measured on this branch — single CPU run (Apple Silicon), batch 32, dim 64 / 4 heads / 2 layers,
word_size=1:The
|Δ log_pf|residual is the equivalence gate: both configurations are the same model, so the wall-clock gap is the optimization. Absolute figures are CPU- and machine-dependent and vary run to run; the robust claim is the trend — the training-step gap widens with sequence length, because the cached rollout is O(L²) instead of O(L³) and the loss recompute collapses to one parallel forward.Tests
testing/test_kv_cache.py: teacher-forcedlog_pf== per-step recompute; the teacher-forced path carries gradients;use_kv_cacheauto-enablesteacher_forced_loss; and the detached-log-probs guard fires with an actionable message.Unaffected
Non-recurrent estimators and the default (
teacher_forced_loss=False) path are unchanged. Stateless policies and theSamplerAPI are unaffected. Fulltesting/suite green on this branch.🤖 Generated with Claude Code