Weight Stage-2 secondary loss equally between direction and type-embedding dims

The masked flow-matching loss for the secondary decoder averaged uniformly
over all 20 per-slot dims, letting the 16 type-embedding dims outvote the
4 physically-interesting ones (stick-break logit + direction). Split the
two blocks and average each over its own width before summing, so they
contribute with equal weight regardless of EMB_DIM.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 11:41:24 +02:00
parent 4ee75d0042
commit 980b6ae7da
2 changed files with 19 additions and 8 deletions
+3
View File
@@ -15,6 +15,9 @@ K_MAX = 15
SEC_SLOT_DIM = 20 # 1 + 3 + 16
EMB_DIM = 16 # must match model emb_dim default
# Per-slot continuous (non-embedding) width: stick-breaking logit + local dir.
CONT_SLOT_DIM = SEC_SLOT_DIM - EMB_DIM # 4
# Flattened Stage-2 target dimension
SEC_DIM = K_MAX * SEC_SLOT_DIM # 15 * 20 = 300
+16 -8
View File
@@ -86,8 +86,14 @@ def flow_matching_loss_secondary(
Only valid-slot dimensions contribute to the loss; padded slots are zeroed
before averaging, so the loss is not diluted by empty slots.
Each slot packs CONT_SLOT_DIM continuous dims (stick_logit, dir) followed
by EMB_DIM type-embedding dims. A flat per-dimension mean would let the
16 embedding dims outvote the 4 physically-interesting ones, so the two
blocks are each averaged over their own width first and then combined
with equal weight — this stays correct if EMB_DIM/CONT_SLOT_DIM change.
"""
from giant.constants import SEC_SLOT_DIM
from giant.constants import CONT_SLOT_DIM, EMB_DIM, K_MAX, SEC_SLOT_DIM
B = x1.size(0)
t = torch.rand(B, device=x1.device)
@@ -96,10 +102,12 @@ def flow_matching_loss_secondary(
u_t = x1 - x0
v_t = model(x_t, t, cond_cont, cond_cat, stage1_out)
# Expand mask: (B, K_MAX) → (B, K_MAX * SEC_SLOT_DIM)
mask_expanded = (
sec_mask.float().unsqueeze(-1).expand(-1, -1, SEC_SLOT_DIM).reshape(B, -1)
)
err = (v_t - u_t) ** 2
denom = mask_expanded.sum().clamp(min=1)
return (err * mask_expanded).sum() / denom
err = ((v_t - u_t) ** 2).view(B, K_MAX, SEC_SLOT_DIM)
cont_err = err[..., :CONT_SLOT_DIM].mean(dim=-1) # (B, K_MAX)
emb_err = err[..., CONT_SLOT_DIM : CONT_SLOT_DIM + EMB_DIM].mean(dim=-1)
mask = sec_mask.float()
denom = mask.sum().clamp(min=1)
cont_loss = (cont_err * mask).sum() / denom
emb_loss = (emb_err * mask).sum() / denom
return cont_loss + emb_loss