Downloads · 30 days
11
15% of all-time downloads
jpcurada/likas-gemma4-e2b-lora
likas-gemma4-e2b-lora is a text generation model from jpcurada. Use it when you need the model to write or continue text. It is set up for peft. The card lists the license as gemma.
LoRA fine-tune of google/gemma-4-e2b-it that turns the base model into LIKAS, an offline disaster-response assistant for the Philippines. The model emits a strict JSON envelope for every turn — either a tool call or a…
Downloads · 30 days
11
15% of all-time downloads
All-time downloads
74
Public
Repo size
281 MB
Likes
0
Public
Click a slice to open those files.
.safetensors248 MB · 89%
From the Hugging Face model README
LoRA fine-tune of google/gemma-4-e2b-it that turns the base model into LIKAS, an offline disaster-response assistant for the Philippines. The model emits a strict JSON envelope for every turn — either a tool call or a user-facing reply — so it can be safely run on-device inside a React Native app via llama.rn.
This is the model that powers LIKAS, an offline-first mobile app for earthquake / typhoon / volcanic-eruption preparedness, evacuation routing, and POI search across Metro Manila.
⚠️ This is a fine-tune for a specific app, not a general-purpose chatbot. It only emits structured JSON and is grounded in NDRRMC / PAGASA / PHIVOLCS protocols. Use it inside the dispatch loop described below or it will produce JSON your client must parse.
This repository hosts the LoRA adapter. The full pipeline produces three artifacts:
| Repo | Contents | Use when |
|---|---|---|
jpcurada/likas-gemma4-e2b-lora | LoRA adapters (~110 MB) | You have base Gemma 4 E2B-IT loaded and want to attach the adapter at runtime |
jpcurada/likas-gemma4-e2b-fp16 | Merged fp16 HF checkpoint (~10 GB) | You want a standalone HF model for further fine-tuning or vLLM serving |
jpcurada/likas-gemma4-e2b-gguf | likas-q4_k_m.gguf (~1.8 GB) | You want to run on mobile / CPU via llama.cpp / llama.rn (the production target) |
In scope:
get_protocol toolroute_to_nearest_evacuation tool (returns a polyline the UI draws on a MapLibre map)find_nearbyget_user_profileOut of scope:
Every turn the model produces exactly one JSON object on a single line. There is no prose outside the JSON. Two shapes:
{"action": "tool", "name": "<tool_name>", "args": {...}}
{"action": "speak", "text": "<reply to user>"}
After the host runs the tool and injects the result, the model decides again — either another tool call or a final speak turn. The host typically caps the tool-dispatch loop at 3 iterations per user query.
| Tool | Args | Purpose |
|---|---|---|
get_protocol | disaster: "earthquake"|"typhoon"|"volcano", phase: "before"|"during"|"after" | Returns the official authority protocol text for the requested combination. The model must quote it verbatim in its speak turn. |
route_to_nearest_evacuation | profile_aware?: boolean | Returns the top-3 nearest evacuation centers and (if the pedestrian graph is installed) a walkable polyline + ETA. |
find_nearby | category: "hospital"|"evacuation_center"|"gymnasium"|"school"|"multi_purpose_hall"|"covered_court" | Returns the 3 nearest POIs of the given category with distances. |
get_user_profile | {} | Returns medical conditions, companions, meeting points, emergency contacts — only when the user asks about themselves. |
user: Bagyo na, kailangan kong lumikas
assistant {"action":"tool","name":"get_protocol","args":{"disaster":"typhoon","phase":"during"}}
tool {"name":"get_protocol","result":"PAGASA and NDRRMC guidance: Stay indoors..."}
assistant {"action":"speak","text":"Mga puntos mula sa PAGASA: Stay indoors away from windows..."}
user: Saan ako lilikas?
assistant {"action":"tool","name":"route_to_nearest_evacuation","args":{"profile_aware":true}}
tool {"name":"route_to_nearest_evacuation","result":"Top evacuation options: 1. Manila High School..."}
assistant {"action":"speak","text":"Pinakamalapit: Manila High School (0.8 km, ~11 min lakad). Naka-plot na sa mapa ang ruta..."}
Trained on jeypiic/likas-ai-datasets (v4) — 691 conversations stratified across 10 task categories, with assistant-output uniqueness of ~80% on speak turns (compared to 30% on v3, which overfit).
| Section | Train+Test | Purpose |
|---|---|---|
| protocol_qa | 162 | Quote NDRRMC / PAGASA / PHIVOLCS protocols across 4 styles × 3 languages × shuffled rule orderings |
| evacuation | 180 | Route to nearest evacuation center; teaches all 3 runtime tail variants (route resolved / graph missing / snap failed) |
| nearby_poi | 153 | find_nearby across all 6 categories using real OpenStreetMap POIs inside the pedestrian-graph bbox |
| profile_aware | 80 | get_user_profile → personalized go-bag / meds / meeting-point answers |
| multi_tool | 40 | Protocol → user follow-up → evacuation in one conversation |
| multi_turn | 40 | Follow-up corrections: switch tool, switch phase, ask about constraints |
| refusal | 15 | Rule 7 — politely refuse off-topic queries and redirect |
| direct_speak | 10 | Greetings and meta-questions that don't need a tool |
| clarification | 8 | Ambiguous user input ("it's bad", "help") — model asks what's wrong first |
| tool_error | 3 | Graceful degradation when a tool returns "unknown category" / "no protocol on file" |
User origins are sampled from 20 Metro Manila barangay centroids; POIs are loaded from OSM extracts (59 hospitals, 75 schools, etc.) inside bbox=(120.85, 14.25, 121.30, 14.90). Distances and walking ETAs are computed via haversine + a 4.2 km/h pace, matching the production routingService exactly.
The runtime tool result strings are 1:1 with what Likas/src/services/aiTools.ts produces, so the model sees the same distribution at inference time as during training.
unsloth/gemma-4-E2B-it (4-bit quantized for training)transformers==5.5.0, trl (Unsloth pin), peft, bitsandbytes, unsloth_zoor=32, alpha=32, dropout=0q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_projadamw_8bit, learning rate 2e-4, cosine schedule, warmup ratio 0.03max_grad_norm=0.3, weight_decay=0.0013407Per-step train and validation loss were logged to Weights & Biases. The full notebook is at Likas_Gemma4_E2B_Finetune.ipynb.
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="jpcurada/likas-gemma4-e2b-lora",
max_seq_length=4096,
load_in_4bit=True,
)
FastLanguageModel.for_inference(model)
SYSTEM_PROMPT = """...""" # see README of the dataset for the exact prompt
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": "May lindol! Ano gagawin ko?"},
]
prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
out = model.generate(**inputs, max_new_tokens=256, temperature=1.0, top_p=0.95, top_k=64)
print(tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))
Download likas-q4_k_m.gguf from jpcurada/likas-gemma4-e2b-gguf and load via llama.rn. The LIKAS app constrains generation with a GBNF grammar (Likas/src/services/aiGrammar.ts) so the model is forced to emit valid JSON envelopes even at temperature 1.0.
Loss curves are logged to wandb during training. We do not publish a benchmark score because the model is task-specific (Filipino disaster-response tool-calling); no standard benchmark covers this distribution.
Manual evaluation rubric used in development:
get_protocol for safety-critical, route_to_nearest_evacuation for evacuation, find_nearby for POI, get_user_profile for self-queriesroute_state == "route_ok", the speak turn references the polyline drawn on the map(120.85, 14.25, 121.30, 14.90) is undefined.Distributed under the Gemma Terms of Use (inherited from the base model). You must accept Google's Gemma license before using this adapter. Training data is the author's own work (jeypiic/likas-ai-datasets) and is governed by that dataset's license.
@misc{likas-gemma4-e2b-2026,
author = {John Paul Curada},
title = {LIKAS — Gemma 4 E2B-IT fine-tune for offline disaster response in the Philippines},
year = {2026},
url = {https://huggingface.co/jpcurada/likas-gemma4-e2b-lora},
}