On this tutorial, we got down to recreate the spirit of the Hierarchical Reasoning Mannequin (HRM) utilizing a free Hugging Face mannequin that runs regionally. We stroll by means of the design of a light-weight but structured reasoning agent, the place we act as each architects and experimenters. By breaking issues into subgoals, fixing them with Python, critiquing the outcomes, and synthesizing a closing reply, we will expertise how hierarchical planning and execution can improve reasoning efficiency. This course of allows us to see, in real-time, how a brain-inspired workflow could be applied with out requiring large mannequin sizes or costly APIs. Try the Paper and FULL CODES.
!pip -q set up -U transformers speed up bitsandbytes wealthy
import os, re, json, textwrap, traceback
from typing import Dict, Any, Checklist
from wealthy import print as rprint
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
MODEL_NAME = "Qwen/Qwen2.5-1.5B-Instruct"
DTYPE = torch.bfloat16 if torch.cuda.is_available() else torch.float32
We start by putting in the required libraries and loading the Qwen2.5-1.5B-Instruct mannequin from Hugging Face. We set the info sort based mostly on GPU availability to make sure environment friendly mannequin execution in Colab.
tok = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=True)
mannequin = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
device_map="auto",
torch_dtype=DTYPE,
load_in_4bit=True
)
gen = pipeline(
"text-generation",
mannequin=mannequin,
tokenizer=tok,
return_full_text=False
)
We load the tokenizer and mannequin, configure it to run in 4-bit for effectivity, and wrap all the things in a text-generation pipeline so we will work together with the mannequin simply in Colab. Try the Paper and FULL CODES.
def chat(immediate: str, system: str = "", max_new_tokens: int = 512, temperature: float = 0.3) -> str:
msgs = []
if system:
msgs.append({"position":"system","content material":system})
msgs.append({"position":"person","content material":immediate})
inputs = tok.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True)
out = gen(inputs, max_new_tokens=max_new_tokens, do_sample=(temperature>0), temperature=temperature, top_p=0.9)
return out[0]["generated_text"].strip()
def extract_json(txt: str) -> Dict[str, Any]:
m = re.search(r"{[sS]*}$", txt.strip())
if not m:
m = re.search(r"{[sS]*?}", txt)
attempt:
return json.hundreds(m.group(0)) if m else {}
besides Exception:
# fallback: strip code fences
s = re.sub(r"^```.*?n|n```$", "", txt, flags=re.S)
attempt:
return json.hundreds(s)
besides Exception:
return {}
We outline helper features: the chat perform permits us to ship prompts to the mannequin with non-compulsory system directions and sampling controls, whereas extract_json helps us parse structured JSON outputs from the mannequin reliably, even when the response contains code fences or further textual content. Try the Paper and FULL CODES.
def extract_code(txt: str) -> str:
m = re.search(r"```(?:python)?s*([sS]*?)```", txt, flags=re.I)
return (m.group(1) if m else txt).strip()
def run_python(code: str, env: Dict[str, Any] | None = None) -> Dict[str, Any]:
import io, contextlib
g = {"__name__": "__main__"}; l = {}
if env: g.replace(env)
buf = io.StringIO()
attempt:
with contextlib.redirect_stdout(buf):
exec(code, g, l)
out = l.get("RESULT", g.get("RESULT"))
return {"okay": True, "outcome": out, "stdout": buf.getvalue()}
besides Exception as e:
return {"okay": False, "error": str(e), "hint": traceback.format_exc(), "stdout": buf.getvalue()}
PLANNER_SYS = """You're the HRM Planner.
Decompose the TASK into 2–4 atomic, code-solvable subgoals.
Return compact JSON solely: {"subgoals":[...], "final_format":""}."""
SOLVER_SYS = """You're the HRM Solver.
Given SUBGOAL and CONTEXT vars, output a single Python snippet.
Guidelines:
- Compute deterministically.
- Set a variable RESULT to the reply.
- Preserve code quick; stdlib solely.
Return solely a Python code block."""
CRITIC_SYS = """You're the HRM Critic.
Given TASK and LOGS (subgoal outcomes), resolve if closing reply is prepared.
Return JSON solely: "revise","critique":"...", "fix_hint":""."""
SYNTH_SYS = """You're the HRM Synthesizer.
Given TASK, LOGS, and final_format, output solely the ultimate reply (no steps).
Comply with final_format precisely."""
We add two vital items: utility features and system prompts. The extract_code perform pulls Python snippets from the mannequin’s output, whereas run_python safely executes these snippets and captures their outcomes. Alongside, we outline 4 position prompts, Planner, Solver, Critic, and Synthesizer, which information the mannequin to interrupt duties into subgoals, remedy them with code, confirm correctness, and eventually produce a clear reply. Try the Paper and FULL CODES.
def plan(job: str) -> Dict[str, Any]:
p = f"TASK:n{job}nReturn JSON solely."
return extract_json(chat(p, PLANNER_SYS, temperature=0.2, max_new_tokens=300))
def solve_subgoal(subgoal: str, context: Dict[str, Any]) -> Dict[str, Any]:
immediate = f"SUBGOAL:n{subgoal}nCONTEXT vars: {listing(context.keys())}nReturn Python code solely."
code = extract_code(chat(immediate, SOLVER_SYS, temperature=0.2, max_new_tokens=400))
res = run_python(code, env=context)
return {"subgoal": subgoal, "code": code, "run": res}
def critic(job: str, logs: Checklist[Dict[str, Any]]) -> Dict[str, Any]:
pl = [{"subgoal": L["subgoal"], "outcome": L["run"].get("outcome"), "okay": L["run"]["ok"]} for L in logs]
out = chat("TASK:n"+job+"nLOGS:n"+json.dumps(pl, ensure_ascii=False, indent=2)+"nReturn JSON solely.",
CRITIC_SYS, temperature=0.1, max_new_tokens=250)
return extract_json(out)
def refine(job: str, logs: Checklist[Dict[str, Any]]) -> Dict[str, Any]:
sys = "Refine subgoals minimally to repair points. Return similar JSON schema as planner."
out = chat("TASK:n"+job+"nLOGS:n"+json.dumps(logs, ensure_ascii=False)+"nReturn JSON solely.",
sys, temperature=0.2, max_new_tokens=250)
j = extract_json(out)
return j if j.get("subgoals") else {}
def synthesize(job: str, logs: Checklist[Dict[str, Any]], final_format: str) -> str:
packed = [{"subgoal": L["subgoal"], "outcome": L["run"].get("outcome")} for L in logs]
return chat("TASK:n"+job+"nLOGS:n"+json.dumps(packed, ensure_ascii=False)+
f"nfinal_format: {final_format}nOnly the ultimate reply.",
SYNTH_SYS, temperature=0.0, max_new_tokens=120).strip()
def hrm_agent(job: str, context: Dict[str, Any] | None = None, funds: int = 2) -> Dict[str, Any]:
ctx = dict(context or {})
hint, plan_json = [], plan(job)
for round_id in vary(1, funds+1):
logs = [solve_subgoal(sg, ctx) for sg in plan_json.get("subgoals", [])]
for L in logs:
ctx_key = f"g{len(hint)}_{abs(hash(L['subgoal']))%9999}"
ctx[ctx_key] = L["run"].get("outcome")
verdict = critic(job, logs)
hint.append({"spherical": round_id, "plan": plan_json, "logs": logs, "verdict": verdict})
if verdict.get("motion") == "submit": break
plan_json = refine(job, logs) or plan_json
closing = synthesize(job, hint[-1]["logs"], plan_json.get("final_format", "Reply: "))
return {"closing": closing, "hint": hint}
We implement the complete HRM loop: we plan subgoals, remedy every by producing and operating Python (capturing RESULT), then we critique, optionally refine the plan, and synthesize a clear closing reply. We orchestrate these rounds in hrm_agent, carrying ahead intermediate outcomes as context so we iteratively enhance and cease as soon as the critic says “submit.” Try the Paper and FULL CODES.
ARC_TASK = textwrap.dedent("""
Infer the transformation rule from practice examples and apply to check.
Return precisely: "Reply: ", the place is a Python listing of lists of ints.
""").strip()
ARC_DATA = {
"practice": [
{"inp": [[0,0],[1,0]], "out": [[1,1],[0,1]]},
{"inp": [[0,1],[0,0]], "out": [[1,0],[1,1]]}
],
"check": [[0,0],[0,1]]
}
res1 = hrm_agent(ARC_TASK, context={"TRAIN": ARC_DATA["train"], "TEST": ARC_DATA["test"]}, funds=2)
rprint("n[bold]Demo 1 — ARC-like Toy[/bold]")
rprint(res1["final"])
WM_TASK = "A tank holds 1200 L. It leaks 2% per hour for 3 hours, then is refilled by 150 L. Return precisely: 'Reply: '."
res2 = hrm_agent(WM_TASK, context={}, funds=2)
rprint("n[bold]Demo 2 — Phrase Math[/bold]")
rprint(res2["final"])
rprint("n[dim]Rounds executed (Demo 1):[/dim]", len(res1["trace"]))
We run two demos to validate the agent: an ARC-style job the place we infer a change from practice pairs and apply it to a check grid, and a word-math downside that checks numeric reasoning. We name hrm_agent with every job, print the ultimate solutions, and likewise show the variety of reasoning rounds the ARC run takes.
In conclusion, we acknowledge that what we now have constructed is greater than a easy demonstration; it’s a window into how hierarchical reasoning could make smaller fashions punch above their weight. By layering planning, fixing, and critiquing, we empower a free Hugging Face mannequin to carry out duties with shocking robustness. We depart with a deeper appreciation of how brain-inspired constructions, when paired with sensible, open-source instruments, allow us to discover reasoning benchmarks and experiment creatively with out incurring excessive prices. This hands-on journey reveals us that superior cognitive-like workflows are accessible to anybody prepared to tinker, iterate, and study.
Try the Paper and FULL CODES. Be at liberty to take a look at our GitHub Web page for Tutorials, Codes and Notebooks. Additionally, be at liberty to comply with us on Twitter and don’t neglect to affix our 100k+ ML SubReddit and Subscribe to our E-newsletter.
Asif Razzaq is the CEO of Marktechpost Media Inc.. As a visionary entrepreneur and engineer, Asif is dedicated to harnessing the potential of Synthetic Intelligence for social good. His most up-to-date endeavor is the launch of an Synthetic Intelligence Media Platform, Marktechpost, which stands out for its in-depth protection of machine studying and deep studying information that’s each technically sound and simply comprehensible by a large viewers. The platform boasts of over 2 million month-to-month views, illustrating its recognition amongst audiences.