"""HTML rendering for the inference demo UI.
Styling follows the Liquid AI design system from liquid-lfm-cloud:
- Monochrome primary scale (#171717 primary, #f5f5f5 background)
- Semantic accents: emerald (#10B981), amber (#F59E0B), red (#EF4444), blue (#3B82F6)
- JetBrains Mono for technical/metric elements, system sans-serif for body
- 16px rounded cards with subtle shadows
- Pill-shaped buttons and badges
"""
from __future__ import annotations
from typing import Callable
import numpy as np
from src.data.generator import AMOUNT_RANGE_LABELS
from src.data.schema import VALUES_START
from src.demo.decode import TransactionDecoder
from src.demo.merchant_catalog import DemoMerchantCatalog, MCC_NAMES
# Liquid design tokens — light mode (liquid-lfm-cloud design system)
_BG = "#f5f5f5"
_BG_CARD = "#ffffff"
_BG_CARD_ALT = "#fafafa"
_BORDER = "rgba(0,0,0,0.1)"
_BORDER_SUBTLE = "rgba(0,0,0,0.05)"
_TEXT = "#171717"
_TEXT_MUTED = "#525252"
_TEXT_DIM = "#737373"
_ACCENT_BLUE = "#3B82F6"
_ACCENT_GREEN = "#10B981"
_ACCENT_AMBER = "#F59E0B"
_ACCENT_RED = "#EF4444"
_RADIUS_CARD = "16px"
_RADIUS_SM = "8px"
_FONT_MONO = "JetBrains Mono, ui-monospace, SFMono-Regular, monospace"
_FONT_SANS = "-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif"
def format_fraud_score(prob: float) -> str:
"""Format fraud probability as colored gauge bar."""
pct = prob * 100
if pct < 20:
color = _ACCENT_GREEN
risk = "LOW RISK"
elif pct < 60:
color = _ACCENT_AMBER
risk = "MEDIUM RISK"
else:
color = _ACCENT_RED
risk = "HIGH RISK"
bar_width = max(2, min(100, int(pct)))
return f"""
LFM2.5 for Payment Sequences
The published LFM2.5 architecture adapted for structured transaction data.
Same hybrid conv-attention backbone. New per-feature embedding layer.
Production Target
| Parameters |
1.2B |
| Hidden dim |
2048 |
| Layers |
10 conv + 6 attn |
| Attention |
32Q / 8KV (GQA) |
| MLP |
SwiGLU 12288 |
| Sequence |
128 tx × 30 feat = 3,840 |
| Latency target |
< 50ms (H100) |
This Demo (Reference)
| Parameters |
9.8M |
| Hidden dim |
256 |
| Layers |
5 conv + 3 attn |
| Attention |
4Q / 2KV (GQA) |
| MLP |
SwiGLU 1024 |
| Sequence |
64 tx × 15 feat = 960 |
| Measured latency |
< 80ms (CPU) |
LFM2.5-1.2B Layer Pattern (16 layers)
{layer_cells}
■ Conv (10): local patterns, k=3, O(n)
■ Attention (6): global context, GQA, O(n²)
First and last layers are convolutional. Attention is densest mid-stack.
The LM head reads from a local-conv output, but 6 attention layers have already
encoded global context upstream.
Per-Feature Embedding
Text LFM2 has one embedding table. Payment LFM2 has one table per feature
(hour, merchant, MCC, amount, ...) plus a feature-type table. Summed to produce
the same (B, T, D) the backbone expects.
value_tables[f](token) + type_table(f)
KV-Cache Advantage
Only 6 of 16 layers need KV cache (attention layers only). A pure-attention
model at the same depth needs 16 layers of cache. At 3,840 token sequences
with 1,024 concurrent requests:
LFM2: ~25 GB
vs
Pure attn: ~64 GB
Weight-Tied Heads
Downstream heads that predict pretrained features (next merchant, MCC)
project through the backbone's own embedding table. Zero extra parameters,
+50% accuracy vs fresh MLP heads.
adapter(h) @ embedding.weight.T
How This Translates to Your Implementation
Schema
Your features, your vocab sizes, your ordering. We review the schema design.
Pretrain
Self-supervised on your unlabeled transactions. No fraud labels needed.
Fine-tune
Attach task heads (fraud, disputes, auth optimization). Multi-task with shared backbone.
Deploy
Your infra, your GPUs, your compliance. Sub-100ms for real-time authorization decisioning.
Own
No data leaves your infrastructure. No external API dependency. You own the model.
"""
def render_comparison_header() -> str:
"""Header explaining the pretrained vs random-init comparison."""
return f"""
Why LFM2.5 for Transaction Sequences
Three claims, each backed by a different kind of evidence. Serving cost is arithmetic.
Label efficiency is measured. Architectural fit is a first-principles argument.
1. Serving Cost Scales Better Than Pure Attention
10 of 16 layers use O(n) conv instead of O(n²) attention. The gap is structural
and compounds as sequence length grows. Measured at matched parameter count on the same
hardware:
{_table_header(["Sequence", "Tokens", "Hybrid", "Pure Attn", "Speedup"])}
{_table_row(["64 tx × 15 feat", "960", "5.96 ms", "9.01 ms", "1.5x"])}
{_table_row(["64 tx × 30 feat", "1,920", "13.05 ms", "23.84 ms", "1.8x"])}
{_table_row(["128 tx × 30 feat", "3,840", "35.65 ms", "75.95 ms",
"2.1x"], bold_last=False)}
{_table_row(["256 tx × 30 feat", "7,680", "119 ms", "283 ms",
"2.4x"], bold_last=False)}
At 3,840 tokens (production target), the FLOP analysis predicts 7.7% fewer operations.
The actual speedup is larger because conv layers achieve better hardware utilization.
At 7,680 tokens, savings reach 17% in FLOPs and 2.4x in wall-clock.
2. Pretraining Gets to 98% of Full-Data Quality with 10% of Labels
Self-supervised pretraining on unlabeled transactions. No fraud labels needed.
Then fine-tune with whatever labels you have. The pretrained model at 10% labels
beats the random-init baseline at 100% labels.
{_table_header(["Labels", "Sequences", "Pretrained PR-AUC", "Baseline PR-AUC", "Delta"])}
{_table_row(["1%", "1,700", "0.539", "0.046", "+0.493"])}
{_table_row(["10%", "17,000", "0.948", "0.690", "+0.258"])}
{_table_row(["100%", "170,000", "0.964", "0.922", "+0.041"])}
At 1% labels the baseline has learned nothing (0.046 is random guessing).
The pretrained model is already useful. This is the defining advantage for
institutions with billions of unlabeled transactions and limited fraud labels.
5x Convergence Speed
The pretrained model hit 0.959 PR-AUC at step 1,000. The random-init baseline
never reached that level in 5,000 steps (peaked at 0.922).
For quarterly model refreshes, this cuts GPU-hours per cycle by 80%.
For weekly refreshes, it is the difference between feasible and infeasible.
One Backbone, Many Tasks
A single forward pass serves fraud detection, next-merchant prediction, amount
forecasting, and merchant category classification. Add dispute prediction, default
risk, or authorization optimization as new heads without retraining the backbone.
Tied-embedding heads: +50% merchant accuracy at zero parameter cost
3. The Architecture Matches Transaction Data Structure
Transaction data is not like text. Information density is concentrated locally
(within-transaction feature correlations, adjacent-transaction continuity) with sparse
global signal (behavioral baselines across the full history). LFM2.5 allocates
O(n) conv to the dense local patterns and O(n²) attention to the sparse
global patterns. A pure transformer allocates O(n²) compute uniformly
across all distances.
Within Transaction
Merchant determines MCC. Entry mode correlates with amount. Dense, local,
often deterministic. A 3-wide conv kernel captures this.
Adjacent Transactions
Strong temporal continuity. A customer at Starbucks is likely at a similar
merchant next. The conditional distribution of t+1 given t is heavily peaked.
Distant Transactions
Weak but non-zero signal. Behavioral profile matters for fraud baseline,
but per-position information density is thin. This is where attention earns its cost.
Your Data, Your Model, Your Infrastructure
Liquid licenses the architecture and training recipe. You train on your proprietary
data behind your firewall. No data leaves your infrastructure. No dependency on
external model APIs. The result is a foundation model you own, optimized for your
specific transaction patterns, deployed on your hardware.
What We Claim vs What We Don't
We claim
- Fewer FLOPs per forward pass above ~1,500 tokens (arithmetic)
- Cost gap widens with sequence length (structural, measured 2.1-2.4x)
- Pretraining dramatically improves low-label performance (measured)
- Full pipeline works end-to-end on LFM2.5 (built it)
We don't claim
- Quality advantage over pure transformers at matched scale
- Absolute latency numbers extrapolated from 10M to 1.2B
- Superiority on all tasks (the advantage is specific to structured sequences)
- Real-data validation (all results are on synthetic data)
Source:
arXiv 2511.23404 ·
Reference implementation measured at 9.85M params, Apple Silicon
"""
def render_integration_guide() -> str:
"""Render high-abstraction integration architecture flow.
Distills docs/integration-guide.md into a visual pipeline overview.
Monochrome design -- no rainbow pills or per-card color coding.
"""
def _phase_card(num: str, title: str, body: str, detail: str) -> str:
return f"""
Integration Architecture
Seven phases from raw transaction data to production fraud scoring.
Each phase has a clear input, output, and set of decisions.
Schema
→
Tokenize
→
Embed
→
Backbone
→
Pretrain
→
Heads
→
Deploy
{_phase_card("1", "Schema Design",
"Define your features, vocab sizes, and feature ordering. This is the contract "
"between your data team and your ML team. Three feature types: categorical "
"(direct index), ordinal (hour, day-of-week), and bucketed-continuous (amount "
"into quantile bins). Spend two weeks here.",
"3 reserved tokens per feature (MASK, OOV, NULL) | "
"Order features by semantic family for the conv window | "
"Embed schema fingerprint in checkpoint metadata")}
{_phase_card("2", "Tokenization",
"Convert raw transaction fields into integer token IDs. Categorical features "
"map directly to vocab indices. Continuous values (amount, days-since-last) get "
"quantile-bucketed into N bins. High-cardinality features (merchant_id) need the "
"long tail bucketed or factored into orthogonal features.",
"amount → 16-256 quantile bins | "
"merchant_id: top 10K distinct, rest into ~1K frequency buckets | "
"Unseen values at inference → OOV token (ID 1)")}
{_phase_card("3", "Structured Embedding",
"One embedding table per feature (sized to its vocab) plus a feature-type table. "
"Summed to produce the (B, T*F, D) tensor the backbone expects. "
"No raw continuous features -- everything goes through an embedding table.",
"value_tables[f](token) + type_table(f) | "
"High-cardinality features dominate param budget -- "
"bucket the merchant long tail")}
{_phase_card("4", "Backbone Config",
"Start from a published LFM2 scale point (350M, 700M, 1.2B, 2.6B). "
"Keep the conv-to-attention ratio, GQA config, SwiGLU MLP, and RoPE theta. "
"Do not deviate without a specific reason.",
"10:6 conv:attn at 1.2B | 32Q/8KV GQA | "
"QK-RMSNorm before RoPE | theta=1M | "
"First and last layers are conv")}
{_phase_card("5", "Pretraining",
"Self-supervised on your unlabeled transactions. No fraud labels needed. "
"Causal next-feature prediction or masked-transaction prediction. "
"Average per-feature losses (do NOT sum).",
"AdamW lr=3e-4, betas=(0.9, 0.95), wd=0.1 | "
"Cosine decay to 10% | BF16 (loss in FP32) | "
"Chinchilla: ~20 tokens per parameter")}
{_phase_card("6", "Downstream Heads",
"Attach task-specific heads. The critical decision: "
"TiedEmbeddingHead for features that were in pretraining vocab "
"(next_merchant, MCC). Fresh MLP for everything else (fraud, disputes).",
"Tied head: adapter(h) @ embedding.weight.T (+50% accuracy) | "
"Pool: last_tx_mean for sequence tasks, pre_last_tx for next-tx | "
"Dual LR: backbone 5e-5, heads 1e-3")}
{_phase_card("7", "Deployment",
"KV cache only on 6 attention layers (not 16). Dynamic batching with "
"5-10ms collection window. Conv-dominant models quantize cleanly to INT8. "
"Same model runs on GPU or CPU.",
"LFM2 @ 3,840 tokens: ~25 GB KV at 1K concurrent | "
"Pure attn: ~64 GB | "
"Sub-100ms on H100 for real-time auth decisioning")}
Top Gotchas
{_gotcha("1", "Per-feature loss summing",
"high-cardinality features dominate. Average, don't sum.")}
{_gotcha("2", "Fresh MLP for pretrained features",
"next_merchant stays at random. Use TiedEmbeddingHead.")}
{_gotcha("3", "Schema-checkpoint drift",
"training on schema v3, deploying on v2. Embed fingerprint in metadata.")}
{_gotcha("4", "Frozen backbone",
"PR-AUC drops from 0.96 to 0.16. Plan to fine-tune.")}
{_gotcha("5", "Pool strategy leak",
"last_tx_mean for next-tx prediction leaks the target. Use pre_last_tx.")}
Typical Engagement
| Phase |
Duration |
What Happens |
| Discovery |
2-4 weeks |
Schema definition, data sample (~1M sequences), compliance review, architectural fit assessment |
| POC |
2 weeks |
Pretrain + fine-tune on your data sample, measurement report, go/no-go recommendation |
| Production |
3-6 months |
Engineering team builds, Liquid provides architectural support, weekly design review |
| Scale |
Ongoing |
Operations, monitoring, retraining cadence, architecture evolution |
"""