space-pilot

A 0.5B language model that chooses which enemy to shoot in a browser Space Invaders game. It is Qwen/Qwen2.5-0.5B-Instruct, LoRA-fine-tuned with MLX on the decisions of a learned game pilot (distillation), merged, and exported to GGUF in F16 and Q8_0.

The model is one half of a pilot. It answers a compact JSON observation with a target. The game's reflex layer, which runs at 120 Hz, does the steering. It dodges shots, follows the chosen enemy and collects drops by fixed rules. Without that layer, the model's answers are only targets. The game, the reflexes, the training and the benchmark are in lcir/Space (see docs/LEARNING.md).

Use with Ollama

ollama run hf.co/penous/space-pilot:Q8_0   # 531 MB, slightly faster
ollama run hf.co/penous/space-pilot:F16    # 994 MB, the original export

Both files hold the same fine-tuned weights and play equally well (see Evaluation). Or locally with the included Modelfile (F16; point FROM at the Q8_0 file to use that one):

ollama create space-pilot -f Modelfile

Use temperature 0 and constrain the output to this JSON schema (Ollama format):

{"type":"object","properties":{"targetX":{"type":"number","minimum":32,"maximum":928},"fire":{"type":"boolean"},"dodge":{"type":"boolean"}},"required":["targetX","fire"],"additionalProperties":false}

Prompt

The model was trained on exactly this system prompt; the text after Strategy memory: is the game's default strategy.

You fly a Space Invaders ship. Enemy entries are [x,y]; incoming shots are [x,y,vx,vy]; direction is the formation movement (1 right, -1 left). The ship dodges and collects drops by itself. Choose targetX (32..928) under the enemy to shoot, usually a bottom one; fire=true, dodge=true. Reply only short JSON. Strategy memory: Aim at the bottom-most invaders. Keep clear of incoming shots.

The user message is the observation: the ship's position, lives, the formation direction, the 12 enemies nearest the ship ([x, y]), the enemy count, the 6 nearest incoming shots ([x, y, vx, vy]) and the sector. The world is 960Γ—680 px.

{"ship":"player","x":480,"y":594,"lives":3,"direction":-1,"enemies":[[515,307],[515,255],[515,203],[578,307],[451,151],[515,151],[578,255],[578,203],[387,151],[578,151],[323,151],[131,307]],"enemyCount":19,"incoming":[[402,345,0,218],[625,613,0,218]],"wave":1}

This model answers {"targetX":453,"fire":true,"dodge":true}, and the reflexes then follow the enemy nearest that position. The current teacher would answer {"targetX":485,"fire":true,"dodge":true}: the bottom enemy at x 515, aimed 30 px ahead of the formation, which moves left.

Training

This release is distillation run 3 of lcir/Space.

  • Teacher: a small game controller whose parameters were trained with a (1 + Ξ») evolution strategy on the level reached in the real game engine. At the time of run 3, it aimed at the bottom enemies, dodged every incoming shot and chased drops by learned values.
  • Data: 6,000 chat examples per run from the teacher's games, one per second. The answer is the teacher's target. The prompt of runs 2 and 3 also listed the falling drops and the triple-laser time, so the model learned to aim at drops too.
  • Fine-tuning: three runs, each resuming from the previous adapter: LoRA on 16 layers, mlx_lm lora with --mask-prompt, 600 iterations, batch 8, learning rate 1e-4.
  • Export: the merged weights are written to GGUF with the tokenizer and metadata of the original qwen2.5:0.5b GGUF. Norms are F32, the other weights F16. The Q8_0 file is the F16 file with every 2-D tensor quantized to Q8_0 (as llama-quantize q8_0 does); norms and biases stay F32.
  • Gate: a model replaces the champion only if it reaches a higher level than both the base model and the current champion on a fixed benchmark. Later runs (4–7), trained for the current reflexes and prompt, have not beaten it yet.

Since run 3, the game's reflexes took over everything that needs fast reactions: exact dodging, collecting drops at the last moment by fixed rules, and following the chosen enemy between decisions. The model is now used with the shorter prompt above, which no longer lists drops. A target it aims at a drop is handled by the reflexes.

Evaluation

npm run bench:llm in lcir/Space: 8 seeded games, each played until it is lost or for at most 300 s. Level is the sector reached minus the fraction of it left.

Benchmark version 8 plays the arena's timing: the game waits for each model decision, then plays it after a fixed latency of 0.15 s and asks again 0.2 s later, so the score does not depend on the machine's speed. It also includes two reflex fixes that version exposed (collisions predicted where the ship really stops, and the commanded enemy named in the state the model saw):

Pilot Level + / ϟ collected per game
qwen2.5:0.5b (base model) 27.04 26.6 / 42.3
space-pilot F16 51.85 42.5 / 70.4
space-pilot Q8_0 53.10 46.5 / 77.8
teacher's targets through the same command path (oracle) 51.48 43.8 / 66.9

Every game of the two space-pilot files lasts the full 300 s. The difference between F16 and Q8_0 is within the noise of 8 games: quantization did not cost accuracy. Without contention, one decision takes 126–135 ms with F16 and 104–115 ms with Q8_0 (Ollama on an Apple Silicon Mac; about 250 prompt tokens and 18 answer tokens).

Benchmark version 7 froze the game for each decision and applied it at once, one every 0.25 game seconds:

Pilot Level Game length + / ϟ collected per game
qwen2.5:0.5b (base model) 9.15 90 s 8.5 / 13.9
space-pilot (this model) 54.16 300 s 51.5 / 73.8
teacher's targets through the same command path (oracle) 53.33 300 s 47.3 / 68.4
the teacher itself, deciding at 120 Hz 56.66 300 s 47.4 / 74.1

On version 7 the model outlasts every benchmark game. 17 of its 9,600 answers were invalid; for those, the previous target is kept until the next decision.

Limitations

  • The model only makes sense inside this game with its reflex layer. It knows nothing else, and on other prompts it behaves like a weaker Qwen2.5-0.5B-Instruct.
  • It decides from a partial observation (12 enemies, 6 shots) a few times a second; the reflexes handle everything that needs faster reactions.
  • It was trained on an earlier prompt that also listed drops. It still works with the current one, but it does not match it exactly.
  • The benchmark has 8 games, so differences of a few levels are within noise.

License

Apache-2.0, like the base model Qwen/Qwen2.5-0.5B-Instruct. This is a modified version of that model: it is fine-tuned, merged and converted to GGUF.

Downloads last month
79
GGUF
Model size
0.5B params
Architecture
qwen2
Hardware compatibility
Log In to add your hardware

8-bit

16-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for penous/space-pilot

Finetuned
(1164)
this model