Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>Microzero Play</title> | |
| <style> | |
| :root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui; } | |
| * { box-sizing: border-box; } | |
| body { margin: 0; min-height: 100vh; background: #060817; color: #edf4ff; } | |
| canvas { position: fixed; inset: 0; width: 100%; height: 100%; opacity: .55; } | |
| main { position: relative; z-index: 1; width: min(1080px, 92vw); margin: auto; | |
| padding: 72px 0 96px; } | |
| .eyebrow { color: #73e6ff; letter-spacing: .18em; text-transform: uppercase; | |
| font-size: .75rem; font-weight: 800; } | |
| h1 { font-size: clamp(3rem, 8vw, 7rem); line-height: .9; margin: 14px 0 24px; | |
| background: linear-gradient(120deg,#fff,#74e7ff 55%,#b48cff); | |
| -webkit-background-clip: text; color: transparent; } | |
| .lead { max-width: 760px; color: #b8c7e6; font-size: 1.2rem; line-height: 1.65; } | |
| .actions { display: flex; flex-wrap: wrap; gap: 12px; margin: 30px 0 48px; } | |
| a { color: inherit; } | |
| .button { padding: 12px 18px; border-radius: 999px; text-decoration: none; | |
| background: #eaf8ff; color: #07101c; font-weight: 800; } | |
| .button.alt { background: #171d38cc; color: #dce8ff; border: 1px solid #415078; } | |
| .grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 20px; } | |
| .card { border: 1px solid #344269; background: #0c1128dd; border-radius: 24px; | |
| padding: 24px; backdrop-filter: blur(18px); box-shadow: 0 24px 80px #0008; } | |
| h2 { margin-top: 0; } | |
| pre { white-space: pre-wrap; word-break: break-word; color: #a9bddf; | |
| max-height: 520px; overflow: auto; } | |
| ul { max-height: 520px; overflow: auto; padding-left: 1.2rem; color: #a9bddf; } | |
| li { margin: 8px 0; } | |
| input { width: 100%; padding: 12px; border-radius: 12px; border: 1px solid #344269; | |
| background: #070b1a; color: white; margin-bottom: 12px; } | |
| @media (max-width: 780px) { .grid { grid-template-columns: 1fr; } } | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="field"></canvas> | |
| <main> | |
| <div class="eyebrow">Jacob Garcia · Hugging Face Model Foundry</div> | |
| <h1>Microzero Play</h1> | |
| <p class="lead">Playable neural MCTS Tic-Tac-Toe agent. This showcase backs up the | |
| trained artifacts, measured evaluation, and complete runnable source.</p> | |
| <div class="actions"> | |
| <a class="button" href="https://huggingface.co/spaces/ARotting/microzero-play/tree/main">Explore every file</a> | |
| <a class="button alt" href="https://huggingface.co/ARotting">View the full foundry</a> | |
| </div> | |
| <div class="grid"> | |
| <section class="card"> | |
| <h2>Verified project card</h2> | |
| <pre># MicroZero | |
| MicroZero is a tiny AlphaZero-style Tic-Tac-Toe agent. A shared neural trunk predicts | |
| both move priors and position value. Monte Carlo Tree Search converts those estimates | |
| into stronger self-play targets, while terminal outcomes supervise value learning. | |
| The training loop uses: | |
| - neural-guided PUCT search; | |
| - root Dirichlet exploration; | |
| - policy targets from MCTS visit counts; | |
| - terminal win/draw/loss value targets; | |
| - all eight square-board symmetries; | |
| - a bounded replay buffer. | |
| Evaluation alternates playing first and second against random and exact minimax | |
| opponents. | |
| ## Verified results | |
| - 7,626 trainable parameters; | |
| - 980 neural-MCTS self-play games; | |
| - 24,000-example bounded replay buffer after symmetry augmentation; | |
| - 384 wins, 16 draws, and zero losses over 400 games against random play; | |
| - 200 draws and zero losses over 200 games against exact minimax. | |
| The exact opponent is used only for final evaluation, not as a source of training | |
| targets. Full metrics and the per-iteration learning history are stored in | |
| `artifacts/microzero/evaluation.json`. | |
| ## Reproduce | |
| ```powershell | |
| uv run python projects/microzero/train.py | |
| ``` | |
| </pre> | |
| <h2>Evaluation snapshot</h2> | |
| <pre>{ | |
| "model": "MicroZero", | |
| "parameters": 7626, | |
| "self_play_iterations": 14, | |
| "self_play_games": 980, | |
| "final_replay_examples": 24000, | |
| "training_history": [ | |
| { | |
| "iteration": 1, | |
| "replay_examples": 4128, | |
| "x_win_rate": 0.5428571428571428, | |
| "o_win_rate": 0.14285714285714285, | |
| "draw_rate": 0.3142857142857143, | |
| "average_game_moves": 7.371428571428571, | |
| "policy_loss": 2.1499555636854732, | |
| "value_loss": 0.5162482239744243 | |
| }, | |
| { | |
| "iteration": 2, | |
| "replay_examples": 8128, | |
| "x_win_rate": 0.5142857142857142, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.4857142857142857, | |
| "average_game_moves": 7.142857142857143, | |
| "policy_loss": 1.9038925133645535, | |
| "value_loss": 0.3203776921145618 | |
| }, | |
| { | |
| "iteration": 3, | |
| "replay_examples": 12328, | |
| "x_win_rate": 0.42857142857142855, | |
| "o_win_rate": 0.014285714285714285, | |
| "draw_rate": 0.5571428571428572, | |
| "average_game_moves": 7.5, | |
| "policy_loss": 1.4543613067695074, | |
| "value_loss": 0.26955098012576295 | |
| }, | |
| { | |
| "iteration": 4, | |
| "replay_examples": 16456, | |
| "x_win_rate": 0.5142857142857142, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.4857142857142857, | |
| "average_game_moves": 7.371428571428571, | |
| "policy_loss": 1.229265012878638, | |
| "value_loss": 0.22285609325537314 | |
| }, | |
| { | |
| "iteration": 5, | |
| "replay_examples": 20952, | |
| "x_win_rate": 0.2857142857142857, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.7142857142857143, | |
| "average_game_moves": 8.028571428571428, | |
| "policy_loss": 1.1138035529633847, | |
| "value_loss": 0.1854344406960214 | |
| }, | |
| { | |
| "iteration": 6, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.3142857142857143, | |
| "o_win_rate": 0.014285714285714285, | |
| "draw_rate": 0.6714285714285714, | |
| "average_game_moves": 7.957142857142857, | |
| "policy_loss": 1.0146886479664357, | |
| "value_loss": 0.15539901554980812 | |
| }, | |
| { | |
| "iteration": 7, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.2571428571428571, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.7428571428571429, | |
| "average_game_moves": 8.085714285714285, | |
| "policy_loss": 0.8795330280319174, | |
| "value_loss": 0.11288299490796759 | |
| }, | |
| { | |
| "iteration": 8, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.24285714285714285, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.7571428571428571, | |
| "average_game_moves": 8.314285714285715, | |
| "policy_loss": 0.7982094690520712, | |
| "value_loss": 0.09204166978993948 | |
| }, | |
| { | |
| "iteration": 9, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.3, | |
| "o_win_rate": 0.014285714285714285, | |
| "draw_rate": 0.6857142857142857, | |
| "average_game_moves": 7.985714285714286, | |
| "policy_loss": 0.7609958442601752, | |
| "value_loss": 0.09048273768077822 | |
| }, | |
| { | |
| "iteration": 10, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.2857142857142857, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.7142857142857143, | |
| "average_game_moves": 8.17142857142857, | |
| "policy_loss": 0.7380844823857571, | |
| "value_loss": 0.08676699136799955 | |
| }, | |
| { | |
| "iteration": 11, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.18571428571428572, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.8142857142857143, | |
| "average_game_moves": 8.371428571428572, | |
| "policy_loss": 0.7269294456915653, | |
| "value_loss": 0.074583658938633 | |
| }, | |
| { | |
| "iteration": 12, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.3142857142857143, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.6857142857142857, | |
| "average_game_moves": 8.142857142857142, | |
| "policy_loss": 0.7146875767948779, | |
| "value_loss": 0.07327091548235175 | |
| }, | |
| { | |
| "iteration": 13, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.22857142857142856, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.7714285714285715, | |
| "average_game_moves": 8.17142857142857, | |
| "policy_loss": 0.7104355310823055, | |
| "value_loss": 0.07133727120433717 | |
| }, | |
| { | |
| "iteration": 14, | |
| "replay_examples": 24000, | |
| "x_win_rate": 0.2, | |
| "o_win_rate": 0.0, | |
| "draw_rate": 0.8, | |
| "average_game_moves": 8.371428571428572, | |
| "policy_loss": 0.7074488862714869, | |
| "value_loss": 0.06895742299867437 | |
| } | |
| ], | |
| "versus_random": { | |
| "games": 400, | |
| "wins": 384, | |
| "draws": 16, | |
| "losses": 0, | |
| "win_rate": 0.96, | |
| "non_loss_rate": 1.0, | |
| "average_moves": 6.065 | |
| }, | |
| "versus_exact_minimax": { | |
| "games": 200, | |
| "wins": 0, | |
| "draws": 200, | |
| "losses": 0, | |
| "win_rate": 0.0, | |
| "non_loss_rate": 1.0, | |
| "average_moves": 9.0 | |
| } | |
| }</pre> | |
| </section> | |
| <section class="card"> | |
| <h2>Backed-up artifact tree</h2> | |
| <input id="filter" placeholder="Filter files…" autocomplete="off"> | |
| <ul id="files"><li><code>README.md</code></li> | |
| <li><code>__pycache__/app.cpython-311.pyc</code></li> | |
| <li><code>__pycache__/game.cpython-311.pyc</code></li> | |
| <li><code>__pycache__/mcts.cpython-311.pyc</code></li> | |
| <li><code>__pycache__/model.cpython-311.pyc</code></li> | |
| <li><code>__pycache__/train.cpython-311.pyc</code></li> | |
| <li><code>app.py</code></li> | |
| <li><code>artifacts/microzero/evaluation.json</code></li> | |
| <li><code>artifacts/microzero/model.safetensors</code></li> | |
| <li><code>game.py</code></li> | |
| <li><code>mcts.py</code></li> | |
| <li><code>model.py</code></li> | |
| <li><code>requirements.txt</code></li> | |
| <li><code>train.py</code></li></ul> | |
| </section> | |
| </div> | |
| </main> | |
| <script> | |
| const canvas=document.querySelector('#field'),ctx=canvas.getContext('2d'); | |
| let dots=[]; | |
| function resize(){canvas.width=innerWidth;canvas.height=innerHeight; | |
| dots=Array.from({length:90},()=>({x:Math.random()*innerWidth, | |
| y:Math.random()*innerHeight,vx:(Math.random()-.5)*.35,vy:(Math.random()-.5)*.35}));} | |
| function draw(){ctx.clearRect(0,0,canvas.width,canvas.height); | |
| for(const d of dots){d.x=(d.x+d.vx+innerWidth)%innerWidth; | |
| d.y=(d.y+d.vy+innerHeight)%innerHeight;ctx.fillStyle='#65dcff99'; | |
| ctx.beginPath();ctx.arc(d.x,d.y,1.4,0,7);ctx.fill();}requestAnimationFrame(draw);} | |
| addEventListener('resize',resize);resize();draw(); | |
| document.querySelector('#filter').addEventListener('input',e=>{ | |
| const q=e.target.value.toLowerCase();for(const li of document.querySelectorAll('li')) | |
| li.hidden=!li.textContent.toLowerCase().includes(q);}); | |
| </script> | |
| </body> | |
| </html> |