Trained entirely on an 8GB M2 Mac Mini.
Part of the Sid Local LLM Benchmark v3.
1import mlx.core as mx
2from mlx_hrm_text.runner import HRMTextGenerator
3from mlx_hrm_text.model import HrmTextForCausalLM, set_metal_swiglu
4from pathlib import Path
5
6set_metal_swiglu(True)
7
8# Load base model
9gen = HRMTextGenerator(
10 model_dir="Aryagm/HRM-Text-1B-MLX-4bit",
11 temperature=0.3,
12)
13
14# Freeze and apply LoRA
15gen.model.freeze()
16
17# Patch attention projections
18from mlx.nn import Module
19class LoRALinear(Module):
20 def __init__(self, linear, r=16, alpha=32):
21 super().__init__()
22 self.linear = linear
23 self.linear.freeze()
24 self.r = r
25 self.scale = alpha / r
26 out_f, in_f = linear.weight.shape
27 self.lora_a = mx.random.normal((in_f, r)) / r
28 self.lora_b = mx.zeros((r, out_f))
29 def __call__(self, x):
30 dtype = x.dtype
31 return self.linear(x) + (x @ self.lora_a.astype(dtype) @ self.lora_b.astype(dtype)) * self.scale
32
33def apply_lora(module):
34 for block in module.layers:
35 block.attn.gqkv_proj = LoRALinear(block.attn.gqkv_proj)
36 block.attn.o_proj = LoRALinear(block.attn.o_proj)
37
38apply_lora(gen.model.model.H_module)
39apply_lora(gen.model.model.L_module)
40
41# Load adapters
42flat = mx.load("adapters.npz")
43# (Full recursive population in run_hrm_lora_bench.py on GitHub)
44
45result = gen.generate("Write a Python function to reverse a string.")
46print(result.text)
1@misc{reddeer2026hrm,
2 author = {the_red_deer},
3 title = {The HRM Fine-Tuning Journey},
4 year = {2026},
5 url = {https://reddeerinv.com/ai/hrm-fine-tuning-journey/}
6}