--- language: - en library_name: transformers base_model: LiquidAI/LFM2.5-350M tags: - schema-extraction - json-extraction - structured-output - information-extraction - lora - edge-ai - schemalm --- # SchemaLM v2 — LFM2.5 350M A 350M parameter model fine-tuned for **JSON-schema-conditioned information extraction**. Give it a JSON Schema and any unstructured text — it returns a JSON object that matches the schema exactly. **Base model:** [`LiquidAI/LFM2.5-350M`](https://huggingface.co/LiquidAI/LFM2.5-350M) (SSM hybrid, ideal for edge/CPU deployment) --- ## Benchmark Results | Metric | Score | |---|---| | Overall score (v2 training benchmark) | **97.7%** | | JSON validity | **100%** | | Schema conformance | **100%** | | Field extraction accuracy | **97.6%** | | Internal benchmark cases | **96.2%** | Evaluated on a 25-case internal benchmark covering easy/medium/hard extraction across 7 domains. | Domain | Avg Accuracy | |---|---| | Software Projects | ~74% | | Governance / Compliance | ~75% | | HR | ~85% | | Education | ~81% | | Sales | ~55% | | Healthcare | ~53% | | Support (phone) | ~61% | --- ## Training - **Dataset:** 49K synthetic schema-extraction examples (93 schemas, 29 domains, nested object/array coverage) - **Method:** PEFT/LoRA SFT — rank 32, alpha 64, ~2% trainable parameters - **Epochs:** 5 | **LR:** 2e-4 (cosine) | **Max seq:** 768 tokens - **Precision:** bf16 on Ampere/Hopper, fp16 otherwise --- ## Usage The model follows the **ChatML format**: system message = JSON Schema, user message = unstructured text, assistant response = JSON. ### Basic (Transformers) ```python from transformers import AutoModelForCausalLM, AutoTokenizer import torch, json model_id = "senthil090/schemalm-v2-lfm2-350m" tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained( model_id, torch_dtype=torch.bfloat16, device_map="auto" ) model.eval() def extract(schema: dict, text: str, max_new_tokens: int = 256) -> dict: messages = [ {"role": "system", "content": json.dumps(schema)}, {"role": "user", "content": text}, ] prompt = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) inputs = tokenizer(prompt, return_tensors="pt").to(model.device) with torch.no_grad(): out = model.generate( **inputs, max_new_tokens=max_new_tokens, do_sample=False, repetition_penalty=1.08, ) raw = tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True) return json.loads(raw.strip()) ``` --- ### Example 1 — Sprint planning note → structured task ```python schema = { "type": "object", "properties": { "task_title": {"type": "string"}, "assignee": {"type": "string"}, "priority": {"type": "string", "enum": ["critical", "high", "medium", "low"]}, "story_points": {"type": "integer"}, "status": {"type": "string", "enum": ["todo", "in_progress", "done"]}, "epic": {"type": "string"}, }, "required": ["task_title", "assignee", "priority"], } text = ( "Assign the Redis caching implementation to Priya for Sprint 14. " "It's high priority under the Performance epic, estimated 5 story points. " "Mark it as in progress since she already started." ) result = extract(schema, text) # → { # "task_title": "Redis caching implementation", # "assignee": "Priya", # "priority": "high", # "story_points": 5, # "status": "in_progress", # "epic": "Performance" # } ``` --- ### Example 2 — Nested support ticket (nested objects + arrays) ```python schema = { "type": "object", "properties": { "customer": { "type": "object", "properties": { "name": {"type": "string"}, "company": {"type": "string"}, "email": {"type": "string", "format": "email"}, }, "required": ["name", "company"], }, "issue": { "type": "object", "properties": { "summary": {"type": "string"}, "severity": {"type": "string", "enum": ["low", "medium", "high", "critical"]}, }, "required": ["summary", "severity"], }, "actions": { "type": "array", "items": { "type": "object", "properties": { "owner": {"type": "string"}, "task": {"type": "string"}, }, "required": ["owner", "task"], }, }, }, "required": ["customer", "issue"], } text = ( "Support note: customer Priya Shah from Velocity Corp, email priya@velocity.io. " "Dashboard charts won't load — severity high. " "Action: Sarah to open an engineering ticket. Marcus to send ETA to customer." ) result = extract(schema, text) # → { # "customer": {"name": "Priya Shah", "company": "Velocity Corp", "email": "priya@velocity.io"}, # "issue": {"summary": "Dashboard charts won't load", "severity": "high"}, # "actions": [ # {"owner": "Sarah", "task": "open an engineering ticket"}, # {"owner": "Marcus", "task": "send ETA to customer"} # ] # } ``` --- ### Example 3 — Compliance finding with date and enum fields ```python schema = { "type": "object", "properties": { "finding_id": {"type": "string"}, "standard": {"type": "string", "enum": ["ISO27001", "SOC2", "HIPAA", "GDPR", "PCI-DSS"]}, "clause": {"type": "string"}, "severity": {"type": "string", "enum": ["critical", "major", "minor", "observation"]}, "description": {"type": "string"}, "due_date": {"type": "string", "format": "date"}, "owner": {"type": "string"}, "status": {"type": "string", "enum": ["open", "in_remediation", "closed"]}, }, "required": ["standard", "severity", "description", "due_date"], } text = ( "Audit finding AF-2024-089: ISO27001 clause A.9.4.2 violation — " "privileged accounts are not protected with MFA. Severity: major. " "Remediation owner: Chen, due by 2024-09-30. Status: in_remediation." ) result = extract(schema, text) # → { # "finding_id": "AF-2024-089", # "standard": "ISO27001", # "clause": "A.9.4.2", # "severity": "major", # "description": "Privileged accounts are not protected with MFA", # "due_date": "2024-09-30", # "owner": "Chen", # "status": "in_remediation" # } ``` --- ### Example 4 — CPU inference (no GPU) ```python model = AutoModelForCausalLM.from_pretrained( "senthil090/schemalm-v2-lfm2-350m", torch_dtype=torch.float32, # fp32 for CPU ) model.eval() # Same extract() function as above — just slower (~5–15s per call on a modern CPU) ``` --- ## Limitations - Best on extraction tasks (reading text and pulling fields) — not a general-purpose chat model - Weaker on very long schemas (>50 fields) or schemas with complex `pattern`/`format` constraints - Sales numeric extraction and phone-call transcripts have lower accuracy (~50–60%) — targeted in v2.1 hardcase training - Not suitable for code generation, reasoning, or creative tasks ## Citation ``` @misc{schemalm-v2, title = {SchemaLM v2 — JSON Schema-Conditioned Information Extraction}, author = {Senthil}, year = {2025}, url = {https://huggingface.co/senthil090/schemalm-v2-lfm2-350m} } ```