Image-Text-to-Text
Transformers
Safetensors
GGUF
qwen3_5
system-one
decision-making
classification
calibration
structured-output
on-device
multimodal
Instructions to use bynn-intelligence-com/decisionnode-edge with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use bynn-intelligence-com/decisionnode-edge with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="bynn-intelligence-com/decisionnode-edge")# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("bynn-intelligence-com/decisionnode-edge") model = AutoModelForMultimodalLM.from_pretrained("bynn-intelligence-com/decisionnode-edge", device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use bynn-intelligence-com/decisionnode-edge with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf bynn-intelligence-com/decisionnode-edge:Q8_0 # Run inference directly in the terminal: llama cli -hf bynn-intelligence-com/decisionnode-edge:Q8_0
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf bynn-intelligence-com/decisionnode-edge:Q8_0 # Run inference directly in the terminal: llama cli -hf bynn-intelligence-com/decisionnode-edge:Q8_0
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf bynn-intelligence-com/decisionnode-edge:Q8_0 # Run inference directly in the terminal: ./llama-cli -hf bynn-intelligence-com/decisionnode-edge:Q8_0
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf bynn-intelligence-com/decisionnode-edge:Q8_0 # Run inference directly in the terminal: ./build/bin/llama-cli -hf bynn-intelligence-com/decisionnode-edge:Q8_0
Use Docker
docker model run hf.co/bynn-intelligence-com/decisionnode-edge:Q8_0
- Llama new
- LM Studio
- Jan
- vLLM
How to use bynn-intelligence-com/decisionnode-edge with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "bynn-intelligence-com/decisionnode-edge" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bynn-intelligence-com/decisionnode-edge", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/bynn-intelligence-com/decisionnode-edge:Q8_0
- SGLang
How to use bynn-intelligence-com/decisionnode-edge with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "bynn-intelligence-com/decisionnode-edge" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bynn-intelligence-com/decisionnode-edge", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "bynn-intelligence-com/decisionnode-edge" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "bynn-intelligence-com/decisionnode-edge", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Ollama
How to use bynn-intelligence-com/decisionnode-edge with Ollama:
ollama run hf.co/bynn-intelligence-com/decisionnode-edge:Q8_0
- Unsloth Desktop
- Docker Model Runner
How to use bynn-intelligence-com/decisionnode-edge with Docker Model Runner:
docker model run hf.co/bynn-intelligence-com/decisionnode-edge:Q8_0
- Lemonade
How to use bynn-intelligence-com/decisionnode-edge with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull bynn-intelligence-com/decisionnode-edge:Q8_0
Run and chat with the model
lemonade run user.decisionnode-edge-Q8_0
List all available models
lemonade list
- Atomic Chat
File size: 9,169 Bytes
071512e | 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 | """Build the files a faster backend loads, from a model directory (only read) into a new directory.
python -m decisionnode_edge.build openvino path/to/model --out path/to/model-openvino [--lengths 512,2048]
python -m decisionnode_edge.build gguf path/to/model --out path/to/model-gguf --llama-cpp path/to/llama.cpp
openvino The backbone's text path (the token embedding, the layers, the final norm: input_ids [1, L] to the hidden
states [1, L, hidden]) exported with torch.onnx's dynamo exporter in float32 at each static length, then
saved as OpenVINO IR with float32 weights (the bf16 weights, exactly); the runtime runs it in bf16. One IR per
length, since the export unrolls the delta rule over the length: each takes 15 to 20 minutes, and lengths
above a few thousand tokens take hours. Then each IR is run once against torch. Needs the `openvino` extra
(openvino, onnx, onnxscript); `--device cuda` (the default when a GPU is present) keeps the weights on the card.
gguf llama.cpp's converter (convert_hf_to_gguf.py --no-mtp) on links to the backbone files, Q8_0 by default: 8-bit
keeps the answers, 4-bit does not. Needs a llama.cpp checkout and its converter's Python requirements, in the
environment of `--python` (default: this one).
Both write decisionnode_edge_build.json (the backend, the files, the model's fingerprint, versions, times), which
EdgeModel.load reads from `artifacts`.
"""
from __future__ import annotations
import argparse
import importlib.metadata
import json
import os
import shutil
import subprocess
import sys
import time
from .backends import BUILD_FILE, BUILD_FORMAT, fingerprint, link_model_files
DEFAULT_LENGTHS = (512, 2048)
def versions(*names: str) -> dict:
out = {}
for name in names:
try:
out[name] = importlib.metadata.version(name)
except importlib.metadata.PackageNotFoundError:
out[name] = None
return out
def new_directory(out: str) -> None:
if os.path.exists(out):
raise SystemExit(f"{out} exists: the build writes a new directory")
os.makedirs(out)
def write_record(out: str, record: dict) -> None:
with open(os.path.join(out, BUILD_FILE), "w", encoding="utf-8") as f:
json.dump(record, f, indent=2)
f.write("\n")
def model_name(model: str) -> str:
with open(os.path.join(model, "decisionnode_edge.json"), encoding="utf-8") as f:
return json.load(f)["name"]
def build_openvino(model: str, out: str, lengths: list[int], device: str | None) -> dict:
import numpy as np
import openvino as ov
import torch
from transformers import AutoModelForImageTextToText, AutoTokenizer
device = device or ("cuda" if torch.cuda.is_available() else "cpu")
record = {"format": BUILD_FORMAT, "backend": "openvino", "model": model_name(model), "model_fingerprint": fingerprint(model), "files": {},
"weights": "float32 (the bf16 weights, exactly); run in bf16", "export_device": device,
"versions": versions("torch", "transformers", "onnx", "onnxscript", "openvino"), "seconds": {}, "check": {}} # fmt: skip
tokenizer = AutoTokenizer.from_pretrained(model)
record["pad_token_id"] = tokenizer.pad_token_id if tokenizer.pad_token_id is not None else 0
class LastHidden(torch.nn.Module):
def __init__(self, text):
super().__init__()
self.text = text
def forward(self, input_ids):
return self.text(input_ids=input_ids, use_cache=False).last_hidden_state
full = AutoModelForImageTextToText.from_pretrained(model, dtype=torch.float32).to(device).eval()
text = LastHidden(full.model.language_model).eval()
generator = torch.Generator().manual_seed(0)
for length in lengths:
work = os.path.join(out, f"onnx-{length}")
os.makedirs(work)
onnx_file = os.path.join(work, "edge.onnx")
ids = torch.randint(10, 200000, (1, length), generator=generator).to(device)
t0 = time.perf_counter()
with torch.inference_mode():
torch.onnx.export(text, (ids,), onnx_file, dynamo=True, external_data=True, input_names=["input_ids"], output_names=["last_hidden_state"], optimize=True)
t1 = time.perf_counter()
ir = ov.convert_model(onnx_file)
name = f"openvino-{length}.xml"
ov.save_model(ir, os.path.join(out, name), compress_to_fp16=False)
del ir
shutil.rmtree(work)
record["files"][str(length)] = name
record["seconds"][str(length)] = {"export": round(t1 - t0, 1), "convert": round(time.perf_counter() - t1, 1)}
print(json.dumps({"length": length, **record["seconds"][str(length)]}), flush=True)
# each IR against torch (float32) on a prompt shorter than its length, so the padding is read past as at run time
core = ov.Core()
for length in lengths:
n = length - 37
ids = torch.randint(10, 200000, (1, n), generator=generator)
with torch.inference_mode():
want = text(ids.to(device))[0, -1].float().cpu()
compiled = core.compile_model(os.path.join(out, record["files"][str(length)]), "CPU", {"INFERENCE_PRECISION_HINT": "bf16"})
x = np.full((1, length), record["pad_token_id"], dtype=np.int64)
x[0, :n] = ids[0].numpy()
got = torch.from_numpy(np.asarray(compiled.create_infer_request().infer({0: x})[compiled.output(0)][0, n - 1], dtype=np.float32))
cosine = float(torch.nn.functional.cosine_similarity(got, want, dim=0))
record["check"][str(length)] = {"tokens": n, "cosine_to_torch_float32": round(cosine, 6), "largest_difference": round(float((got - want).abs().max()), 4)}
print(json.dumps({"check": length, **record["check"][str(length)]}), flush=True)
del compiled
if not torch.isfinite(got).all() or cosine < 0.99:
raise SystemExit(f"the IR at {length} tokens does not reproduce the backbone (cosine {cosine:.4f}): {out} is incomplete")
return record
def build_gguf(model: str, out: str, llama_cpp: str, outtype: str, python: str) -> dict:
converter = os.path.join(llama_cpp, "convert_hf_to_gguf.py")
if not os.path.isfile(converter):
raise SystemExit(f"{converter} not found: --llama-cpp is the llama.cpp checkout")
source = os.path.join(out, "source") # the converter reads links to the backbone files, never the readout
os.makedirs(source)
link_model_files(model, source)
name = f"model-{outtype}.gguf"
t0 = time.perf_counter()
subprocess.run([python, converter, source, "--no-mtp", "--outfile", os.path.join(out, name), "--outtype", outtype], check=True)
shutil.rmtree(source)
commit = subprocess.run(["git", "-C", llama_cpp, "rev-parse", "--short", "HEAD"], capture_output=True, text=True).stdout.strip() or None
return {"format": BUILD_FORMAT, "backend": "llamacpp", "model": model_name(model), "model_fingerprint": fingerprint(model), "files": {"gguf": name},
"type": outtype, "bytes": os.path.getsize(os.path.join(out, name)), "llama_cpp": commit, "seconds": round(time.perf_counter() - t0, 1)} # fmt: skip
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="python -m decisionnode_edge.build", description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("backend", choices=("openvino", "gguf"))
parser.add_argument("model", help="the model directory (only read)")
parser.add_argument("--out", required=True, help="the directory to write (must not exist)")
parser.add_argument("--lengths", default=",".join(map(str, DEFAULT_LENGTHS)), help="openvino: the static lengths in tokens (default 512,2048)")
parser.add_argument("--device", default=None, help="openvino: where the export runs, cuda or cpu (default: cuda when present)")
parser.add_argument("--llama-cpp", help="gguf: the llama.cpp checkout (its convert_hf_to_gguf.py)")
parser.add_argument("--type", default="q8_0", choices=("q8_0", "bf16"), help="gguf: the weight type (default q8_0)")
parser.add_argument("--python", default=sys.executable, help="gguf: the Python that runs llama.cpp's converter (default: this one)")
args = parser.parse_args(argv)
for name in ("config.json", "model.safetensors", "decisionnode_edge.json"):
if not os.path.isfile(os.path.join(args.model, name)):
raise SystemExit(f"{args.model} is not a DecisionNode Edge model directory (no {name})")
if args.backend == "gguf" and not args.llama_cpp:
raise SystemExit("gguf needs --llama-cpp")
new_directory(args.out)
if args.backend == "openvino":
lengths = sorted({int(x) for x in args.lengths.split(",") if x.strip()})
record = build_openvino(args.model, args.out, lengths, args.device)
else:
record = build_gguf(args.model, args.out, args.llama_cpp, args.type, args.python)
write_record(args.out, record)
print(json.dumps({k: v for k, v in record.items() if k != "versions"}), flush=True)
return 0
if __name__ == "__main__":
sys.exit(main())
|