Text Generation
Transformers
Safetensors
PyTorch
qwen3
chess
reinforcement-learning
self-play
causal-lm
text-generation-inference
Instructions to use aLocks/Plynder-1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use aLocks/Plynder-1 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="aLocks/Plynder-1")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("aLocks/Plynder-1") model = AutoModelForCausalLM.from_pretrained("aLocks/Plynder-1", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use aLocks/Plynder-1 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "aLocks/Plynder-1" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "aLocks/Plynder-1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/aLocks/Plynder-1
- SGLang
How to use aLocks/Plynder-1 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "aLocks/Plynder-1" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "aLocks/Plynder-1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "aLocks/Plynder-1" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "aLocks/Plynder-1", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use aLocks/Plynder-1 with Docker Model Runner:
docker model run hf.co/aLocks/Plynder-1
|
Download README.md from aLocks/Plynder-1: direct link, hf CLI and curl.
- Browser
- Download file 6.27 kB
-
https://huggingface.co/aLocks/Plynder-1/resolve/main/README.md
- Command line
-
hf download hf://aLocks/Plynder-1/README.md
-
curl -L -o README.md https://huggingface.co/aLocks/Plynder-1/resolve/main/README.md
6.27 kB
| license: apache-2.0 | |
| library_name: transformers | |
| pipeline_tag: text-generation | |
| tags: | |
| - chess | |
| - reinforcement-learning | |
| - self-play | |
| - qwen3 | |
| - causal-lm | |
| - pytorch | |
| # Plynder-1 | |
| Plynder-1 is a randomly initialized 50M-parameter Qwen3 architecture trained | |
| to play chess through reinforcement learning and self-play. | |
| It does not use pretrained Qwen language-model weights and was not trained by imitating a PGN corpus. | |
| Plynder represents a game as UCI move tokens. Its public vocabulary has 1,972 | |
| entries: 1,968 possible moves and four game-state tokens: `<bos>`, `<draw>`, | |
| `<white_win>`, and `<black_win>`. The causal model produces logits for the full | |
| vocabulary; legal-move filtering is required before selecting an action. | |
| > [!Note] | |
| > Plynder-1 is a chess policy model. It | |
| > predicts moves in Plynder's custom token space. Select actions from the legal | |
| > moves in the current position as shown in the inference example. | |
| ## Model overview | |
| | Property | Value | | |
| |---|---| | |
| | Architecture | `Qwen3ForCausalLM` | | |
| | Parameters | ~50M | | |
| | Hidden size | 512 | | |
| | Transformer layers | 16 | | |
| | Attention heads | 8 query heads, 4 key-value heads | | |
| | Head dimension | 64 | | |
| | Feed-forward dimension | 1,534 | | |
| | Vocabulary | 1,972 chess and game-state tokens | | |
| | Maximum sequence length | 8,000 tokens | | |
| | Training precision | bfloat16 | | |
| The policy model uses full attention in all transformer layers. | |
| ## Training recipe | |
| | Setting | Value | | |
| |---|---:| | |
| | Steps | 265k | | |
| | Global batch size | 8192 | | |
| | Optimizer | Muon and AdamW | | |
| | Learning rate | `7e-4` | | |
| | Rollout group size | 16 continuations | | |
| | Policy objective | CISPO | | |
| | CISPO lower and upper bounds | `0.1` and `0.2` | | |
| | CISPO importance-sampling mask | Enabled | | |
| | Rules objective | KL distillation from legal-move masks | | |
| During training, a separate linear rules head reads the intermediate hidden state at layer 6 and | |
| predicts the legal-move mask. The rules head is an auxiliary training component; | |
| standard Transformers inference uses the published causal language model. | |
| For each opening position, rollout generates a group of continuations. Their | |
| outcomes provide group-relative advantages, separately for White and Black. The | |
| policy is updated with CISPO, while the rules head receives a dense legal-move | |
| signal from the Rust chess engine. | |
| ## Training statistics | |
| | Statistic | Value | | |
| |---|---:| | |
| | Tokens processed by trainer | **245.3B** padded token slots | | |
| | Non-padding trainer tokens | **232.7B** | | |
| | Tokens generated by rollout | **134.7B** kept-group tokens | | |
| | Games generated | **1.62B** sampled continuations (**1.27B** in kept groups) | | |
| | Average padding ratio | **5.16%** | | |
| The rollout-token total counts the full token sequence for every member of a | |
| kept 16-game group, including the shared opening prefix each time. Groups whose | |
| continuations all have the same outcome are discarded. The | |
| game total includes every sampled continuation; the kept-group figure excludes | |
| discarded groups. | |
| ### Training progress | |
| <p align="center"> | |
| <img | |
| src="https://huggingface.co/aLocks/plynder-1/resolve/main/plynder_1_training_progress.png" | |
| alt="Plynder-1 training progress" | |
| width="860" | |
| > | |
| </p> | |
| The plot shows the smoothed internal strength trajectory. Its horizontal axis is | |
| kept rollout tokens, with the shared prefix counted for every continuation. | |
| ### Data staleness | |
| The estimated mean rollout-data staleness is **5.6 optimizer steps**: | |
| - **0.6 steps**: measured p50 trajectory/group latency | |
| - **1.0 step**: expected delay from the 16,384-trajectory sampler buffer | |
| - **4.0 steps**: expected delay from refreshing rollout weights every 8 optimizer steps | |
| The latter two values use half the corresponding buffering/refresh interval as | |
| the expected delay. | |
| ## Evaluation | |
| Plynder-1 measured an internal ranking of **1,433**. The ranking is an Elo-like project metric | |
| calibrated against Stockfish with 4,096-game evaluations. It is not a Lichess | |
| rating. | |
| A deployment of the trained model on Lichess reached approximately **1,550 Elo** | |
| in the Bullet time control. | |
| ## Usage | |
| Install the inference dependencies: | |
| ```bash | |
| pip install torch transformers chess | |
| ``` | |
| The following example loads the tokenizer from the model repository and chooses | |
| the highest-scoring legal UCI move: | |
| ```python | |
| import chess | |
| import torch | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| CASTLING_MAP = {"e1g1": "e1h1", "e1c1": "e1a1", "e8g8": "e8h8", "e8c8": "e8a8"} | |
| def to_plynder_uci(move: chess.Move, board: chess.Board) -> str: | |
| """Convert a python-chess move to Plynder's token notation.""" | |
| uci = move.uci() | |
| return CASTLING_MAP.get(uci, uci) if board.is_castling(move) else uci | |
| model_name = "aLocks/plynder-1" | |
| tokenizer = AutoTokenizer.from_pretrained(model_name) | |
| model = AutoModelForCausalLM.from_pretrained(model_name) | |
| prompt = "<bos> e2e3 f7f6 b1c3 g7g5" | |
| # Get legal moves | |
| board = chess.Board() | |
| for uci in prompt.split(" ")[1:]: | |
| board.push_uci(uci) | |
| legal = list(board.legal_moves) | |
| legal_ids = torch.tensor( | |
| tokenizer.convert_tokens_to_ids([to_plynder_uci(move, board) for move in legal]) | |
| ) | |
| # Infer policy | |
| inputs = tokenizer(prompt, return_tensors="pt") | |
| with torch.inference_mode(): | |
| logits = model(**inputs).logits[0, -1] | |
| played_uci = legal[logits.index_select(0, legal_ids).argmax().item()].uci() | |
| print("played:", played_uci) | |
| ``` | |
| Plynder uses UCI-like move tokens. For castling, its vocabulary uses the | |
| king-to-rook forms `e1h1` or `e1a1` for White and `e8h8` or `e8a8` for Black. | |
| ## Limitations | |
| - Plynder-1 is train to continue games with at least 2 moves (4 plies). To get variability, use an opening book | |
| - Legal filtering is part of the inference procedure. The raw language-model | |
| logits also contain illegal moves and game-state tokens. | |
| - A board created directly from a FEN has no prior move history. Provide the | |
| history when it is available. | |
| ## Source and license | |
| Plynder-1 is released under the Apache License 2.0. The training system, Rust | |
| legal-move engine, and configuration are available in the | |
| [source repository](https://github.com/AntoineLorentz/plynder). | |
| ## Citation | |
| ``` | |
| @software{plynder, | |
| author = {AntoineLorentz}, | |
| title = {Plynder}, | |
| url = {https://github.com/AntoineLorentz/plynder}, | |
| license = {Apache-2.0} | |
| } | |
| ``` | |