hitit-cuneiform-ocr / code /src /swa_average.py
savastakan's picture
Initial upload: code + 5 record checkpoints + fuse
f211247 verified
Raw
History Blame Contribute Delete
1.73 kB
#!/usr/bin/env python3
"""SWA: son N intermediate ckpt'in ağırlık ortalaması.
Usage: python swa_average.py runs/detect/.../yolo_fold0/weights/ [N=5]
"""
import sys, glob, copy
from pathlib import Path
import torch
def main():
if len(sys.argv) < 2:
print("usage: swa_average.py <weights_dir> [N=5]"); sys.exit(1)
wdir = Path(sys.argv[1])
n = int(sys.argv[2]) if len(sys.argv) > 2 else 5
# Collect epoch ckpts (epoch{N}.pt or last.pt)
ckpts = sorted(wdir.glob('epoch*.pt'))
if len(ckpts) < n:
print(f"only {len(ckpts)} epoch ckpts; using all + last.pt");
last = wdir / 'last.pt'
if last.exists() and last not in ckpts:
ckpts.append(last)
ckpts = ckpts[-n:]
print(f"Averaging {len(ckpts)}: {[c.name for c in ckpts]}")
avg_state = None; avg_meta = None
for i, c in enumerate(ckpts):
d = torch.load(c, map_location='cpu')
sd = d['model'].state_dict() if hasattr(d['model'], 'state_dict') else d['model']
if i == 0:
avg_state = {k: v.float().clone() for k, v in sd.items()}
avg_meta = d
else:
for k in avg_state:
if k in sd and avg_state[k].shape == sd[k].shape:
avg_state[k] += sd[k].float()
for k in avg_state:
avg_state[k] /= len(ckpts)
# Replace model state, save
if hasattr(avg_meta['model'], 'load_state_dict'):
avg_meta['model'].load_state_dict({k: v.to(next(avg_meta['model'].parameters()).dtype) for k,v in avg_state.items()})
else:
avg_meta['model'] = avg_state
out = wdir / 'swa.pt'
torch.save(avg_meta, out)
print(f"SWA -> {out}")
if __name__ == '__main__':
main()