lifatsastain's picture
add src floder
45f5949
Raw
History Blame Contribute Delete
27.5 kB
import random
import torch
import torch.nn.functional as F
from stage2_config import *
from stage2_losses import flow_matching_loss
from stage2_riemannian import generate_suffix, prompt_condition, suffix_positions
def seed_everything(seed):
random.seed(seed)
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
def sample_token_ids(
logits,
tokenizer,
temperature=EVAL_SAMPLE_TEMPERATURE,
top_k=EVAL_SAMPLE_TOP_K,
top_p=EVAL_SAMPLE_TOP_P,
):
if temperature <= 0:
return logits.argmax(dim=-1)
logits = logits.float() / temperature
for token_id in tokenizer.all_special_ids:
logits[..., token_id] = -float("inf")
if top_k is not None and top_k > 0:
kth = logits.topk(min(top_k, logits.size(-1)), dim=-1).values[..., -1, None]
logits = logits.masked_fill(logits < kth, -float("inf"))
if top_p is not None and 0.0 < top_p < 1.0:
sorted_logits, sorted_idx = logits.sort(dim=-1, descending=True)
sorted_probs = sorted_logits.softmax(dim=-1)
keep = sorted_probs.cumsum(dim=-1) <= top_p
keep[..., 0] = True
sorted_logits = sorted_logits.masked_fill(~keep, -float("inf"))
logits = torch.full_like(logits, -float("inf")).scatter(dim=-1, index=sorted_idx, src=sorted_logits)
probs = logits.softmax(dim=-1)
return torch.multinomial(probs.reshape(-1, probs.size(-1)), 1).view(logits.shape[:-1])
def generated_decode_stats(z_real, z_gen_suffix, suffix_mask, input_ids, attn_mask, decoder, device):
z_gen_flat = z_gen_suffix[suffix_mask]
real_flat = z_real[:, PROMPT_LEN:, :][suffix_mask]
gen_mean = z_gen_flat.mean().item()
gen_std = z_gen_flat.std().item()
cosine_sim = F.cosine_similarity(
real_flat.mean(0, keepdim=True),
z_gen_flat.mean(0, keepdim=True),
).item()
decode_idx = (attn_mask[:, PROMPT_LEN:].sum(dim=1) > 0).nonzero(as_tuple=False).flatten()
decode_idx = decode_idx[:DECODE_LOSS_BATCH]
if decode_idx.numel() == 0:
return gen_mean, gen_std, cosine_sim, 0.0
z_decode_gen = torch.cat([z_real[:, :PROMPT_LEN, :], z_gen_suffix], dim=1)[decode_idx]
decode_targets = input_ids[decode_idx, PROMPT_LEN:].reshape(-1)
with torch.amp.autocast("cuda", enabled=device.type == "cuda"):
gen_decode_logits = decoder.decode_from_latent(z_decode_gen)
gen_decode_ce = F.cross_entropy(
gen_decode_logits[:, PROMPT_LEN:, :].reshape(-1, gen_decode_logits.size(-1)),
decode_targets,
ignore_index=0,
).item()
return gen_mean, gen_std, cosine_sim, gen_decode_ce
def latent_mix_decode_ce(z_real, z_gen_suffix, input_ids, attn_mask, decoder, device, alphas=(0.01, 0.03, 0.05, 0.10, 0.20, 0.50)):
decode_idx = (attn_mask[:, PROMPT_LEN:].sum(dim=1) > 0).nonzero(as_tuple=False).flatten()
decode_idx = decode_idx[:DECODE_LOSS_BATCH]
if decode_idx.numel() == 0:
return []
z_real_suffix = z_real[:, PROMPT_LEN:, :]
decode_targets = input_ids[decode_idx, PROMPT_LEN:].reshape(-1)
results = []
for alpha in alphas:
z_mix_suffix = (1.0 - alpha) * z_gen_suffix + alpha * z_real_suffix
z_mix_seq = torch.cat([z_real[:, :PROMPT_LEN, :], z_mix_suffix], dim=1)[decode_idx]
with torch.amp.autocast("cuda", enabled=device.type == "cuda"):
mix_logits = decoder.decode_from_latent(z_mix_seq)
mix_ce = F.cross_entropy(
mix_logits[:, PROMPT_LEN:, :].reshape(-1, mix_logits.size(-1)),
decode_targets,
ignore_index=0,
).item()
results.append((alpha, mix_ce))
return results
def argmax_token_collapse_stats(logits, token_ids, tokenizer):
suffix_logits = logits[:, PROMPT_LEN:, :].float()
suffix_ids = token_ids[:, PROMPT_LEN:]
probs = suffix_logits.softmax(dim=-1)
entropy = -(probs * probs.clamp_min(1e-9).log()).sum(dim=-1).mean().item()
unique_ratios = []
max_fracs = []
flat_tokens = []
for row in suffix_ids:
valid = row[~torch.isin(row, row.new_tensor(tokenizer.all_special_ids))]
if valid.numel() == 0:
continue
counts = torch.bincount(valid.cpu(), minlength=logits.size(-1))
unique_ratios.append((counts > 0).sum().item() / valid.numel())
max_fracs.append(counts.max().item() / valid.numel())
flat_tokens.append(valid.cpu())
if flat_tokens:
flat = torch.cat(flat_tokens)
counts = torch.bincount(flat, minlength=logits.size(-1))
top_counts, top_ids = counts.topk(min(5, counts.numel()))
top_tokens = [
f"{tokenizer.convert_ids_to_tokens(int(token_id))}:{int(count)}"
for token_id, count in zip(top_ids.tolist(), top_counts.tolist())
if count > 0
]
else:
top_tokens = []
return {
"entropy": entropy,
"unique_ratio": sum(unique_ratios) / max(len(unique_ratios), 1),
"max_frac": sum(max_fracs) / max(len(max_fracs), 1),
"top_tokens": top_tokens,
}
def decoder_distribution_stats(logits, tokenizer, mask=None, oracle_logits=None, target_ids=None):
suffix_logits = logits[:, PROMPT_LEN:, :].float()
probs = suffix_logits.softmax(dim=-1)
top1_acc = 0.0
target_prob_mean = 0.0
oracle_top1_acc = 0.0
oracle_target_prob_mean = 0.0
if target_ids is not None:
suffix_targets = target_ids[:, PROMPT_LEN:] if target_ids.size(1) == logits.size(1) else target_ids
target_valid = suffix_targets != 0
if mask is not None:
target_valid = target_valid & mask.bool()
if target_valid.any():
target_gather_ids = suffix_targets.clamp(0, probs.size(-1) - 1).unsqueeze(-1)
target_probs = probs.gather(dim=-1, index=target_gather_ids).squeeze(-1)
top_ids = probs.argmax(dim=-1)
top1_acc = (top_ids[target_valid] == suffix_targets[target_valid]).float().mean().item()
target_prob_mean = target_probs[target_valid].mean().item()
if oracle_logits is not None:
oracle_probs_full = oracle_logits[:, PROMPT_LEN:, :].float().softmax(dim=-1)
oracle_target_probs = oracle_probs_full.gather(dim=-1, index=target_gather_ids).squeeze(-1)
oracle_top_ids = oracle_probs_full.argmax(dim=-1)
oracle_top1_acc = (
oracle_top_ids[target_valid] == suffix_targets[target_valid]
).float().mean().item()
oracle_target_prob_mean = oracle_target_probs[target_valid].mean().item()
if mask is not None:
valid = mask.bool()
if valid.any():
probs = probs[valid]
suffix_logits = suffix_logits[valid]
if oracle_logits is not None:
oracle_suffix_logits = oracle_logits[:, PROMPT_LEN:, :].float()[valid]
else:
probs = probs.reshape(-1, probs.size(-1))
suffix_logits = suffix_logits.reshape(-1, suffix_logits.size(-1))
oracle_suffix_logits = None
else:
probs = probs.reshape(-1, probs.size(-1))
suffix_logits = suffix_logits.reshape(-1, suffix_logits.size(-1))
oracle_suffix_logits = (
oracle_logits[:, PROMPT_LEN:, :].float().reshape(-1, oracle_logits.size(-1))
if oracle_logits is not None
else None
)
special_ids = torch.tensor(tokenizer.all_special_ids, device=probs.device)
entropy = -(probs * probs.clamp_min(1e-9).log()).sum(dim=-1)
top_probs, _ = probs.topk(min(50, probs.size(-1)), dim=-1)
mean_probs = probs.clone()
mean_probs[:, special_ids] = 0.0
mean_probs = mean_probs.mean(dim=0)
batch_top_mass = mean_probs.topk(min(8, mean_probs.numel())).values.sum()
special_mass = probs[:, special_ids].sum(dim=-1)
kl_to_oracle = None
if oracle_logits is not None and oracle_suffix_logits is not None:
oracle_log_probs = F.log_softmax(oracle_suffix_logits, dim=-1)
gen_log_probs = F.log_softmax(suffix_logits, dim=-1)
kl_to_oracle = F.kl_div(gen_log_probs, oracle_log_probs.exp(), reduction="batchmean").item()
return {
"entropy": entropy.mean().item(),
"top1_prob": top_probs[:, 0].mean().item(),
"top5_mass": top_probs[:, :min(5, top_probs.size(1))].sum(dim=-1).mean().item(),
"top50_mass": top_probs.sum(dim=-1).mean().item(),
"batch_top8_mass": batch_top_mass.item(),
"special_mass": special_mass.mean().item(),
"kl_to_oracle": kl_to_oracle,
"top1_acc": top1_acc,
"target_prob": target_prob_mean,
"oracle_top1_acc": oracle_top1_acc,
"oracle_target_prob": oracle_target_prob_mean,
}
def fuse_aux_logits(flow_net, aux_token_head, decoder_logits, z_suffix, z_cond, mask=None):
if aux_token_head is None or AUX_LOGIT_FUSION_BETA <= 0:
return decoder_logits
B, T, _ = z_suffix.shape
pos = suffix_positions(B, T, z_suffix.device, z_suffix.dtype)
t = torch.ones(B, T, device=z_suffix.device, dtype=z_suffix.dtype)
_, aux_hidden = flow_net(z_suffix, t, z_cond, pos, mask, return_hidden=True)
aux_logits = aux_token_head(aux_hidden).float()
fused_logits = decoder_logits.float().clone()
fused_logits[:, PROMPT_LEN:, :] = fused_logits[:, PROMPT_LEN:, :] + AUX_LOGIT_FUSION_BETA * aux_logits
return fused_logits
def evaluate(
flow_net,
metric_net,
encoder,
decoder,
tokenizer,
val_loader,
device,
n_samples=4,
start_mlp=None,
aux_token_head=None,
latent_projector=None,
residual_refiner=None,
draft_start_fn=None,
):
flow_net.eval()
metric_net.eval()
encoder.eval()
decoder.eval()
if start_mlp is not None:
start_mlp.eval()
if aux_token_head is not None:
aux_token_head.eval()
if latent_projector is not None:
latent_projector.eval()
if residual_refiner is not None:
residual_refiner.eval()
val_loss = 0
eval_rng_state = torch.random.get_rng_state()
cuda_rng_state = torch.cuda.get_rng_state_all() if device.type == "cuda" else None
with torch.no_grad():
for batch in val_loader:
input_ids = batch["input_ids"].to(device, non_blocking=True)
attention_mask = batch["attention_mask"].to(device, non_blocking=True)
with torch.amp.autocast("cuda", enabled=device.type == "cuda"):
z_data = decoder.compress(encoder(input_ids, attention_mask))
z_cond = prompt_condition(z_data, attention_mask)
z_target = z_data[:, PROMPT_LEN:, :]
target_mask = attention_mask[:, PROMPT_LEN:]
z_draft_start = draft_start_fn(input_ids, attention_mask) if draft_start_fn is not None else None
val_loss += flow_matching_loss(
flow_net,
metric_net,
z_target,
z_cond,
target_mask,
start_mlp=start_mlp,
residual_refiner=residual_refiner,
z_draft_start=z_draft_start,
).item()
avg_val_loss = val_loss / len(val_loader)
with torch.no_grad():
seed_everything(SEED + 10_000)
batch = next(iter(val_loader))
input_ids = batch["input_ids"].to(device)
attn_mask = batch["attention_mask"].to(device)
z_real = decoder.compress(encoder(input_ids, attn_mask))
B, S, D = z_real.shape
suffix_mask = attn_mask[:, PROMPT_LEN:].bool()
z_real_suffix = z_real[:, PROMPT_LEN:, :]
z_draft_start = draft_start_fn(input_ids, attn_mask) if draft_start_fn is not None else None
z_real_flat = z_real_suffix[suffix_mask]
z_cond = prompt_condition(z_real, attn_mask)
if z_draft_start is not None and start_mlp is not None and hasattr(start_mlp, "set_draft_target"):
start_mlp.set_draft_target(z_draft_start)
z_gen_suffix, metric_snapshot, z_initial_suffix, z_uncalibrated_suffix = generate_suffix(
flow_net,
metric_net,
z_cond,
B,
S - PROMPT_LEN,
D,
device,
mask=suffix_mask,
start_mlp=start_mlp,
z_target_start=z_real_suffix if STRUCTURED_TARGET_START else None,
)
z_projected_suffix = z_gen_suffix
if residual_refiner is not None:
pos_res = suffix_positions(B, S - PROMPT_LEN, device, z_real.dtype)
z_projected_suffix, _residual_delta = residual_refiner(
z_projected_suffix,
z_real[:, :PROMPT_LEN, :],
pos_res,
suffix_mask,
)
if latent_projector is not None:
z_projected_suffix, projector_delta = latent_projector(
z_gen_suffix,
z_real[:, :PROMPT_LEN, :],
suffix_mask,
)
projector_delta_norm = projector_delta[suffix_mask].norm(dim=-1).mean().item()
else:
projector_delta_norm = 0.0
z_gen_flat = z_gen_suffix[suffix_mask]
z_projected_flat = z_projected_suffix[suffix_mask]
z_initial_flat = z_initial_suffix[suffix_mask]
z_uncalibrated_flat = z_uncalibrated_suffix[suffix_mask]
real_mean = z_real_flat.mean().item()
real_std = z_real_flat.std().item()
real_norm = z_real_flat.norm(dim=-1).mean().item()
initial_mean = z_initial_flat.mean().item()
initial_std = z_initial_flat.std().item()
initial_norm = z_initial_flat.norm(dim=-1).mean().item()
uncal_mean = z_uncalibrated_flat.mean().item()
uncal_std = z_uncalibrated_flat.std().item()
uncal_norm = z_uncalibrated_flat.norm(dim=-1).mean().item()
gen_mean, gen_std, cosine_sim, gen_decode_ce = generated_decode_stats(
z_real,
z_projected_suffix,
suffix_mask,
input_ids,
attn_mask,
decoder,
device,
)
mix_decode_ce = latent_mix_decode_ce(
z_real,
z_gen_suffix,
input_ids,
attn_mask,
decoder,
device,
)
raw_gen_mean = z_gen_flat.mean().item()
raw_gen_std = z_gen_flat.std().item()
projected_norm = z_projected_flat.norm(dim=-1).mean().item()
if start_mlp is not None:
pos_start = suffix_positions(B, S - PROMPT_LEN, device, z_real.dtype)
if z_draft_start is not None and hasattr(start_mlp, "set_draft_target"):
start_mlp.set_draft_target(z_draft_start)
z_coarse_suffix = start_mlp(z_cond, pos_start, suffix_mask)
coarse_mean, coarse_std, coarse_cosine, coarse_decode_ce = generated_decode_stats(
z_real,
z_coarse_suffix,
suffix_mask,
input_ids,
attn_mask,
decoder,
device,
)
coarse_mse = F.mse_loss(z_coarse_suffix[suffix_mask], z_real_suffix[suffix_mask]).item()
coarse_decode_idx = (attn_mask[:, PROMPT_LEN:].sum(dim=1) > 0).nonzero(as_tuple=False).flatten()
coarse_decode_idx = coarse_decode_idx[:DECODE_LOSS_BATCH]
if coarse_decode_idx.numel() > 0:
coarse_seq = torch.cat([z_real[:, :PROMPT_LEN, :], z_coarse_suffix], dim=1)[coarse_decode_idx]
coarse_targets = input_ids[coarse_decode_idx, PROMPT_LEN:]
coarse_valid = coarse_targets != 0
with torch.amp.autocast("cuda", enabled=device.type == "cuda"):
coarse_logits = decoder.decode_from_latent(coarse_seq)[:, PROMPT_LEN:, :].float()
coarse_probs = coarse_logits.softmax(dim=-1)
coarse_target_ids = coarse_targets.clamp(0, coarse_probs.size(-1) - 1).unsqueeze(-1)
coarse_target_probs = coarse_probs.gather(dim=-1, index=coarse_target_ids).squeeze(-1)
coarse_target_prob = coarse_target_probs[coarse_valid].mean().item() if coarse_valid.any() else 0.0
else:
coarse_target_prob = 0.0
else:
coarse_mean = 0.0
coarse_std = 0.0
coarse_cosine = 0.0
coarse_decode_ce = 0.0
coarse_mse = 0.0
coarse_target_prob = 0.0
_, _, _, initial_decode_ce = generated_decode_stats(
z_real,
z_initial_suffix,
suffix_mask,
input_ids,
attn_mask,
decoder,
device,
)
_, _, _, uncal_decode_ce = generated_decode_stats(
z_real,
z_uncalibrated_suffix,
suffix_mask,
input_ids,
attn_mask,
decoder,
device,
)
metric_valid = metric_snapshot[suffix_mask] if metric_snapshot is not None else z_gen_flat.new_ones(z_gen_flat.shape)
metric_mean = metric_valid.mean().item()
metric_std = metric_valid.std().item()
metric_min = metric_valid.min().item()
metric_max = metric_valid.max().item()
decode_idx = (attn_mask[:, PROMPT_LEN:].sum(dim=1) > 0).nonzero(as_tuple=False).flatten()
decode_idx = decode_idx[:DECODE_LOSS_BATCH]
if decode_idx.numel() > 0:
z_decode_real = z_real[decode_idx]
z_decode_gen = torch.cat([z_real[:, :PROMPT_LEN, :], z_projected_suffix], dim=1)[decode_idx]
decode_targets = input_ids[decode_idx, PROMPT_LEN:].reshape(-1)
with torch.amp.autocast("cuda", enabled=device.type == "cuda"):
real_decode_logits = decoder.decode_from_latent(z_decode_real)
gen_decode_logits = decoder.decode_from_latent(z_decode_gen)
fused_decode_logits = fuse_aux_logits(
flow_net,
aux_token_head,
gen_decode_logits,
z_projected_suffix[decode_idx],
z_cond[decode_idx],
suffix_mask[decode_idx],
)
real_decode_ce = F.cross_entropy(
real_decode_logits[:, PROMPT_LEN:, :].reshape(-1, real_decode_logits.size(-1)),
decode_targets,
ignore_index=0,
).item()
fused_decode_ce = F.cross_entropy(
fused_decode_logits[:, PROMPT_LEN:, :].reshape(-1, fused_decode_logits.size(-1)),
decode_targets,
ignore_index=0,
).item()
fused_suffix_logits = fused_decode_logits[:, PROMPT_LEN:, :].float()
fused_targets = input_ids[decode_idx, PROMPT_LEN:]
fused_valid = fused_targets != 0
if fused_valid.any():
fused_probs = fused_suffix_logits.softmax(dim=-1)
fused_target_ids = fused_targets.clamp(0, fused_probs.size(-1) - 1).unsqueeze(-1)
fused_decode_target_prob = (
fused_probs.gather(dim=-1, index=fused_target_ids).squeeze(-1)[fused_valid]
.mean()
.item()
)
else:
fused_decode_target_prob = 0.0
else:
real_decode_ce = 0.0
fused_decode_ce = gen_decode_ce
fused_decode_target_prob = 0.0
decode_ce_gap = gen_decode_ce - real_decode_ce
fused_decode_ce_gap = fused_decode_ce - real_decode_ce
with torch.no_grad():
sample_idx = (attn_mask[:, PROMPT_LEN:].sum(dim=1) > 0).nonzero(as_tuple=False).flatten()
sample_idx = sample_idx[:n_samples]
z_gen_seq = torch.cat([z_real[:, :PROMPT_LEN, :], z_projected_suffix], dim=1)[sample_idx]
with torch.amp.autocast("cuda", enabled=device.type == "cuda"):
raw_logits = decoder.decode_from_latent(z_gen_seq)
logits = fuse_aux_logits(
flow_net,
aux_token_head,
raw_logits,
z_projected_suffix[sample_idx],
z_cond[sample_idx],
attn_mask[sample_idx, PROMPT_LEN:],
)
oracle_logits = decoder.decode_from_latent(z_real[sample_idx])
pred_ids = logits.argmax(-1)
sampled_ids = sample_token_ids(logits, tokenizer)
oracle_ids = oracle_logits.argmax(-1)
gen_collapse = argmax_token_collapse_stats(logits, pred_ids, tokenizer)
sampled_collapse = argmax_token_collapse_stats(logits, sampled_ids, tokenizer)
oracle_collapse = argmax_token_collapse_stats(oracle_logits, oracle_ids, tokenizer)
sample_suffix_mask = attn_mask[sample_idx, PROMPT_LEN:]
sample_target_ids = input_ids[sample_idx]
gen_dist = decoder_distribution_stats(
logits,
tokenizer,
sample_suffix_mask,
oracle_logits=oracle_logits,
target_ids=sample_target_ids,
)
raw_gen_dist = decoder_distribution_stats(
raw_logits,
tokenizer,
sample_suffix_mask,
oracle_logits=oracle_logits,
target_ids=sample_target_ids,
)
oracle_dist = decoder_distribution_stats(
oracle_logits,
tokenizer,
sample_suffix_mask,
target_ids=sample_target_ids,
)
print("\n-- riemannian samples -----------------------------------------")
for sample_pos, batch_idx in enumerate(sample_idx.tolist()):
prompt = tokenizer.decode(input_ids[batch_idx, :PROMPT_LEN], skip_special_tokens=True)
target = tokenizer.decode(input_ids[batch_idx, PROMPT_LEN:], skip_special_tokens=True)
sampled = tokenizer.decode(sampled_ids[sample_pos, PROMPT_LEN:], skip_special_tokens=True)
argmax = tokenizer.decode(pred_ids[sample_pos, PROMPT_LEN:], skip_special_tokens=True)
oracle = tokenizer.decode(oracle_ids[sample_pos, PROMPT_LEN:], skip_special_tokens=True)
print(f" prompt: {prompt}")
print(f" target: {target[:120]}")
print(f" oracle: {oracle[:120]}")
print(f" generated: {sampled[:120]}")
print(f" argmax: {argmax[:120]}")
print()
print(
" collapse argmax: "
f"entropy={gen_collapse['entropy']:.2f} "
f"uniq={gen_collapse['unique_ratio']:.3f} "
f"maxfrac={gen_collapse['max_frac']:.3f} "
f"top={', '.join(gen_collapse['top_tokens'])}"
)
print(
" collapse gen : "
f"entropy={sampled_collapse['entropy']:.2f} "
f"uniq={sampled_collapse['unique_ratio']:.3f} "
f"maxfrac={sampled_collapse['max_frac']:.3f} "
f"top={', '.join(sampled_collapse['top_tokens'])}"
)
print(
" collapse oracle: "
f"entropy={oracle_collapse['entropy']:.2f} "
f"uniq={oracle_collapse['unique_ratio']:.3f} "
f"maxfrac={oracle_collapse['max_frac']:.3f} "
f"top={', '.join(oracle_collapse['top_tokens'])}"
)
print(
" dist gen : "
f"ent={gen_dist['entropy']:.2f} "
f"top1={gen_dist['top1_prob']:.3f} "
f"top5={gen_dist['top5_mass']:.3f} "
f"top50={gen_dist['top50_mass']:.3f} "
f"batch_top8={gen_dist['batch_top8_mass']:.3f} "
f"special={gen_dist['special_mass']:.3f} "
f"oracle_to_gen_kl={gen_dist['kl_to_oracle']:.3f}"
)
print(
" target raw : "
f"top1_acc={raw_gen_dist['top1_acc']:.3f} "
f"target_prob={raw_gen_dist['target_prob']:.4f}"
)
print(
" target gen : "
f"top1_acc={gen_dist['top1_acc']:.3f} "
f"target_prob={gen_dist['target_prob']:.4f} "
f"oracle_top1_acc={gen_dist['oracle_top1_acc']:.3f} "
f"oracle_target_prob={gen_dist['oracle_target_prob']:.4f}"
)
print(
" dist oracle : "
f"ent={oracle_dist['entropy']:.2f} "
f"top1={oracle_dist['top1_prob']:.3f} "
f"top5={oracle_dist['top5_mass']:.3f} "
f"top50={oracle_dist['top50_mass']:.3f} "
f"batch_top8={oracle_dist['batch_top8_mass']:.3f} "
f"special={oracle_dist['special_mass']:.3f} "
f"target_prob={oracle_dist['target_prob']:.4f} "
f"top1_acc={oracle_dist['top1_acc']:.3f}"
)
print()
torch.random.set_rng_state(eval_rng_state)
if cuda_rng_state is not None:
torch.cuda.set_rng_state_all(cuda_rng_state)
latent_std_gap = abs(gen_std - real_std)
raw_norm_gap = abs(uncal_norm - real_norm)
collapse_uniq_penalty = max(0.0, COLLAPSE_UNIQ_TARGET - gen_collapse["unique_ratio"])
collapse_maxfrac_penalty = max(0.0, gen_collapse["max_frac"] - COLLAPSE_MAXFRAC_TARGET)
val_score = (
avg_val_loss
+ latent_std_gap
+ max(0.0, 0.8 - cosine_sim)
+ 0.05 * max(0.0, fused_decode_ce_gap if aux_token_head is not None else decode_ce_gap)
+ RAW_NORM_GAP_SCORE_WEIGHT * raw_norm_gap
+ COLLAPSE_UNIQ_SCORE_WEIGHT * collapse_uniq_penalty
+ COLLAPSE_MAXFRAC_SCORE_WEIGHT * collapse_maxfrac_penalty
)
print("-- val metrics ------------------------------------------------")
print(f" val loss : {avg_val_loss:.4f}")
print(f" real latents : mean={real_mean:.3f} std={real_std:.3f} norm={real_norm:.3f}")
print(f" gen latents : mean={gen_mean:.3f} std={gen_std:.3f}")
if start_mlp is not None:
print(f" coarse start : mean={coarse_mean:.3f} std={coarse_std:.3f} mse={coarse_mse:.4f} cos={coarse_cosine:.4f} ce={coarse_decode_ce:.4f} p={coarse_target_prob:.4f}")
if latent_projector is not None:
print(f" raw gen lat : mean={raw_gen_mean:.3f} std={raw_gen_std:.3f}")
print(f" projector : delta_norm={projector_delta_norm:.3f} proj_norm={projected_norm:.3f}")
print(f" init latents : mean={initial_mean:.3f} std={initial_std:.3f} norm={initial_norm:.3f}")
print(f" raw flow lat : mean={uncal_mean:.3f} std={uncal_std:.3f} norm={uncal_norm:.3f} norm_gap={raw_norm_gap:.3f}")
print(f" metric diag : mean={metric_mean:.3f} std={metric_std:.3f} min={metric_min:.3f} max={metric_max:.3f}")
print(f" cosine sim : {cosine_sim:.4f}")
print(f" decoder CE : real={real_decode_ce:.4f} init={initial_decode_ce:.4f} raw={uncal_decode_ce:.4f} gen={gen_decode_ce:.4f} gap={decode_ce_gap:.4f}")
if aux_token_head is not None:
print(
f" fused CE : beta={AUX_LOGIT_FUSION_BETA:.3f} gen={fused_decode_ce:.4f} "
f"gap={fused_decode_ce_gap:.4f} p={fused_decode_target_prob:.4f}"
)
if mix_decode_ce:
mix_text = " ".join(f"a={alpha:.2f}:{ce:.3f}" for alpha, ce in mix_decode_ce)
print(f" mix CE raw : {mix_text}")
print(f" collapse pen : uniq={collapse_uniq_penalty:.4f} maxfrac={collapse_maxfrac_penalty:.4f}")
print(f" ode steps : {ODE_STEPS}")
print(f" val score : {val_score:.4f}")
print()
return avg_val_loss, val_score