Instructions to use litert-community/d1-2B-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/d1-2B-LiteRT with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 7,948 Bytes
df44977 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | """Export the batch decide graph (d1_graph_b.D1DecideB, B sequences of the L128 bucket in one call) with
litert-torch, cast its FULLY_CONNECTED weights to float16 (export_decide.fp16fc), check the float32 file on the CPU
against the module and four of its rows against the batch-1 D1Decide (the module form's own identity), scan both
files, dump the operand ranks (rank_dump: runtime rank 3 + constant rank 4 pairs = 0 wanted), list the largest runtime
buffers (DEQUANTIZE outputs excluded: the GPU takes the float16 constants as weights; Pixel 11 Pro caps one buffer at
1 GiB).
PYTHONHASHSEED=0 $EXPORT conversion/export_batch.py --B 8 --causal-runtime [--L 128] [--keep-fp32]
--causal-runtime = the sliding layers' causal mask as the batch-1 graph's runtime rank-4 tensor (constant x the row's
first key flag): the shipped form; without it the constant [1, 1, L, L] is added to the rank-4 scores.
Writes out/graphs/d1-2b_decide_b<B>_L<L>_{fp32,fp16fc}.tflite (the float32 file deleted after the fp16 one unless
--keep-fp32) and results/export_batch_b<B>_L<L>.json. Never overwrites.
"""
from __future__ import annotations
import argparse
import contextlib
import hashlib
import importlib.metadata
import io
import json
import os
import resource
import sys
import time
HERE = os.path.dirname(os.path.abspath(__file__))
WORK = os.path.normpath(os.path.join(HERE, ".."))
sys.path.insert(0, HERE)
sys.path.insert(0, HERE)
SNAP = os.path.join(WORK, "snapshot")
def sha256_file(p):
h = hashlib.sha256()
with open(p, "rb") as f:
while b := f.read(1 << 24):
h.update(b)
return h.hexdigest()
def sample_rows(B, L, hidden, seed=0):
"""B rows of different lengths (one full-length row, the rest 43..L), state halves, 1-4 questions; embeds of the
export sample = small random values (as the batch-1 export's sample)."""
import numpy as np
rng = np.random.default_rng(seed)
rows = []
for j in range(B):
T = L if j == 0 else int(rng.integers(43, L + 1))
st = int(rng.integers(5, T // 2))
nq = int(rng.integers(1, 5))
tags = [-1] * st + [1 + (i * nq) // (T - st) for i in range(T - st)]
rows.append((T, st, tags, (rng.standard_normal((T, hidden)) * 0.02).astype(np.float32)))
return rows
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--B", type=int, required=True)
ap.add_argument("--L", type=int, default=128)
ap.add_argument("--keep-fp32", action="store_true")
ap.add_argument("--causal-runtime", action="store_true")
a = ap.parse_args()
import numpy as np
import torch
import litert_torch
import d1_graph as G
import d1_graph_b as GB
import rank_dump
from d1_layout_b import make_sees_batch
from export_decide import fp16fc
from tflite_scan_d1 import scan
assert os.environ.get("PYTHONHASHSEED") == "0"
B, L = a.B, a.L
sig = f"decide_b{B}_L{L}"
gdir = os.path.join(WORK, "out/graphs")
os.makedirs(gdir, exist_ok=True)
p32 = os.path.join(gdir, f"d1-2b_decide_b{B}_L{L}_fp32.tflite")
p16 = os.path.join(gdir, f"d1-2b_decide_b{B}_L{L}_fp16fc.tflite")
rec_path = os.path.join(WORK, f"results/export_batch_b{B}_L{L}.json")
for p in (p32, p16, rec_path):
assert not os.path.exists(p), f"never overwrite {p}"
torch.set_num_threads(8)
t0 = time.time()
cfg = G.Cfg(SNAP)
W = G.load_text_weights(SNAP, dtype=torch.float32)
W.pop("embed_tokens.weight", None)
model = GB.build(B, L, W, cfg, causal_runtime=a.causal_runtime)
rows = sample_rows(B, L, cfg.hidden)
emb = np.zeros((B, L, cfg.hidden), np.float32)
for b, (T, st, tags, e) in enumerate(rows):
emb[b, :T] = e
q, k = make_sees_batch([(st, tags) for T, st, tags, e in rows], B, L)
sample = {"embeds": torch.from_numpy(emb), "sees_q": torch.from_numpy(q), "sees_k": torch.from_numpy(k)}
with torch.inference_mode():
ref = model(**sample)["hidden"].numpy()
single = G.D1Decide(W, cfg, L).eval().requires_grad_(False)
rows_vs_single = []
for b in (0, 1, B // 2, B - 1):
T, st, tags, e = rows[b]
q1, k1 = G.make_sees(st, tags, L)
e1 = torch.zeros(1, L, cfg.hidden)
e1[0, :T] = torch.from_numpy(e)
h1 = single(embeds=e1, sees_q=torch.from_numpy(q1), sees_k=torch.from_numpy(k1))["hidden"][0, :T].numpy()
rows_vs_single.append({"row": b, "T": T, "max_abs": float(np.abs(ref[b, :T] - h1).max())})
del single
rec = {"B": B, "L": L, "signature": sig, "graph": "conversion/d1_graph_b.D1DecideB", "causal_runtime": a.causal_runtime,
"graph_module_sha256": sha256_file(os.path.join(HERE, "d1_graph_b.py")),
"inputs": {n: list(v.shape) for n, v in sample.items()}, "rows_T": [r[0] for r in rows],
"torch_rows_vs_single_module": rows_vs_single, "pythonhashseed": os.environ.get("PYTHONHASHSEED"),
"versions": {p: importlib.metadata.version(p) for p in
("torch", "litert-torch", "litert-converter", "ai-edge-litert", "ai-edge-quantizer", "numpy")},
"load_build_s": round(time.time() - t0, 1)}
t1 = time.time()
lrt = litert_torch.signature(sig, model, sample_kwargs=sample).convert()
rec["convert_s"] = round(time.time() - t1, 1)
t2 = time.time()
lrt.export(p32)
rec["write_s"] = round(time.time() - t2, 1)
del lrt
rec["fp32"] = {"file": os.path.relpath(p32, WORK), "bytes": os.path.getsize(p32), "sha256": sha256_file(p32)}
from ai_edge_litert.interpreter import Interpreter
t3 = time.time()
it = Interpreter(model_path=p32, num_threads=8)
got = it.get_signature_runner(sig)(**{n: v.numpy() for n, v in sample.items()})["hidden"]
rec["fp32_cpu_vs_module_real_max_abs"] = max(float(np.abs(got[b, :T] - ref[b, :T]).max())
for b, (T, *_ ) in enumerate(rows))
rec["fp32_cpu_s"] = round(time.time() - t3, 1)
del it
t4 = time.time()
rec["recipe"] = fp16fc(p32, p16)
rec["quant_s"] = round(time.time() - t4, 1)
rec["fp16fc"] = {"file": os.path.relpath(p16, WORK), "bytes": os.path.getsize(p16), "sha256": sha256_file(p16)}
s32, s16 = scan(p32, with_sha=False), scan(p16, with_sha=False)
keys = ("operator_count", "op_histogram", "custom_ops", "rank_gt4_tensor_count", "int64_tensor_count",
"broadcast_to_count", "fc_weight_dtypes")
rec["scan_fp32"] = {k_: s32[k_] for k_ in keys}
rec["scan_fp16fc"] = {k_: s16[k_] for k_ in keys}
seen, top = set(), []
for t in s16["largest_activations"]:
if tuple(t["shape"]) in seen:
continue
seen.add(tuple(t["shape"]))
top.append({"shape": t["shape"], "MiB": round(t["bytes"] / 2 ** 20, 1), "name": t["name"][:90]})
if len(top) == 5:
break
rec["largest_runtime_buffers"] = top
rec["largest_runtime_buffer_under_1GiB"] = all(t["MiB"] < 1024 for t in top)
sys.argv = ["rank_dump.py", p16]
buf = io.StringIO()
with contextlib.redirect_stdout(buf):
pats = rank_dump.main()
rec["rank_dump_fp16fc"] = buf.getvalue().splitlines()
rec["risk_pairs"] = sum(p["count"] for p in pats if p["risk"].startswith("RISK"))
if not a.keep_fp32:
os.remove(p32)
rec["fp32"]["deleted"] = True
rec["peak_rss_bytes"] = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
rec["wall_s"] = round(time.time() - t0, 1)
json.dump(rec, open(rec_path, "w"), indent=1)
print(json.dumps({k_: rec[k_] for k_ in ("signature", "fp32", "fp16fc", "fp32_cpu_vs_module_real_max_abs",
"torch_rows_vs_single_module", "largest_runtime_buffers", "risk_pairs",
"wall_s")}))
print("peak_rss_gb", round(rec["peak_rss_bytes"] / 2 ** 30, 1))
if __name__ == "__main__":
main()
|