Instructions to use litert-community/clef-flash-LiteRT with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/clef-flash-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
Download examples/run_example.py from litert-community/clef-flash-LiteRT: direct link, hf CLI and curl.
- Browser
- Download file 10.9 kB
-
https://huggingface.co/litert-community/clef-flash-LiteRT/resolve/main/examples/run_example.py
- Command line
-
hf download hf://litert-community/clef-flash-LiteRT/examples/run_example.py
-
curl -L -o run_example.py https://huggingface.co/litert-community/clef-flash-LiteRT/resolve/main/examples/run_example.py
10.9 kB
| """Answer a request of the SystemOne-compatible request shape with the clef-flash LiteRT graphs of this folder, or check | |
| this folder against the provider's float32 reference. | |
| Run from the repository root, in a Python with host/requirements-host.txt installed (examples/README.md): | |
| python examples/run_example.py --check # the GPU at float32 precision (Metal on a Mac) | |
| python examples/run_example.py --check --accelerator cpu # the CPU (XNNPACK, 8 threads) | |
| python examples/run_example.py --request examples/request.json --image fixtures/images/clock_3oclock_256x240.png --tile 256 | |
| python examples/run_example.py --request my_request.json [--image photo.jpg] [--accelerator cpu] | |
| A request is {"model": str, "state": text or any JSON value, "questions": {id: {"type": "noul" | "choice" | "score", | |
| "instructions": str, "criteria": ...}}}: choice criteria {option id: description}, score criteria a list of levels | |
| (lowest first), noul criteria optional {"true": ..., "false": ...}. --image adds one picture (or put a local path in | |
| "images": [...]), read at a square tile of 448 px (196 picture tokens, the default) or 256 px (64). The response body | |
| is printed as JSON on stdout. A request the host refuses prints `refused: <error>: <message>` on stderr: RequestTooLong | |
| (more than 4,096 tokens, the largest row graph), UnsupportedMedia (more than one picture, videos, media_kwargs, a | |
| picture that cannot be opened, a URL, a tile other than 256 / 448) and the provider's own checks (MissingModelOrState, | |
| NoQuestions, BadQuestionType, EmptyCriteria, SchemaTooLong). | |
| --check runs the four public fixture requests named in examples/run_example.expected.json (a SemIf record, a support | |
| ticket with noul / choice / score questions, a JSON order, and a drawn picture at the 256 px tile; the row graphs of | |
| lengths 256 and 512) and compares them with the provider's own code in float32 on the CPU: on every question whose two | |
| most likely options are more than 0.02 apart the most likely option is the same, every probability is within 0.02, the | |
| mean over the requests of each request's mean |difference| is at most 0.002 (the acceptance line of this conversion), | |
| and the input tokens, row graph length and answer fields are equal; then it sends the refusal requests of REFUSALS and | |
| compares each error's name (and message, where it names no path). It prints one line, PASS or FAIL. | |
| Exit codes: 0 answered / PASS, 1 check FAIL, 2 bad arguments, 3 refused request, 4 a file of the folder is missing.""" | |
| from __future__ import annotations | |
| import argparse | |
| import copy | |
| import json | |
| import sys | |
| import time | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| sys.path.insert(0, str(ROOT / "host")) | |
| import clef_litert as C # noqa: E402 | |
| EXPECTED = ROOT / "examples/run_example.expected.json" | |
| PICTURE = "fixtures/images/shapes_224.png" | |
| def _refusals() -> dict: | |
| """name -> (request, tile): one request for each refusal the host names (the --check part).""" | |
| base = {"model": "clef-flash", "state": "The kettle stopped heating after a week.", | |
| "questions": {"faulty": {"type": "noul", "instructions": "The product is faulty."}}} | |
| long_state = {"room": "cold-room-2", "unit": "celsius", | |
| "readings": [{"minute": i, "value": round(3.0 + (i % 9) * 0.1, 1)} for i in range(400)]} | |
| many = {f"option_{i:04d}": f"Description number {i} of a very long list of options" for i in range(1500)} | |
| def edit(**kw): | |
| r = copy.deepcopy(base) | |
| for k, v in kw.items(): | |
| if v is None: | |
| r.pop(k, None) | |
| else: | |
| r[k] = v | |
| return r | |
| pic = str(ROOT / PICTURE) | |
| return { | |
| "too_long": (edit(state=long_state), 448), | |
| "two_pictures": (edit(images=[pic, pic]), 448), | |
| "videos": (edit(videos=["clip.mp4"]), 448), | |
| "media_kwargs": (edit(media_kwargs={"max_pixels": 1000}), 448), | |
| "url_picture": (edit(images=["https://example.com/picture.png"]), 448), | |
| "unreadable_picture": (edit(images=[str(ROOT / "examples/request.json")]), 448), | |
| "tile_300": (edit(images=[pic]), 300), | |
| "no_model": (edit(model=None), 448), | |
| "no_questions": (edit(questions={}), 448), | |
| "bad_type": (edit(questions={"faulty": {"type": "boolean"}}), 448), | |
| "empty_criteria": (edit(questions={"team": {"type": "choice", "criteria": {}}}), 448), | |
| "schema_too_long": (edit(questions={"team": {"type": "choice", "criteria": many}}), 448), | |
| } | |
| def load_folder(accelerator: str, threads: int) -> C.ClefLiteRT: | |
| missing = [p for p in (C.FOLDER["tokenizer"], C.FOLDER["embed_tokens"], C.FOLDER["lm_head"], | |
| C.FOLDER["joint_head"], C.FOLDER["joint_head_config"]) if not (ROOT / p).is_file()] | |
| if missing: | |
| print(f"missing in {ROOT}: {', '.join(missing)}", file=sys.stderr) | |
| raise SystemExit(4) | |
| try: | |
| return C.ClefLiteRT.from_dir(ROOT, accelerator=accelerator, threads=threads) | |
| except ValueError as e: # not one row graph file in the folder | |
| print(f"{e} in {ROOT}", file=sys.stderr) | |
| raise SystemExit(4) | |
| def answer(args) -> int: | |
| request = json.loads(Path(args.request).read_text()) | |
| if args.image: | |
| request["images"] = list(request.get("images") or []) + [args.image] | |
| with load_folder(args.accelerator, args.threads) as clef: | |
| t = time.perf_counter() | |
| try: | |
| body = clef.decide(request, tile=args.tile) | |
| except C.RequestError as e: | |
| print(f"refused: {type(e).__name__}: {e}", file=sys.stderr) | |
| return 3 | |
| seconds = time.perf_counter() - t | |
| print(json.dumps(body, indent=1, ensure_ascii=False)) | |
| print(f"# {seconds:.1f} s on the {args.accelerator}, with the compile of the graphs this request needed", | |
| file=sys.stderr) | |
| return 0 | |
| def check(args) -> int: | |
| expected = json.loads(EXPECTED.read_text()) | |
| records = {r["id"]: r for r in json.loads((ROOT / "fixtures/requests_public.json").read_text())["records"]} | |
| problems, worst, means = [], (0.0, ""), [] | |
| with load_folder(args.accelerator, args.threads) as clef: | |
| kept = {} | |
| row_graph = clef.graphs.row_graph | |
| def keep_hidden(length, inputs): # the hidden rows decide() reads, kept for the unrounded check | |
| kept["hidden"] = row_graph(length, inputs) | |
| return kept["hidden"] | |
| clef.graphs.row_graph = keep_hidden | |
| for item in sorted(expected["requests"], key=lambda x: x["length"]): | |
| name = item["record"] | |
| request = copy.deepcopy(records[name]["request"]) | |
| if item.get("image"): | |
| request["images"] = [str(ROOT / item["image"])] | |
| body = clef.decide(request, tile=item["tile"]) | |
| enc = clef.host.encode(request, tile=item["tile"]) | |
| logits = clef.host.scores(enc, kept["hidden"]) | |
| if clef.host.respond(request, enc, logits) != body: | |
| problems.append(f"{name}: the response is not the one of its own probabilities") | |
| if (enc.record.tokens, enc.length) != (item["input_tokens"], item["length"]): | |
| problems.append(f"{name}: {enc.record.tokens} tokens on L{enc.length}, expected {item['input_tokens']} " | |
| f"on L{item['length']}") | |
| if body["usage"] != {"input_tokens": item["input_tokens"], "output_tokens": 0}: | |
| problems.append(f"{name}: usage {body['usage']}") | |
| diffs = [] | |
| for q, z in zip(enc.record.questions, logits): | |
| e = item["questions"][q.question_id] | |
| got = dict(zip(q.option_ids, (float(x) for x in C.question_probs(z)))) | |
| if list(got) != e["option_ids"]: | |
| problems.append(f"{name}/{q.question_id}: options {list(got)}") | |
| continue | |
| d = [abs(got[o] - r) for o, r in zip(e["option_ids"], e["probabilities"])] | |
| diffs += d | |
| if max(d) > worst[0]: | |
| worst = (max(d), f"{name}/{q.question_id}") | |
| top = max(got, key=got.__getitem__) | |
| if not e["near_tie"] and top != e["argmax"]: | |
| problems.append(f"{name}/{q.question_id}: most likely {top}, expected {e['argmax']}") | |
| if max(d) > expected["line"]["max_abs_dp"]: | |
| problems.append(f"{name}/{q.question_id}: |dp| {max(d):.2e}") | |
| a = body["answers"][q.question_id] | |
| if [a["type"], sorted(a)] != [e["type"], e["answer_fields"]]: | |
| problems.append(f"{name}/{q.question_id}: answer {a}") | |
| means.append(sum(diffs) / max(len(diffs), 1)) | |
| print(f"# {name}: {enc.record.tokens} tokens, L{enc.length}" + (f", {enc.tile} px tile" if enc.tile else "") | |
| + f", max |dp| {max(diffs):.2e}", file=sys.stderr) | |
| mean = sum(means) / len(means) | |
| if mean > expected["line"]["mean_of_request_means"]: | |
| problems.append(f"mean of the requests' mean |dp| {mean:.2e}") | |
| cases = _refusals() | |
| for name, want in expected["refusals"].items(): | |
| request, tile = cases[name] | |
| try: | |
| clef.decide(request, tile=tile) | |
| problems.append(f"refusal {name}: answered") | |
| except C.RequestError as e: | |
| if type(e).__name__ != want["error"] or (want["message"] is not None and str(e) != want["message"]): | |
| problems.append(f"refusal {name}: {type(e).__name__}: {e}") | |
| verdict = "PASS" if not problems else "FAIL" | |
| print(f"{verdict} ({args.accelerator}): {len(expected['requests'])} requests, max |dp| {worst[0]:.2e} ({worst[1]}), " | |
| f"mean of the requests' mean |dp| {mean:.2e}, {len(expected['refusals'])} refusals named" | |
| + ("" if not problems else "; " + "; ".join(problems))) | |
| return 0 if not problems else 1 | |
| def main() -> int: | |
| ap = argparse.ArgumentParser(description=__doc__.split("\n")[0]) | |
| ap.add_argument("--request", help="a request JSON file") | |
| ap.add_argument("--image", help="one picture for the request (a local file)") | |
| ap.add_argument("--tile", type=int, default=448, help="the picture's square tile: 448 (default) or 256") | |
| ap.add_argument("--accelerator", choices=["gpu", "cpu"], default="gpu", | |
| help="gpu = float32 precision (Metal on a Mac, the default), cpu = XNNPACK") | |
| ap.add_argument("--threads", type=int, default=8, help="CPU threads (default 8)") | |
| ap.add_argument("--check", action="store_true", help="compare with examples/run_example.expected.json") | |
| a = ap.parse_args() | |
| if a.check == bool(a.request): | |
| ap.error("give --request or --check") | |
| return check(a) if a.check else answer(a) | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |