9OCR / predict.py
ansarzeinulla's picture
Initial commit
20d7fde
Raw
History Blame Contribute Delete
2.44 kB
"""Classify cropped cell images.
python predict.py data/real_crops/96_a.jpg
python predict.py "data/real_crops/*.jpg" --topk 3
python predict.py cell.jpg --allowed "12,34x,56" # restrict to legal moves
--allowed renormalizes probabilities over the given moves - at any game state
at most 9 moves are legal, so an upstream game tracker can pass them here.
"""
import argparse
import glob
import numpy as np
import torch
from togyz.classes import CLASS_TO_IDX
from togyz.model import auto_device, load_checkpoint
from togyz.preprocess import preprocess_file
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("images", nargs="+", help="image paths or globs")
parser.add_argument("--ckpt", default="checkpoints/best.pt")
parser.add_argument("--topk", type=int, default=3)
parser.add_argument("--allowed", default=None,
help="comma-separated legal moves, e.g. '12,34x,56'")
parser.add_argument("--device", default=None)
args = parser.parse_args()
paths = []
for pattern in args.images:
matched = sorted(glob.glob(pattern))
paths.extend(matched if matched else [pattern])
device = torch.device(args.device) if args.device else auto_device()
model, ckpt = load_checkpoint(args.ckpt, device)
classes = ckpt["classes"]
allowed_idx = None
if args.allowed:
moves = [m.strip() for m in args.allowed.split(",") if m.strip()]
unknown = [m for m in moves if m not in CLASS_TO_IDX]
if unknown:
parser.error(f"unknown moves in --allowed: {unknown}")
allowed_idx = torch.tensor([CLASS_TO_IDX[m] for m in moves])
batch = torch.from_numpy(np.stack([preprocess_file(p) for p in paths]))
with torch.no_grad():
probs = torch.softmax(model(batch.to(device)).cpu(), dim=1)
for path, p in zip(paths, probs):
topk = p.topk(min(args.topk, len(classes)))
guesses = ", ".join(
f"{classes[i]} {v:.1%}" for i, v in zip(topk.indices.tolist(), topk.values.tolist())
)
line = f"{path}: {guesses}"
if allowed_idx is not None:
legal = p[allowed_idx]
legal = legal / legal.sum()
best = int(legal.argmax())
line += f" | legal pick: {classes[int(allowed_idx[best])]} {legal[best]:.1%}"
print(line)
if __name__ == "__main__":
main()