tchbcb commited on
Commit
7136107
·
verified ·
1 Parent(s): ff3d70b

QwenJev v0.2.0: vision tower on the System-1 inference path (tiny/hf backends, mock env, e2e local run)

Browse files
qwenjev/hf_compat.py CHANGED
@@ -64,7 +64,17 @@ def pooled_last_position(model, batch, device, layer_idx=(-2, -1)):
64
  for k, li in enumerate(layer_idx):
65
  hooks.append(layers[li].register_forward_hook(make_hook(k)))
66
  try:
67
- out = model(**batch)
 
 
 
 
 
 
 
 
 
 
68
  finally:
69
  for h in hooks:
70
  h.remove()
 
64
  for k, li in enumerate(layer_idx):
65
  hooks.append(layers[li].register_forward_hook(make_hook(k)))
66
  try:
67
+ # logits_to_keep=1: we only need decoder-layer hidden states, but the
68
+ # default forward computes the FULL [B, T, vocab=151k] logits tensor
69
+ # (~0.5-1 GB per forward on a 9B) - pure waste, and on a 16 GB T4
70
+ # next to a 4-bit teacher it IS the OOM.
71
+ try:
72
+ out = model(**batch, logits_to_keep=1)
73
+ except TypeError:
74
+ try:
75
+ out = model(**batch, num_logits_to_keep=1)
76
+ except TypeError:
77
+ out = model(**batch)
78
  finally:
79
  for h in hooks:
80
  h.remove()
train/calibrate_rlcd.py CHANGED
@@ -122,7 +122,8 @@ def main() -> None:
122
  + list(model._score_head.parameters())
123
  )
124
  groups = [{"params": head_params, "lr": float(c.get("lr_head", 1.0e-4))}]
125
- if not c.get("freeze_backbone", False):
 
126
  groups.insert(0, {"params": list(backbone.parameters()),
127
  "lr": float(c.get("lr_backbone", 2.5e-5))})
128
  else:
@@ -143,6 +144,10 @@ def main() -> None:
143
  leaves = model.encode_question(row["state"], cands, row["instruction"],
144
  row.get("grid"))
145
  pooled = model._choice_pooled(leaves)
 
 
 
 
146
  logits = model._choice_logits(pooled)
147
  return logits, pooled
148
 
 
122
  + list(model._score_head.parameters())
123
  )
124
  groups = [{"params": head_params, "lr": float(c.get("lr_head", 1.0e-4))}]
125
+ FROZEN = bool(c.get("freeze_backbone", False))
126
+ if not FROZEN:
127
  groups.insert(0, {"params": list(backbone.parameters()),
128
  "lr": float(c.get("lr_backbone", 2.5e-5))})
129
  else:
 
144
  leaves = model.encode_question(row["state"], cands, row["instruction"],
145
  row.get("grid"))
146
  pooled = model._choice_pooled(leaves)
147
+ if FROZEN:
148
+ # frozen backbone: cut the activation graph at the pooled output
149
+ # so the (large) VLM forward is not kept alive until backward
150
+ pooled = pooled.detach()
151
  logits = model._choice_logits(pooled)
152
  return logits, pooled
153
 
train/train_system1.py CHANGED
@@ -113,10 +113,15 @@ def main() -> None:
113
 
114
  steps = 0
115
  epochs = int(b["epochs"])
 
116
  rng = random.Random(int(cfg.get("data", {}).get("seed", 13)))
117
  for epoch in range(epochs):
118
  for batch in iter_batches(data, int(b["batch_questions"])):
119
  losses = []
 
 
 
 
120
  # ---- Choice: complete-question cross entropy ----------------
121
  for row in batch["choice"]:
122
  from qwenjev.candidates import CandidateAction
@@ -140,33 +145,38 @@ def main() -> None:
140
  proj = model._choice_proj(pooled)
141
  attn_out = model._set_attn(proj.unsqueeze(0)).squeeze(0)
142
  logits = attn_out.sum(-1)
143
- losses.append(torch.nn.functional.cross_entropy(
144
  logits.unsqueeze(0),
145
  torch.tensor([label], device=model.device),
146
- ))
 
 
147
  # ---- Boolean / Score: trainable-head calibration -------------
148
  for row in batch["boolean"][:8]:
149
  logits = model.forward_boolean_logits(
150
  row["state"], row["instruction"], row["proposition"],
151
  row.get("grid"))
152
- losses.append(F.cross_entropy(
153
- logits, torch.tensor([row["label"]], device=model.device)))
 
 
154
  for row in batch["score"][:8]:
155
  logits = model.forward_score_logits(
156
  row["state"], row["instruction"], row["description"],
157
  row.get("grid"))
158
- losses.append(F.cross_entropy(
159
- logits, torch.tensor([row["label"]], device=model.device)))
 
 
160
 
161
  if not losses: # batch without choice rows
162
  continue
163
- loss = sum(losses) / max(1, int(b.get("grad_accum", 4)))
164
- optim.zero_grad()
165
- loss.backward()
166
  optim.step()
 
167
  steps += 1
168
  if steps % int(cfg.get("log_every", 10)) == 0:
169
- print(f"epoch={epoch} step={steps} loss={float(loss):.4f}")
 
170
 
171
  model.save(cfg["out_dir"])
172
  # hf backend: persist LoRA adapters so the SFT result is reproducible
 
113
 
114
  steps = 0
115
  epochs = int(b["epochs"])
116
+ grad_acc = max(1, int(b.get("grad_accum", 4)))
117
  rng = random.Random(int(cfg.get("data", {}).get("seed", 13)))
118
  for epoch in range(epochs):
119
  for batch in iter_batches(data, int(b["batch_questions"])):
120
  losses = []
121
+ # NOTE: every row's loss is backwarded IMMEDIATELY. The hf
122
+ # fp16/QLoRA forward keeps each row's activation graph alive;
123
+ # accumulating whole-batch graphs OOMs even a chunked T4 run.
124
+ # Gradients accumulate across rows/chunks; step once per batch.
125
  # ---- Choice: complete-question cross entropy ----------------
126
  for row in batch["choice"]:
127
  from qwenjev.candidates import CandidateAction
 
145
  proj = model._choice_proj(pooled)
146
  attn_out = model._set_attn(proj.unsqueeze(0)).squeeze(0)
147
  logits = attn_out.sum(-1)
148
+ ce = torch.nn.functional.cross_entropy(
149
  logits.unsqueeze(0),
150
  torch.tensor([label], device=model.device),
151
+ )
152
+ losses.append(float(ce.detach()))
153
+ (ce / grad_acc).backward()
154
  # ---- Boolean / Score: trainable-head calibration -------------
155
  for row in batch["boolean"][:8]:
156
  logits = model.forward_boolean_logits(
157
  row["state"], row["instruction"], row["proposition"],
158
  row.get("grid"))
159
+ ce = F.cross_entropy(
160
+ logits, torch.tensor([row["label"]], device=model.device))
161
+ losses.append(float(ce.detach()))
162
+ (ce / grad_acc).backward()
163
  for row in batch["score"][:8]:
164
  logits = model.forward_score_logits(
165
  row["state"], row["instruction"], row["description"],
166
  row.get("grid"))
167
+ ce = F.cross_entropy(
168
+ logits, torch.tensor([row["label"]], device=model.device))
169
+ losses.append(float(ce.detach()))
170
+ (ce / grad_acc).backward()
171
 
172
  if not losses: # batch without choice rows
173
  continue
 
 
 
174
  optim.step()
175
+ optim.zero_grad()
176
  steps += 1
177
  if steps % int(cfg.get("log_every", 10)) == 0:
178
+ print(f"epoch={epoch} step={steps} "
179
+ f"loss={sum(losses)/len(losses):.4f}")
180
 
181
  model.save(cfg["out_dir"])
182
  # hf backend: persist LoRA adapters so the SFT result is reproducible