Safetensors
GGUF
English
Russian
lfm3
reasoning
test-time-compute
inference-time-scaling
code-generation
llama.cpp
negative-results
conversational
Instructions to use HelioAI/LFM3-1.7B-inference-modules-experiments with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use HelioAI/LFM3-1.7B-inference-modules-experiments 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 HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M # Run inference directly in the terminal: llama cli -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M # Run inference directly in the terminal: llama cli -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Build from source code
git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-app # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama serve -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M # Run inference directly in the terminal: ./build/bin/llama cli -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Use Docker
docker model run hf.co/HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
- Llama new
- LM Studio
- Jan
- Ollama
How to use HelioAI/LFM3-1.7B-inference-modules-experiments with Ollama:
ollama run hf.co/HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
- Unsloth Desktop
- Pi
How to use HelioAI/LFM3-1.7B-inference-modules-experiments with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use HelioAI/LFM3-1.7B-inference-modules-experiments with Docker Model Runner:
docker model run hf.co/HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
- Lemonade
How to use HelioAI/LFM3-1.7B-inference-modules-experiments with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Run and chat with the model
lemonade run user.LFM3-1.7B-inference-modules-experiments-Q5_K_M
List all available models
lemonade list
- Hermes Agent
How to use HelioAI/LFM3-1.7B-inference-modules-experiments with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use HelioAI/LFM3-1.7B-inference-modules-experiments with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "HelioAI/LFM3-1.7B-inference-modules-experiments:Q5_K_M" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
Download research/scripts/bc_probe.py from HelioAI/LFM3-1.7B-inference-modules-experiments: direct link, hf CLI and curl.
- Browser
- Download file 6.81 kB
-
https://huggingface.co/HelioAI/LFM3-1.7B-inference-modules-experiments/resolve/main/research/scripts/bc_probe.py
- Command line
-
hf download hf://HelioAI/LFM3-1.7B-inference-modules-experiments/research/scripts/bc_probe.py
-
curl -L -o bc_probe.py https://huggingface.co/HelioAI/LFM3-1.7B-inference-modules-experiments/resolve/main/research/scripts/bc_probe.py
6.81 kB
| """Commitment bootstrap: turn truncated (budget-exhausted) reasoning into learning signal. | |
| For every truncated math rollout, the reasoning is cut every --step tokens, thinking is closed by force and the | |
| policy answers greedily. Each cut yields a candidate "stop here" continuation that is graded against the reference: | |
| * the earliest cut whose forced answer is correct -> forced sample with reward 1 ("you could have stopped here") | |
| * the latest cut before it whose answer is wrong -> forced sample with reward 0 ("stopping here is premature") | |
| If no cut is correct, the last wrong cut is added with reward 0. Forced samples join the GRPO group of their prompt, | |
| so advantages are computed against the policy's own full-length attempts. | |
| Writes <out_dir>/forced.jsonl (rollout format, stop_type eos) and <out_dir>/forced_graded.jsonl. | |
| usage: bc_probe.py --rollouts R --graded G --items P --out-dir D [--step 1024]""" | |
| import argparse, json, sys, threading, urllib.request | |
| from concurrent.futures import ThreadPoolExecutor | |
| from transformers import AutoTokenizer | |
| sys.path.insert(0, __file__.rsplit("\\", 1)[0].rsplit("/", 1)[0]) | |
| from grade import grade_math # noqa: E402 | |
| ap = argparse.ArgumentParser() | |
| for a in ["--rollouts", "--graded", "--items", "--out-dir"]: | |
| ap.add_argument(a, required=True) | |
| ap.add_argument("--step", type=int, default=1024) | |
| ap.add_argument("--stable", type=int, default=1, | |
| help="a cut counts as 'answer known' only if it and the next stable-1 cuts are all correct") | |
| ap.add_argument("--tokenizer", default="models/LFM3-1.7B") | |
| ap.add_argument("--from-probes", default=None, help="probes.jsonl of an earlier run with the same cuts") | |
| ap.add_argument("--unpaired-neg", action="store_true", | |
| help="also add a negative forced stop for rollouts whose answer is never right (unbalances the signal)") | |
| args = ap.parse_args() | |
| tok = AutoTokenizer.from_pretrained(args.tokenizer) | |
| items = {json.loads(l)["id"]: json.loads(l) for l in open(args.items, encoding="utf-8")} | |
| recs = [json.loads(l) for l in open(args.rollouts, encoding="utf-8")] | |
| recs = [r for r in recs if r["truncated"] and items[r["id"]]["task"] == "math" and "tokens" in r] | |
| THINK_END = 124902 # </think>; the model itself closes thinking right after a sentence end: "...}." + </think> + "The" | |
| SUFFIX = "The final answer is $\\boxed{" | |
| suffix_ids = [THINK_END] + tok(SUFFIX, add_special_tokens=False)["input_ids"] | |
| ENDS = set() | |
| for i_ in range(len(tok)): | |
| t_ = tok.convert_ids_to_tokens(i_) | |
| if t_ is not None and (t_.endswith(".") or t_.endswith("\u010a")): | |
| ENDS.add(i_) | |
| def snap(tokens, k, lo): | |
| """last sentence/paragraph end at or before k (cut right after it), strictly after lo; None if there is none""" | |
| for j in range(k, lo, -1): | |
| if tokens[j - 1] in ENDS: | |
| return j | |
| return None | |
| prompts = {i: tok.apply_chat_template([{"role": "user", "content": items[i]["prompt"]}], tokenize=True, | |
| add_generation_prompt=True, return_dict=False) for i in {r["id"] for r in recs}} | |
| jobs = [] | |
| for r in recs: | |
| prev = 0 | |
| for k in range(args.step, len(r["tokens"]), args.step): | |
| j = snap(r["tokens"], k, prev) | |
| if j: | |
| jobs.append((r, j)) | |
| prev = j | |
| print(len(recs), "truncated math rollouts,", len(jobs), "probes", flush=True) | |
| res = {} | |
| lock = threading.Lock() | |
| def run(job): | |
| r, k = job | |
| body = {"prompt": prompts[r["id"]] + r["tokens"][:k] + suffix_ids, "n_predict": 48, "temperature": 0.0, | |
| "cache_prompt": False, "stop": ["}$", "}\n", "$"]} | |
| try: | |
| out = json.loads(urllib.request.urlopen(urllib.request.Request( | |
| "http://localhost:8080/completion", data=json.dumps(body).encode(), | |
| headers={"Content-Type": "application/json"}), timeout=900).read())["content"] | |
| except urllib.error.HTTPError as e: # e.g. prompt + cut exceeds the slot context: skip this cut | |
| print("probe skipped:", e.code, flush=True) | |
| return | |
| depth, cut = 1, len(out) | |
| for i, ch in enumerate(out): | |
| depth += (ch == "{") - (ch == "}") | |
| if depth == 0: | |
| cut = i | |
| break | |
| pred = out[:cut].strip() | |
| ok = bool(pred) and grade_math("\\boxed{" + pred + "}", items[r["id"]]["answer"]) | |
| with lock: | |
| res[(r["id"], r["sample"], k)] = (pred, ok) | |
| if args.from_probes: # reuse saved probe results (no server needed) | |
| for l in open(args.from_probes, encoding="utf-8"): | |
| q = json.loads(l) | |
| res[(q["id"], q["sample"], q["k"])] = (q["pred"], q["ok"]) | |
| else: | |
| with ThreadPoolExecutor(32) as ex: | |
| list(ex.map(run, jobs)) | |
| with open(f"{args.out_dir}/probes.jsonl", "w", encoding="utf-8") as f: | |
| f.writelines(json.dumps({"id": i, "sample": s_, "k": k, "pred": v[0], "ok": v[1]}) + "\n" for (i, s_, k), v in res.items()) | |
| forced, graded, n_pos, n_neg, n_any = [], [], 0, 0, 0 | |
| for r in recs: | |
| cuts = sorted(k for (i, s, k) in res if i == r["id"] and s == r["sample"]) | |
| oks = [res[(r["id"], r["sample"], k)] for k in cuts] | |
| first_ok = next((j for j in range(len(oks)) if all(ok for _, ok in oks[j: j + args.stable])), None) | |
| picks = [] | |
| if first_ok is not None: | |
| n_any += 1 | |
| picks.append((cuts[first_ok], 1.0)) | |
| wrong_before = [j for j in range(first_ok) if not oks[j][1]] | |
| if wrong_before: | |
| picks.append((cuts[wrong_before[-1]], 0.0)) | |
| elif cuts and args.unpaired_neg: | |
| picks.append((cuts[-1], 0.0)) # off by default: 'no answer anywhere' is not a premature-stop signal | |
| for k, rew in picks: | |
| pred = res[(r["id"], r["sample"], k)][0] | |
| tail = [THINK_END] + tok(SUFFIX + pred + "}$", add_special_tokens=False)["input_ids"] | |
| sid = 1000 + r["sample"] * 100 + k // 256 | |
| forced.append({"id": r["id"], "task": "math", "sample": sid, "tokens": r["tokens"][:k] + tail, | |
| "stop_type": "eos", "truncated": False, "forced": True, "cut": k, "loss_from": k}) | |
| graded.append({"id": r["id"], "task": "math", "sample": sid, "correct": rew, "forced": True}) | |
| n_pos += rew == 1.0 | |
| n_neg += rew == 0.0 | |
| with open(f"{args.out_dir}/forced.jsonl", "w", encoding="utf-8") as f: | |
| f.writelines(json.dumps(x) + "\n" for x in forced) | |
| with open(f"{args.out_dir}/forced_graded.jsonl", "w", encoding="utf-8") as f: | |
| f.writelines(json.dumps(x) + "\n" for x in graded) | |
| print(f"truncated rollouts whose forced answer is right at some cut: {n_any}/{len(recs)}; " | |
| f"forced samples: {n_pos} positive, {n_neg} negative", flush=True) | |
| probe_acc = sum(ok for _, ok in res.values()) / max(1, len(res)) | |
| print(f"probe accuracy over all cuts: {probe_acc:.3f}") | |