convaiinnovations/shoeguard-safety-slm-q4_k_m
ShoeGuard Safety SLM (SmolLM2-135M Q4KM)
This is the fine-tuned SmolLM2-135M model for the ShoeGuard edge AI chip, quantized to Q4KM GGUF format.
Overview
ShoeGuard is the smallest edge AI chip embedded in a tiny custom PCB designed for women's safety. It fires a panic alarm and sends location alerts (via GPS) to relatives when the wearer performs a deliberate repeated kick pattern.
The model takes a 14-dimensional summary feature vector extracted from a two-second window of 50 Hz MPU6050 IMU data and classifies the leg action into one of 10 classes: standing, sitting, walking, running, jumping, stomp, shake_leg, soft_kick, hard_kick, repeated_kick.
Hardware Deployment
The model is quantized to Q4KM (approx. 88 MB) to run efficiently on an RP2040/RP2350 microcontroller with external PSRAM using llama.cpp.
Inference Prompt
The on-chip firmware constructs a short prompt containing the 14 extracted features:
You are an on chip safety monitor for a shoe mounted MPU6050. Given the IMU window features below classify the leg action into one of: standing, sitting, walking, running, jumping, stomp, shake_leg, soft_kick, hard_kick, repeated_kick. Reply with the label only.
acc_mean_g=... acc_std_g=...Intended Use
This model is intended strictly for the physical trigger engine aboard the ShoeGuard PCB to determine whether an emergency impact sequence has occurred. It acts as an embedded classifier running locally, fully preserving wearer privacy.
Python Inference Example
You can test the model logic locally using llama-cpp-python and the provided test dataset.
from llama_cpp import Llama
import json, time
llm = Llama(model_path='safety-q4_k_m.gguf', n_gpu_layers=0, n_ctx=512, n_threads=4, verbose=False)
from collections import deque
KICKS = {'hard_kick', 'repeated_kick'}
history = deque(maxlen=3)
# Chat template (SmolLM2 Instruct format)
input_prompt = "<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n{}"
def classify(user_msg):
p = input_prompt.format(user_msg, '')
out = llm(p, max_tokens=8, temperature=0.0, top_p=1.0, stop=['###', '\n\n', '<|im_end|>'])
return out['choices'][0]['text'].strip().lower()
def trigger(label):
history.append(label)
if label == 'repeated_kick':
return True
return sum(1 for x in history if x in KICKS) >= 2
# Load dataset and demo trigger
rows = [json.loads(l) for l in open('imu_actions_1000.jsonl', encoding='utf-8')]
demo = [r for r in rows if r['label'] in ('walking','hard_kick','hard_kick','repeated_kick')][:6]
for r in demo:
user = next(m['content'] for m in r['messages'] if m['role'] == 'user')
t0 = time.time()
pred = classify(user)
fire = trigger(pred)
print(f"true={r['label']:14s} pred={pred:14s} fire={fire} ({(time.time()-t0)*1000:.0f} ms)")