Instructions to use thealper2/lfm2-350m-2048-lora with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use thealper2/lfm2-350m-2048-lora with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("LiquidAI/LFM2-350M") model = PeftModel.from_pretrained(base_model, "thealper2/lfm2-350m-2048-lora") - Notebooks
- Google Colab
- Kaggle
LFM2-350M 2048 policy (LoRA adapter)
LiquidAI/LFM2-350M fine-tuned with supervised LoRA to map a 2048 board and its legal moves to the next move (LEFT/UP/RIGHT/DOWN), trained on the 2048 demonstrations of IntelligenceLab/Cos-Play-Cold-Start.
Model
| Base model | LiquidAI/LFM2-350M (354M params; 16 layers: 10 short-conv + 6 GQA attention) |
| Fine-tuning | LoRA, r=16, alpha=32, dropout=0.05 |
| LoRA targets | q_proj, k_proj, v_proj, out_proj, in_proj, w1, w2, w3 (92 modules) |
| Trainable params | 5,996,544 |
| Precision | bfloat16 |
| Context used | ~384 tokens max (prompts ≈ 85–90 tokens) |
Input / output format
LFM2 chat template, single user turn, greedy decoding. The prompt lists only legal (board-changing) moves in the fixed order LEFT, UP, RIGHT, DOWN:
Game: 2048
State:
[0, 2, 0, 0]
[0, 4, 2, 0]
[0, 0, 8, 0]
[0, 0, 0, 0]
Available actions:
LEFT
UP
RIGHT
DOWN
Choose the next action:
Target completion: one action word followed by <|im_end|> (training loss is computed only on these tokens).
Training data
| Source | IntelligenceLab/Cos-Play-Cold-Start, configs grpo_action_taking_twenty_forty_eight + episodes_twenty_forty_eight |
| Demonstrator | GPT-5.4 agent, 60 episodes, ≤200 steps each, max tile 256 |
| Examples | 8125 steps; 1151 no-op demonstrations removed |
| Board source | episode state (action-taking prompts only contain a text summary); 289 boards repaired for a uint8 display overflow (256 shown as 0) |
| Split | episode-level 80%/10%/10%, seed 42 |
| Episodes (train/val/test) | 48/6/6 |
| Examples (train/val/test) | 5668/731/575 |
| Action distribution | LEFT 50.1%, UP 20.7%, DOWN 18.2%, RIGHT 11.0% |
Training procedure
| Hyperparameter | Value |
|---|---|
| Epochs | 3 |
| Learning rate / schedule | 0.0001 / cosine, warmup ratio 0.05 |
| Batch size | 1 × grad. accumulation 16 = 16 |
| Weight decay / max grad norm | 0.0 / 1.0 |
| Optimizer | AdamW (torch fused) |
| Checkpoint selection | best validation action_accuracy (greedy first-token action accuracy) |
| Optimizer steps | 1065 |
| Best checkpoint | checkpoint-750 (val accuracy 60.5%) |
| Hardware / runtime | NVIDIA GeForce RTX 5060 Ti, 34.7 min, peak 2.66 GB |
| Seed | 42 |
Evaluation
Offline action prediction (held-out test episodes)
| Metric | Value |
|---|---|
| Examples | 575 |
| Accuracy | 61.6% |
| Macro accuracy | 44.2% |
| Accuracy LEFT (n=292) | 89.0% |
| Accuracy UP (n=114) | 40.4% |
| Accuracy RIGHT (n=63) | 4.8% |
| Accuracy DOWN (n=106) | 42.5% |
| Invalid generation rate | 0.0% |
| Illegal action rate | 0.0% |
| Reference: majority / random / heuristic agreement | 60.2% / 29.2% / 43.0% |
Autonomous gameplay
Local 2048 environment (4×4, spawn 2/4 with p=0.9/0.1, reward = merged tile values; validated against the dataset: 100.0% transition match). 100 games, seeds 0–99, played until no legal move remains. Invalid outputs get one retry with a stricter prompt, then a deterministic fallback (first legal move).
| Agent | Mean score | Median | Mean max tile | ≥512 | ≥1024 | 2048 rate | Mean steps | Invalid | Retry | Fallback |
|---|---|---|---|---|---|---|---|---|---|---|
| this model | 2,677.1 | 2,600 | 220.8 | 7 | 0 | 0.0% | 228.9 | 0.0% | 0.0% | 0.0% |
| greedy heuristic | 7,753.6 | 7,242 | 572.2 | 69 | 24 | 2.0% | 518.2 | 0.0% | 0.0% | 0.0% |
| majority action | 2,545.6 | 2,478 | 206.1 | 5 | 0 | 0.0% | 224.4 | 0.0% | 0.0% | 0.0% |
| random legal | 1,018.9 | 872 | 96.5 | 0 | 0 | 0.0% | 112.9 | 0.0% | 0.0% | 0.0% |
Usage
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
model = AutoModelForCausalLM.from_pretrained("LiquidAI/LFM2-350M", dtype=torch.bfloat16).cuda()
model = PeftModel.from_pretrained(model, "thealper2/lfm2-350m-2048-lora").merge_and_unload()
tok = AutoTokenizer.from_pretrained("thealper2/lfm2-350m-2048-lora")
board = [[0, 2, 0, 0], [0, 4, 2, 0], [0, 0, 8, 0], [0, 0, 0, 0]]
legal = ["LEFT", "UP", "RIGHT", "DOWN"] # only moves that change the board
prompt = ("Game: 2048\n\nState:\n" + "\n".join(str(r) for r in board)
+ "\n\nAvailable actions:\n" + "\n".join(legal) + "\n\nChoose the next action:")
text = tok.apply_chat_template([{"role": "user", "content": prompt}], tokenize=False, add_generation_prompt=True)
ids = tok(text, return_tensors="pt", add_special_tokens=False).to(model.device)
out = model.generate(**ids, max_new_tokens=6, do_sample=False)
print(tok.decode(out[0, ids["input_ids"].shape[1]:], skip_special_tokens=True)) # e.g. "LEFT"
Board rows must be formatted exactly as [a, b, c, d] and actions listed in the order LEFT, UP, RIGHT, DOWN.
Limitations
- Imitation of a weak demonstrator: training episodes stop at ≤200 steps and never exceed tile 256, so late-game boards with 512+ tiles are outside the training distribution.
- Board-only policy: no move history, no lookahead; one move per forward pass.
- Offline accuracy measures agreement with the demonstrator, not move quality; several moves are often equally good in 2048.
- Trained and evaluated on 4×4 boards with the prompt format above only.
- Downloads last month
- 17
Model tree for thealper2/lfm2-350m-2048-lora
Base model
LiquidAI/LFM2-350M