Views
No views yet
| Variant | Size | Description |
|---|---|---|
| FP16 | ~692MB | All weights in FP16 |
| Q4 | ~276MB | INT4 embedding (GatherBlockQuantized), INT4 lm_head (MatMulNBits, shared), INT4 MatMul weights |
| Q4F32 | ~459MB | INT4 MatMul weights, FP32 embedding and norms |
| Q8 | ~604MB | INT8 MatMul weights, FP32 embedding and norms |
| Parameter | Value |
|---|---|
temperature | 0.1 |
top_k | 50 |
repetition_penalty | 1.05 |
onnx/
├── model.onnx # FP32
├── model_fp16.onnx # FP16
├── model_q4.onnx # Q4
├── model_q4f32.onnx # Q4F32
└── model_q8.onnx # Q81pip install onnxruntime transformers numpy huggingface_hub
2# or with GPU support:
3pip install onnxruntime-gpu transformers numpy huggingface_hub1import numpy as np
2import onnxruntime as ort
3from huggingface_hub import hf_hub_download
4from transformers import AutoTokenizer
5
6# Download model
7model_id = "LiquidAI/LFM2.5-350M-ONNX"
8model_path = hf_hub_download(model_id, "onnx/model_q4.onnx")
9data_path = hf_hub_download(model_id, "onnx/model_q4.onnx_data")
10
11# Load model and tokenizer
12session = ort.InferenceSession(model_path)
13tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
14
15# Sampling parameters
16TEMPERATURE = 0.1
17TOP_K = 50
18REPETITION_PENALTY = 1.05
19
20# Prepare chat input
21messages = [{"role": "user", "content": "What is the capital of France?"}]
22prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
23input_ids = np.array([tokenizer.encode(prompt, add_special_tokens=False)], dtype=np.int64)
24
25# Initialize KV cache
26ONNX_DTYPE = {"tensor(float)": np.float32, "tensor(float16)": np.float16, "tensor(int64)": np.int64}
27cache = {}
28for inp in session.get_inputs():
29 if inp.name in {"input_ids", "attention_mask", "position_ids"}:
30 continue
31 shape = [d if isinstance(d, int) else 1 for d in inp.shape]
32 for i, d in enumerate(inp.shape):
33 if isinstance(d, str) and "sequence" in d.lower():
34 shape[i] = 0
35 cache[inp.name] = np.zeros(shape, dtype=ONNX_DTYPE.get(inp.type, np.float32))
36
37# Check if model uses position_ids
38input_names = {inp.name for inp in session.get_inputs()}
39use_position_ids = "position_ids" in input_names
40
41
42def sample_token(logits, generated_tokens):
43 """Sample next token with temperature, top-k, and repetition penalty."""
44 # Apply repetition penalty
45 for token_id in set(generated_tokens):
46 if logits[token_id] > 0:
47 logits[token_id] /= REPETITION_PENALTY
48 else:
49 logits[token_id] *= REPETITION_PENALTY
50
51 # Apply temperature
52 logits = logits / TEMPERATURE
53
54 # Top-k filtering
55 top_k_indices = np.argpartition(logits, -TOP_K)[-TOP_K:]
56 top_k_logits = logits[top_k_indices]
57
58 # Softmax over top-k
59 top_k_logits -= np.max(top_k_logits)
60 probs = np.exp(top_k_logits) / np.sum(np.exp(top_k_logits))
61
62 # Sample
63 chosen = np.random.choice(len(top_k_indices), p=probs)
64 return int(top_k_indices[chosen])
65
66
67# Generate tokens
68seq_len = input_ids.shape[1]
69generated_tokens = []
70
71for step in range(512): # max tokens
72 if step == 0:
73 ids = input_ids
74 pos = np.arange(seq_len, dtype=np.int64).reshape(1, -1)
75 else:
76 ids = np.array([[generated_tokens[-1]]], dtype=np.int64)
77 pos = np.array([[seq_len + len(generated_tokens) - 1]], dtype=np.int64)
78
79 attn_mask = np.ones((1, seq_len + len(generated_tokens)), dtype=np.int64)
80 feed = {"input_ids": ids, "attention_mask": attn_mask, **cache}
81 if use_position_ids:
82 feed["position_ids"] = pos
83
84 outputs = session.run(None, feed)
85 logits = outputs[0][0, -1].copy()
86 next_token = sample_token(logits, generated_tokens)
87 generated_tokens.append(next_token)
88
89 # Update cache
90 for i, out in enumerate(session.get_outputs()[1:], 1):
91 name = out.name.replace("present_conv", "past_conv").replace("present.", "past_key_values.")
92 if name in cache:
93 cache[name] = outputs[i]
94
95 if next_token == tokenizer.eos_token_id:
96 break
97
98print(tokenizer.decode(generated_tokens, skip_special_tokens=True))npm install onnxruntime-web @huggingface/transformerschrome://flags/#enable-unsafe-webgpu, enable, and restartchrome://gpu for "WebGPU" statusnavigator.gpu.requestAdapter() in DevTools console1import * as ort from "onnxruntime-web/webgpu";
2import { AutoTokenizer } from "@huggingface/transformers";
3
4// Check WebGPU availability
5if (!navigator.gpu) {
6 throw new Error("WebGPU not available. Enable at chrome://flags/#enable-unsafe-webgpu");
7}
8const adapter = await navigator.gpu.requestAdapter();
9if (!adapter) {
10 throw new Error("WebGPU adapter not found. Check chrome://gpu for status.");
11}
12
13ort.env.wasm.numThreads = 1;
14
15const modelId = "LiquidAI/LFM2.5-350M-ONNX";
16const modelBase = `https://huggingface.co/${modelId}/resolve/main`;
17
18// Load tokenizer
19const tokenizer = await AutoTokenizer.from_pretrained(modelId);
20
21// Load ONNX session with external data
22const onnxPath = `${modelBase}/onnx/model_q4.onnx`;
23const dataPath = `${modelBase}/onnx/model_q4.onnx_data`;
24const session = await ort.InferenceSession.create(onnxPath, {
25 executionProviders: ["webgpu"],
26 externalData: [{ path: "model_q4.onnx_data", data: dataPath }],
27});
28
29// Sampling parameters
30const TEMPERATURE = 0.1;
31const TOP_K = 50;
32const REPETITION_PENALTY = 1.05;
33
34// Model config (from config.json)
35const hiddenSize = 1024;
36const numKVHeads = 8;
37const headDim = 64;
38
39// Initialize KV cache
40function initCache() {
41 const cache = {};
42 for (const name of session.inputNames) {
43 if (name.startsWith("past_conv")) {
44 cache[name] = new ort.Tensor("float32", new Float32Array(hiddenSize * 3), [1, hiddenSize, 3]);
45 } else if (name.startsWith("past_key_values")) {
46 cache[name] = new ort.Tensor("float32", new Float32Array(0), [1, numKVHeads, 0, headDim]);
47 }
48 }
49 return cache;
50}
51
52// Update cache from outputs
53function updateCache(cache, outputs) {
54 for (const [name, tensor] of Object.entries(outputs)) {
55 if (name.startsWith("present_conv")) {
56 cache[name.replace("present_conv", "past_conv")] = tensor;
57 } else if (name.startsWith("present.")) {
58 cache[name.replace("present.", "past_key_values.")] = tensor;
59 }
60 }
61}
62
63// Sample next token with temperature, top-k, and repetition penalty
64function sampleToken(logitsData, vocabSize, generatedTokens) {
65 const logits = new Float32Array(logitsData);
66
67 // Apply repetition penalty
68 const seen = new Set(generatedTokens);
69 for (const tokenId of seen) {
70 if (logits[tokenId] > 0) {
71 logits[tokenId] /= REPETITION_PENALTY;
72 } else {
73 logits[tokenId] *= REPETITION_PENALTY;
74 }
75 }
76
77 // Apply temperature
78 for (let i = 0; i < vocabSize; i++) {
79 logits[i] /= TEMPERATURE;
80 }
81
82 // Top-k: find top K indices
83 const indexed = Array.from(logits.slice(0, vocabSize), (v, i) => [v, i]);
84 indexed.sort((a, b) => b[0] - a[0]);
85 const topK = indexed.slice(0, TOP_K);
86
87 // Softmax over top-k
88 const maxLogit = topK[0][0];
89 const exps = topK.map(([v, i]) => [Math.exp(v - maxLogit), i]);
90 const sumExp = exps.reduce((s, [e]) => s + e, 0);
91 const probs = exps.map(([e, i]) => [e / sumExp, i]);
92
93 // Sample from distribution
94 let r = Math.random();
95 for (const [p, i] of probs) {
96 r -= p;
97 if (r <= 0) return i;
98 }
99 return probs[probs.length - 1][1];
100}
101
102// Build prompt and tokenize
103const messages = [{ role: "user", content: "What is the capital of France?" }];
104const prompt = tokenizer.apply_chat_template(messages, { add_generation_prompt: true, tokenize: false });
105const inputIds = tokenizer.encode(prompt);
106
107// Generation loop
108const cache = initCache();
109const eosTokenId = tokenizer.eos_token_id;
110const generatedTokens = [];
111let curLen = inputIds.length;
112let ids = inputIds;
113
114for (let step = 0; step < 512; step++) {
115 const inputIdsTensor = new ort.Tensor("int64", new BigInt64Array(ids.map(BigInt)), [1, ids.length]);
116 const attentionMask = new ort.Tensor("int64", new BigInt64Array(curLen).fill(1n), [1, curLen]);
117
118 const outputs = await session.run({ input_ids: inputIdsTensor, attention_mask: attentionMask, ...cache });
119
120 const logits = outputs.logits;
121 const vocabSize = logits.dims[2];
122 const lastLogits = logits.data.slice((logits.dims[1] - 1) * vocabSize, logits.dims[1] * vocabSize);
123 const nextToken = sampleToken(lastLogits, vocabSize, generatedTokens);
124
125 generatedTokens.push(nextToken);
126 if (nextToken === eosTokenId) break;
127
128 updateCache(cache, outputs);
129 ids = [nextToken];
130 curLen++;
131}
132
133console.log(tokenizer.decode(generatedTokens, { skip_special_tokens: true }));.onnx_data) that are loaded automaticallyBigInt64Array