Downloads · 30 days
5
13% of all-time downloads
dmitchelljackson/cerebellum-e4b-lora
cerebellum-e4b-lora is a machine learning model from dmitchelljackson. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for peft. The card lists the license as apache-2.0.
LoRA adapter on top of google/gemma-4-E4B-it that predicts the next Android UI action given a screenshot and accessibility tree.
Downloads · 30 days
5
13% of all-time downloads
All-time downloads
38
Public
Repo size
1.2 GB
Likes
0
Public
Click a slice to open those files.
.safetensors559 MB · 95%
From the Hugging Face model README
LoRA adapter on top of google/gemma-4-E4B-it that predicts the next Android UI action given a screenshot and accessibility tree.
Architecture: The LLM (or orchestrating agent) issues high-level intent. Cerebellum executes it locally by grounding intent to a specific UI element and action — without screenshot round-trips to a remote model.
Given a task goal, the current screen (screenshot + accessibility tree), and optional action history, the model outputs a single compact action code indicating what to do next.
The model uses a chat-style prompt (Gemma4 format). The user turn is structured as:
Task: {goal}
Step 1 (past): <|image|> -> {action_text}
Step 2 (past): <|image|> -> {action_text}
...
Current screen: <|image|>
{compressed_accessibility_tree}
[n zone]=tap-target(top-to-bottom left-to-right) zone=tl/tc/tr/ml/mc/mr/bl/bc/br ed=text-input sr=scrollable fc=focused(use 'K your_text' to type here)
Actions: T{n}=tap element n, P{n}=long-press element n, K {text}=type text(space required), U/D/L/R=scroll(single token), B=back, H=home, W=wait, F=done, I=impossible
Next action:
Inputs:
goal — natural language task description (e.g. "Open the settings app and enable dark mode")history — up to 4 past (screenshot, action) pairs; can be emptycurrent screenshot — PIL image of the current screen, resized to 896px on the long edgecompressed_accessibility_tree — compact text representation of the UI element tree (see below)Each interactive element is one line:
[0 btn tl] Settings
[1 ed mc fc=focused] Search...
[2 btn sr tr] More options
Fields per element:
[n] — element index (used in action codes)bt=Button, ed=EditText, tx=TextView, im=ImageView, ck=CheckBox, sw=Switch, rd=RadioButton, sp=Spinner, sc=ScrollView, ls=ListView/RecyclerView, bar=Toolbar, tab=TabLayout, dw=DrawerLayout, vw=othert=top, m=mid, b=bottom) + col (l=left, c=center, r=right), e.g. tl=top-left, mc=mid-centerfc — element has keyboard focus (K action types here)ed — element is editable (text input)sr — element is scrollablehd — element supports long-pressds — element is disabledck/uc — checkbox checked/uncheckedsl — element is selectedpw — password field...above (N nodes, scroll up) / ...below (N nodes, scroll down) — off-screen content indicatorsThe raw Android accessibility tree is compressed before being passed to the model:
x2<=0, y1>=screen_height, etc.) are excluded; replaced with ...above (N) / ...below (N) scroll indicatorsclickable=true AND enabled=true nodes get a numeric index [n]. Non-clickable nodes are rendered without an index. Index order is top-to-bottom, left-to-right by element positionandroid.widget.Button → bt)tl/tc/tr/ml/mc/mr/bl/bc/br)text is preferred; falls back to content_desc; falls back to resource_id (last component after /)A single action code (one forward pass, greedy decode):
| Code | Action | Example |
|---|---|---|
T{n} | Tap element n | T7 |
P{n} | Long-press element n | P3 |
K {text} | Type text into focused field | K hello world |
U | Scroll up | U |
D | Scroll down | D |
L | Scroll left | L |
R | Scroll right | R |
B | System back | B |
H | Home button | H |
W | Wait (screen loading) | W |
F | Done (task complete) | F |
I | Impossible (task cannot complete) | I |
Single-token actions (U/D/L/R/B/H/W/F/I) self-terminate — no EOS token follows. T/P generate up to 5 tokens (letter + digits + EOS). K generates until EOS.
The model occasionally produces malformed outputs (action letter fused with wrong content, e.g. B4, W3, T some text). A lightweight validator detects these and retries with a disambiguating correction blurb appended to the prompt:
Next action:
'B4' is not valid. Did you mean 'B' (back) or 'T4' (tap element 4)? Try again:
This zero-shot correction resolves the majority of format errors without additional training.
Evaluated on AndroidControl dataset (accessibility tree format, single-step predictions):
| Metric | Last 20 steps | Last 50 steps | All (102 steps) |
|---|---|---|---|
| Overall accuracy | 95.0% | 92.0% | 88.2% |
| Element index accuracy | 93.3% | 88.6% | 84.6% |
Action type breakdown (last 20 steps):
| Action | Accuracy |
|---|---|
| tap (T) | 93% |
| scroll (U/D/L/R) | 100% |
| back (B) | 100% |
| type (K) | 100% |
| wait (W) | 100% |
Remaining errors are primarily element index off-by-one on tap targets — a known SFT ceiling, addressed by RL.
Base model: google/gemma-4-E4B-it (4B MoE, 4-bit quantized during training via bitsandbytes)
LoRA config:
r=64, alpha=32, dropout=0.05Training data: AndroidControl dataset (accessibility tree variant), ~20 shards from GCS. Each sample is a single (screenshot, a11y tree, goal, history) → action step from a real Android interaction trajectory.
Key training decisions:
accum_steps=1 — every sample is its own gradient update (maximum signal density)lr=5e-5, cosine scheduleTraining infrastructure:
To replicate from scratch:
scripts/preprocess_a11y.py to extract accessibility treespy -3.11 -u scripts/train_autoregressive.py --out checkpoints/autoreg/currentpy -3.11 -u scripts/train_autoregressive.py --resume checkpoints/autoreg/current/step_XXXXXXX --out checkpoints/autoreg/currentfrom transformers import AutoProcessor
from peft import PeftModel
from transformers import Gemma4ForConditionalGeneration
import torch
base = Gemma4ForConditionalGeneration.from_pretrained(
"google/gemma-4-E4B-it",
torch_dtype=torch.bfloat16,
device_map="auto",
)
model = PeftModel.from_pretrained(base, "dmitchelljackson/cerebellum-e4b-lora")
processor = AutoProcessor.from_pretrained("dmitchelljackson/cerebellum-e4b-lora")
model.eval()