alphamike commited on
Commit
1508177
·
1 Parent(s): 6333fb2

Update training configuration and dependencies

Browse files

- Modified `requirements.txt` to use flexible versions of PyTorch and related libraries.
- Adjusted training parameters in `train.yaml`, reducing epochs from 20 to 8 and batch sizes from 32 and 64 to 8.
- Enhanced `train_gnn.py` with gradient accumulation and mixed precision training support.
- Fixed data type handling in `graph_models.py` for message passing layer.

configs/train.yaml CHANGED
@@ -12,7 +12,7 @@ run:
12
  training:
13
  stage1:
14
  enabled: true
15
- epochs: 20
16
  freeze_encoders: true
17
  lr_head: 0.001
18
  lr_encoder: 0.0
@@ -40,8 +40,8 @@ scheduler:
40
  min_lr: 0.0000001
41
 
42
  batching:
43
- batch_size: 32
44
- eval_batch_size: 64
45
 
46
  loss:
47
  bce:
 
12
  training:
13
  stage1:
14
  enabled: true
15
+ epochs: 8
16
  freeze_encoders: true
17
  lr_head: 0.001
18
  lr_encoder: 0.0
 
40
  min_lr: 0.0000001
41
 
42
  batching:
43
+ batch_size: 8
44
+ eval_batch_size: 8
45
 
46
  loss:
47
  bce:
requirements.txt CHANGED
@@ -3,9 +3,9 @@
3
  PyYAML
4
  pandas
5
  pyarrow
6
- torch==2.5.1+cu121
7
- torchvision==0.20.1+cu121
8
- torchaudio==2.5.1+cu121
9
  timm
10
  scikit-learn
11
  Pillow
 
3
  PyYAML
4
  pandas
5
  pyarrow
6
+ torch
7
+ torchvision
8
+ torchaudio
9
  timm
10
  scikit-learn
11
  Pillow
scripts/train_gnn.py CHANGED
@@ -53,7 +53,8 @@ def parse_args() -> argparse.Namespace:
53
  parser.add_argument("--run-name", type=str, required=True)
54
  parser.add_argument("--overrides-json", type=str, default="")
55
  parser.add_argument("--mode", type=str, default="full", choices=["smoke", "full"])
56
- parser.add_argument("--device", type=str, default="auto", choices=["auto", "cuda", "cpu"])
 
57
  return parser.parse_args()
58
 
59
 
@@ -272,6 +273,10 @@ def train() -> None:
272
  weight_decay=weight_decay,
273
  )
274
 
 
 
 
 
275
  output_root = REPO_ROOT / run_cfg.get("output_dir", "outputs")
276
  run_dir = output_root / args.run_name
277
  run_dir.mkdir(parents=True, exist_ok=True)
@@ -279,22 +284,47 @@ def train() -> None:
279
  history: List[Dict[str, Any]] = []
280
  best_map = -1.0
281
  best_path = run_dir / "best.pt"
282
- log(f"Training for epochs={train_epochs}, batch_size={batch_size}, eval_batch_size={eval_batch_size}")
 
 
 
283
  for epoch in range(1, train_epochs + 1):
284
  backbone.eval()
285
  gnn_model.train()
286
  train_losses: List[float] = []
287
- for batch in tqdm(train_loader, desc=f"{args.run_name} epoch {epoch}/{train_epochs}"):
 
 
 
 
 
288
  targets = batch["targets"].to(device)
289
  images = batch["images"]
290
  feats = backbone.encode(images=images, device=device).unsqueeze(1)
291
  graph = build_bipartite_batch(feats=feats, targets=targets)
292
- logits = gnn_model(graph)
293
- loss = bce_logits_loss(logits, targets, pos_weight=pos_weight)
294
- optimizer.zero_grad(set_to_none=True)
295
- loss.backward()
296
- optimizer.step()
297
- train_losses.append(float(loss.item()))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
299
  val_metrics = run_eval(
300
  backbone=backbone,
 
53
  parser.add_argument("--run-name", type=str, required=True)
54
  parser.add_argument("--overrides-json", type=str, default="")
55
  parser.add_argument("--mode", type=str, default="full", choices=["smoke", "full"])
56
+ parser.add_argument("--device", type=str, default="auto",
57
+ help="Device: auto, cuda, cpu, or cuda:N (e.g. cuda:1)")
58
  return parser.parse_args()
59
 
60
 
 
273
  weight_decay=weight_decay,
274
  )
275
 
276
+ grad_accum_steps = int(cfg["optimization"].get("gradient_accumulation_steps", 1))
277
+ use_amp = bool(cfg["optimization"].get("mixed_precision", False)) and device.type == "cuda"
278
+ scaler = torch.cuda.amp.GradScaler(enabled=use_amp)
279
+
280
  output_root = REPO_ROOT / run_cfg.get("output_dir", "outputs")
281
  run_dir = output_root / args.run_name
282
  run_dir.mkdir(parents=True, exist_ok=True)
 
284
  history: List[Dict[str, Any]] = []
285
  best_map = -1.0
286
  best_path = run_dir / "best.pt"
287
+ log(
288
+ f"Training for epochs={train_epochs}, batch_size={batch_size}, "
289
+ f"eval_batch_size={eval_batch_size}, grad_accum_steps={grad_accum_steps}, amp={use_amp}"
290
+ )
291
  for epoch in range(1, train_epochs + 1):
292
  backbone.eval()
293
  gnn_model.train()
294
  train_losses: List[float] = []
295
+ step_times: List[float] = []
296
+ start_epoch = time.time()
297
+ for step_idx, batch in enumerate(
298
+ tqdm(train_loader, desc=f"{args.run_name} epoch {epoch}/{train_epochs}")
299
+ ):
300
+ batch_start = time.time()
301
  targets = batch["targets"].to(device)
302
  images = batch["images"]
303
  feats = backbone.encode(images=images, device=device).unsqueeze(1)
304
  graph = build_bipartite_batch(feats=feats, targets=targets)
305
+
306
+ with torch.cuda.amp.autocast(enabled=use_amp):
307
+ logits = gnn_model(graph)
308
+ loss = bce_logits_loss(logits, targets, pos_weight=pos_weight)
309
+ loss = loss / grad_accum_steps
310
+
311
+ scaler.scale(loss).backward()
312
+ if (step_idx + 1) % grad_accum_steps == 0 or (step_idx + 1) == len(train_loader):
313
+ scaler.unscale_(optimizer)
314
+ torch.nn.utils.clip_grad_norm_(gnn_model.parameters(), cfg["optimization"].get("grad_clip_norm", 1.0))
315
+ scaler.step(optimizer)
316
+ scaler.update()
317
+ optimizer.zero_grad(set_to_none=True)
318
+
319
+ train_losses.append(float(loss.item()) * grad_accum_steps)
320
+ step_times.append(time.time() - batch_start)
321
+
322
+ epoch_time = time.time() - start_epoch
323
+ avg_step = float(np.mean(step_times)) if step_times else 0.0
324
+ log(
325
+ f"Epoch {epoch} finished in {epoch_time:.1f}s, "
326
+ f"avg_step_time={avg_step:.3f}s, steps={len(step_times)}"
327
+ )
328
 
329
  val_metrics = run_eval(
330
  backbone=backbone,
src/train/graph_models.py CHANGED
@@ -68,7 +68,8 @@ class BipartiteMessagePassingLayer(nn.Module):
68
  # Messages from attributes to objects.
69
  attr_msgs = flat_attrs.index_select(0, src_attr) # [E, Din_attr]
70
  attr_msgs = self.attr_to_obj(attr_msgs) # [E, Din]
71
- w = edge_weight.view(-1, 1)
 
72
  weighted_msgs = attr_msgs * w
73
 
74
  # Aggregate messages per object index.
 
68
  # Messages from attributes to objects.
69
  attr_msgs = flat_attrs.index_select(0, src_attr) # [E, Din_attr]
70
  attr_msgs = self.attr_to_obj(attr_msgs) # [E, Din]
71
+ attr_msgs = attr_msgs.to(flat_objects.dtype)
72
+ w = edge_weight.view(-1, 1).to(flat_objects.dtype)
73
  weighted_msgs = attr_msgs * w
74
 
75
  # Aggregate messages per object index.