diff --git a/src/projected_grpo/train.py b/src/projected_grpo/train.py index fe39c47..3957992 100644 --- a/src/projected_grpo/train.py +++ b/src/projected_grpo/train.py @@ -559,11 +559,25 @@ def main(cfg: Config) -> int: # lp_s, lp_t are mean per-token gen_logp by source. Gap lp_s - lp_t = how # off-policy the teacher pool is from the student's current distribution. # No IS correction is applied to the loss; this is diagnostic only. + # Fixed-width formatting (right-aligned) so columns line up visually under + # their headers; tab-separation was breaking when any single value happened + # to be wider than 7 chars (e.g. a 4-digit "sec" or 5-char "ref_eq"). + _col_w = { + "step": 4, "ref_eq": 6, "rew": 6, "rew_s": 6, "std": 5, "sprd": 4, "N": 3, + "gt": 6, "gt_s": 6, "gt_t": 6, "hack": 6, "hack_s": 6, "hack_t": 6, + "lp_s": 6, "lp_t": 6, + "loss": 8, "cin": 6, "cin_s": 6, "cin_t": 6, "cout": 6, "fired": 5, + "gen": 5, "fb": 4, "t_rew": 5, "sec": 4, + } _row_cols = ["step", "ref_eq", "rew", "rew_s", "std", "sprd", "N", "gt", "gt_s", "gt_t", "hack", "hack_s", "hack_t", "lp_s", "lp_t", "loss", "cin", "cin_s", "cin_t", "cout", "fired", "gen", "fb", "t_rew", "sec"] + def _fmt_row(cells: dict) -> str: + return " ".join(f"{str(cells[c]):>{_col_w[c]}}" for c in _row_cols) + def _fmt_header() -> str: + return " ".join(f"{c:>{_col_w[c]}}" for c in _row_cols) REF_GENS_PER_STEP = 16 * 16 # ariahw/rl-rewardhacking config.py:num_prompts * num_generations est_gens_per_step = cfg.prompts_per_step * cfg.group # before mixed-pool split logger.info( @@ -572,7 +586,7 @@ def main(cfg: Config) -> int: f"this run's {steps} steps ~= {steps * est_gens_per_step / REF_GENS_PER_STEP:.1f} reference steps." ) logger.info("") - logger.info("row\t" + "\t".join(_row_cols)) + logger.info("row " + _fmt_header()) logger.info("") OUT_DIR.mkdir(exist_ok=True) @@ -986,7 +1000,7 @@ def main(cfg: Config) -> int: } rows.append(row) # Stream this step as TSV row (header was printed before the loop). - logger.info("row\t" + "\t".join(str(row[c]) for c in _row_cols)) + logger.info("row " + _fmt_row(row)) if (step + 1) % 25 == 0: save_ckpt(rows) # survive early kills; ~12 days for the full sweep if not first_hack_saved and hack_s_n > 0: