Download evaluate.py from xcx0902/QOJDoudizhuModel: direct link, hf CLI and curl.
- Browser
- Download file 4.39 kB
-
https://huggingface.co/xcx0902/QOJDoudizhuModel/resolve/main/evaluate.py
- Command line
-
hf download hf://xcx0902/QOJDoudizhuModel/evaluate.py
-
curl -L -o evaluate.py https://huggingface.co/xcx0902/QOJDoudizhuModel/resolve/main/evaluate.py
4.39 kB
| """Paired, role-balanced tests; bootstrap units are complete seeded deals.""" | |
| import argparse | |
| import json | |
| import statistics | |
| import sys | |
| import time | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| if __package__ in (None, ''): | |
| sys.path.insert(0, str(ROOT)) | |
| from qojbot.history import write_json | |
| from qojbot.model_benchmark import run, _bootstrap | |
| from QOJDoudizhuModel.policy import QOJPolicy | |
| from QOJDoudizhuModel.storage import digest, source_hashes, teacher_hashes | |
| def evaluate(policy, deals, seed, modes=('fixed', 'bidding'), opponent=None): | |
| opponent = opponent or policy.teacher | |
| result = run({'lstm': opponent, 'resnet': policy}, deals=deals, seed=seed, modes=modes) | |
| # Reuse the tested paired evaluator without presenting the new network as ResNet. | |
| result['labels'] = {'lstm': type(opponent).__name__, 'resnet': 'QOJNet'} | |
| result['selection_score'] = statistics.mean( | |
| metrics['resnet']['mean_score'] for metrics in result['summary'].values()) | |
| clusters = {} | |
| for record in result['records']: | |
| clusters.setdefault(record['seed'], []).extend( | |
| record['deltas'][seat] for seat, name in enumerate(record['lineup']) if name == 'resnet') | |
| result['selection_score_95pct_cluster_bootstrap'] = _bootstrap( | |
| [statistics.mean(values) for values in clusters.values()]) | |
| result['positive_score_supported'] = ( | |
| deals >= 100 and result['selection_score_95pct_cluster_bootstrap'][0] > 0 and | |
| all(metrics['resnet']['mean_score'] > 0 for metrics in result['summary'].values())) | |
| result['teacher_sha256'] = teacher_hashes(policy.teacher) | |
| if hasattr(opponent, 'paths'): | |
| result['opponent'] = {'model_type': opponent.model_type, | |
| 'paths': {key: str(path) for key, path in opponent.paths.items()}, | |
| 'sha256': teacher_hashes(opponent)} | |
| result['source_sha256'] = source_hashes() | |
| result['protocol'] = {'lineups_per_deal_per_mode': 6, | |
| 'selection': 'validation only; test seed reserved', | |
| 'score': 'QOJ bid * (1+bombs+spring), landlord x2', | |
| 'confidence': 'bootstrap by original seed; few deals yield unreliable intervals', | |
| 'information': 'own hand and public information only', | |
| 'limitation': 'not online rating or six-game match placement'} | |
| return result | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument('--checkpoint', type=Path, required=True) | |
| parser.add_argument('--device', choices=('cpu', 'auto', 'mps', 'cuda'), default='mps') | |
| parser.add_argument('--deals', type=int, default=100) | |
| parser.add_argument('--seed', type=int, default=40261002) | |
| parser.add_argument('--modes', nargs='+', choices=('fixed', 'bidding'), default=['fixed', 'bidding']) | |
| parser.add_argument('--opponent', choices=('douzero', 'search'), default='douzero') | |
| parser.add_argument('--opponent-dir', type=Path, | |
| help='explicit DouZero benchmark weights, independent of the frozen prior') | |
| parser.add_argument('--teacher-dir', type=Path, | |
| help='frozen prior used by the checkpoint') | |
| parser.add_argument('--output', type=Path, default=Path('QOJDoudizhuModel/results/test.json')) | |
| args = parser.parse_args() | |
| if args.opponent == 'search' and args.opponent_dir: | |
| parser.error('--opponent-dir requires --opponent douzero') | |
| policy = QOJPolicy(args.checkpoint, device=args.device, teacher_dir=args.teacher_dir) | |
| opponent = None | |
| if args.opponent == 'search': | |
| from QOJDoudizhuModel.learning import SearchOpponent | |
| opponent = SearchOpponent(.1) | |
| elif args.opponent_dir: | |
| from qojbot.douzero import DouZeroPolicy | |
| opponent = DouZeroPolicy(args.opponent_dir, device=str(policy.device), batch_size=256) | |
| report = evaluate(policy, args.deals, args.seed, tuple(args.modes), opponent) | |
| path = args.checkpoint / 'best.pt' if args.checkpoint.is_dir() else args.checkpoint | |
| report['checkpoint_sha256'] = digest(path) | |
| args.output.parent.mkdir(parents=True, exist_ok=True) | |
| write_json(args.output, report) | |
| print(json.dumps({key: report[key] for key in ('games', 'selection_score', 'summary')}, indent=2)) | |
| if __name__ == '__main__': | |
| main() | |