Meet Kyutai REKI: The 2.4B VLA Model Bringing Efficient Memory to Robot Manipulation

Kyutai, with Inria and École des Ponts, has released REKI, a 2.4B vision-language-action model (VLA) for robot manipulation. The REKI vision-language-action model is pretrained only on public data. It also carries a cheap memory of its recent past. On three out-of-distribution benchmarks, only models about twice its size beat it. All weights are live on Hugging Face today.

TL;DR

  • Size: 2.4B parameters (2.2B Qwen3.5-2B VLM + 0.2B flow-matching action expert). Memory covers the last 3 frames, 1 s apart.
  • Runs on: Benchmarked on 1 NVIDIA H100. 21.8 ms per action chunk, compiled, from 2 cameras at 256×256. Weights ship in BF16. No quantized variants announced.
  • Performance: Best among VLAs pretrained on public data on LIBERO-Plus and RoboTwin Clean2Rand.
  • Best: 90.4% on LIBERO-Plus, the top score in Kyutai’s comparison.
  • Worst: 38.4% on RoboCasa365, well behind Xiaomi-Robotics-1 (57.4%).

What is REKI?

REKI is a vision-language-action model from Kyutai that maps camera views and an instruction to robot actions. It pairs a Qwen3.5-2B backbone with a 200M-parameter action expert. The expert generates action chunks by flow matching, integrated in 10 Euler steps. Robot state and flow time enter through adaptive RMSNorm. Each robot state layout gets its own small state MLP.

How does REKI’s memory work?

Most VLAs act on the current frame alone. Prior memory methods feed past frames to the VLM, unroll training, or add modules. Each option adds cost.

REKI places memory inside the action expert instead. Before each frame’s action tokens sit 32 learned register tokens. They cross-attend the encoded prompt and views of that frame. They also self-attend the registers of earlier frames.

Registers never read action tokens. So they depend only on observations, not flow time or robot state. They are computed once per frame and cached in a rolling window.

The cost is small, per the project page:

  • Reading cached registers adds 0.1 ms to a 21.8 ms chunk.
  • The cache uses about 2 MiB of GPU memory per past frame.
  • Training packs a 3-frame window into 1 batched pass.

Memory also fixes a failure mode. Without it, arms often oscillate between 2 poses. On RoboTwin, oscillating episodes fall from 18.6% to 4.1% with memory. Kyutai attributes this to perceptual aliasing.

How does REKI perform on benchmarks?

REKI is pretrained once, then finetuned separately per benchmark. Scores below come from the model card and project page.

  • LIBERO-Plus: 90.4%, ahead of Qwen-RobotManip (89.0%) and π0.5 (85.7%).
  • RoboTwin Clean2Rand: 65.8%, behind only Qwen-RobotManip (68.5%).
  • RoboCasa365: 38.4%, ahead of RLDX-1 (36.0%) and Qwen-RobotManip (35.9%).
  • LIBERO (4 suites): 97.6%.
  • RoboTwin 2.0 Easy / Hard: 85.9% / 84.6%.

Pretraining helps most out of distribution. It adds 13.8 points on Clean2Rand and 30.3 under clutter. Memory adds 1.5 points on LIBERO-Plus and 5.4 on RoboCasa365.

<iframe id="mtp-reki-frame" title="REKI interactive explainer" style="width:100%;height:600px;border:0;display:block;background:#0a0a0a;border-radius:14px;" loading="lazy" srcdoc="<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>REKI Explainer</title><style>html,body{margin:0;background:#0a0a0a}</style></head><body><div id="mtp-reki">
<style>
#mtp-reki{–bg:#0a0a0a;–card:#141414;–line:#262626;–fg:#f2f2f2;–mut:#9a9a9a;–g:#6be3a0;–g2:#2f9e6a;–mtp:#76B900;
max-width:880px;margin:0 auto;background:var(–bg)!important;color:var(–fg)!important;border:1px solid var(–line)!important;border-radius:14px;padding:22px 22px 14px;font-family:Inter,system-ui,-apple-system,Segoe UI,Roboto,sans-serif;box-sizing:border-box;line-height:1.45}
#mtp-reki *{box-sizing:border-box}
#mtp-reki hr,#mtp-reki p:empty,#mtp-reki del,#mtp-reki s{display:none!important}
#mtp-reki .hd{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:14px}
#mtp-reki .kick{font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(–g)!important;font-weight:700}
#mtp-reki h3{margin:4px 0 0;font-size:22px;font-weight:800;color:var(–fg)!important;letter-spacing:-.01em}
#mtp-reki .chip{font-size:12px;color:var(–mut)!important;border:1px solid var(–line)!important;border-radius:999px;padding:4px 10px;background:var(–card)!important}
#mtp-reki .tabs{display:flex;gap:6px;flex-wrap:wrap;border-bottom:1px solid var(–line);margin-bottom:16px}
#mtp-reki .tab{background:transparent!important;color:var(–mut)!important;border:0!important;border-bottom:2px solid transparent!important;padding:9px 12px;font:600 13px Inter,system-ui,sans-serif;cursor:pointer;transition:color .2s}
#mtp-reki .tab:hover{color:var(–fg)!important}
#mtp-reki .tab.on{color:var(–g)!important;border-bottom-color:var(–g)!important}
#mtp-reki .pane{display:none;animation:rkfade .35s ease}
#mtp-reki .pane.on{display:block}
@keyframes rkfade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
#mtp-reki .flow{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-bottom:14px}
#mtp-reki .node{background:var(–card)!important;border:1px solid var(–line)!important;border-radius:10px;padding:12px 10px;min-height:92px;transition:all .35s;opacity:.45;position:relative}
#mtp-reki .node b{display:block;font-size:13px;color:var(–fg)!important;margin-bottom:4px}
#mtp-reki .node span{font-size:11.5px;color:var(–mut)!important}
#mtp-reki .node.act{opacity:1;border-color:var(–g)!important;box-shadow:0 0 0 1px var(–g),0 0 22px rgba(107,227,160,.25);transform:translateY(-2px)}
#mtp-reki .node.done{opacity:.85}
#mtp-reki .desc{background:var(–card)!important;border-left:3px solid var(–g)!important;border-radius:8px;padding:12px 14px;font-size:14px;min-height:64px;color:var(–fg)!important}
#mtp-reki .ctrl{display:flex;gap:8px;margin-top:12px;align-items:center;flex-wrap:wrap}
#mtp-reki .btn{background:var(–card)!important;color:var(–fg)!important;border:1px solid var(–line)!important;border-radius:8px;padding:7px 13px;font:600 12.5px Inter,system-ui,sans-serif;cursor:pointer;transition:all .2s}
#mtp-reki .btn:hover{border-color:var(–g)!important;color:var(–g)!important}
#mtp-reki .btn.pri{background:var(–g)!important;color:#06140c!important;border-color:var(–g)!important}
#mtp-reki .dots{display:flex;gap:5px;margin-left:auto}
#mtp-reki .dot{width:7px;height:7px;border-radius:50%;background:#333!important;transition:background .3s}
#mtp-reki .dot.on{background:var(–g)!important}
#mtp-reki .cache{display:flex;gap:10px;align-items:stretch;margin:6px 0 14px;overflow:hidden}
#mtp-reki .fr{flex:1;background:var(–card)!important;border:1px solid var(–line)!important;border-radius:10px;padding:10px;text-align:center;transition:all .5s}
#mtp-reki .fr .t{font-size:11px;color:var(–mut)!important}
#mtp-reki .fr .regs{display:grid;grid-template-columns:repeat(8,1fr);gap:3px;margin:8px 0}
#mtp-reki .fr .regs i{height:9px;border-radius:2px;background:var(–g2)!important;display:block}
#mtp-reki .fr.cur{border-color:var(–g)!important}
#mtp-reki .fr.cur .regs i{background:var(–g)!important;animation:rkpulse 1.6s infinite}
#mtp-reki .fr.drop{opacity:.18;filter:grayscale(1)}
@keyframes rkpulse{50%{opacity:.5}}
#mtp-reki .grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
#mtp-reki .box{background:var(–card)!important;border:1px solid var(–line)!important;border-radius:10px;padding:14px}
#mtp-reki .box h4{margin:0 0 10px;font-size:13px;color:var(–fg)!important}
#mtp-reki .row{display:grid;grid-template-columns:150px 1fr 52px;gap:8px;align-items:center;margin:7px 0;font-size:12.5px}
#mtp-reki .row .n{color:var(–mut)!important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#mtp-reki .row.me .n,#mtp-reki .row.me .v{color:var(–g)!important;font-weight:700}
#mtp-reki .bar{height:14px;background:#1d1d1d!important;border-radius:4px;overflow:hidden}
#mtp-reki .bar i{display:block;height:100%;width:0;background:#4a4a4a!important;border-radius:4px;transition:width .9s cubic-bezier(.2,.8,.2,1)}
#mtp-reki .row.me .bar i{background:linear-gradient(90deg,var(–g2),var(–g))!important}
#mtp-reki .v{text-align:right;font-variant-numeric:tabular-nums;color:var(–fg)!important}
#mtp-reki .seg{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px}
#mtp-reki .seg .btn.on{border-color:var(–g)!important;color:var(–g)!important}
#mtp-reki .note{font-size:11.5px;color:var(–mut)!important;margin-top:10px}
#mtp-reki .big{font-size:34px;font-weight:800;color:var(–g)!important;line-height:1}
#mtp-reki .ft{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:16px;padding-top:10px;border-top:1px solid var(–line);font-size:11.5px;color:var(–mut)!important}
#mtp-reki .ft a{color:var(–mtp)!important;text-decoration:none;font-weight:700}
#mtp-reki code,#mtp-reki pre{background:#1a1a1a!important;color:var(–g)!important;border:0!important}
@media (max-width:640px){
#mtp-reki{padding:16px 14px 12px}
#mtp-reki h3{font-size:18px}
#mtp-reki .flow{grid-template-columns:1fr 1fr}
#mtp-reki .node{min-height:0}
#mtp-reki .grid2{grid-template-columns:1fr}
#mtp-reki .row{grid-template-columns:132px 1fr 38px;font-size:11px;gap:6px}
#mtp-reki .tab{padding:8px 8px;font-size:12px}
#mtp-reki .cache{gap:6px}
#mtp-reki .fr{padding:7px}
}
</style>

<div class="hd">
<div><div class="kick">Kyutai · Vision-Language-Action</div><h3>How REKI works</h3></div>
<div class="chip">2.4B params · public data only · 21.8 ms / chunk</div>
</div>

<div class="tabs" role="tablist">
<button class="tab on" data-t="0">Architecture</button>
<button class="tab" data-t="1">Memory</button>
<button class="tab" data-t="2">Benchmarks</button>
<button class="tab" data-t="3">Latency</button>
</div>


<div class="pane on" data-p="0">
<div class="flow">
<div class="node" data-s="0"><b>1. Inputs</b><span>2 camera views + text instruction</span></div>
<div class="node" data-s="1"><b>2. VLM</b><span>Qwen3.5-2B encodes the context (2.2B)</span></div>
<div class="node" data-s="2"><b>3. Registers</b><span>32 tokens summarize this frame</span></div>
<div class="node" data-s="3"><b>4. KV cache</b><span>Registers of last 2 frames kept</span></div>
<div class="node" data-s="4"><b>5. Action expert</b><span>0.2B flow matching, 10 Euler steps</span></div>
</div>
<div class="desc" id="rk-desc"></div>
<div class="ctrl">
<button class="btn" id="rk-prev">Back</button>
<button class="btn pri" id="rk-next">Next step</button>
<button class="btn" id="rk-play">Auto-play</button>
<div class="dots" id="rk-dots"></div>
</div>
</div>


<div class="pane" data-p="1">
<div class="cache" id="rk-cache"></div>
<div class="ctrl" style="margin:0 0 14px"><button class="btn pri" id="rk-adv">New frame arrives</button><span class="note" style="margin:0">Window K = 3 frames, 1 s apart. The oldest frame’s registers are dropped.</span></div>
<div class="grid2">
<div class="box">
<h4>Pose oscillation on RoboTwin (% of episodes)</h4>
<div class="row"><span class="n">No memory (1→1)</span><div class="bar"><i data-w="18.6" data-m="25"></i></div><span class="v">18.6</span></div>
<div class="row me"><span class="n">Memory (3→3)</span><div class="bar"><i data-w="4.1" data-m="25"></i></div><span class="v">4.1</span></div>
<div class="note">About 4× rarer with memory.</div>
</div>
<div class="box">
<h4>Success with vs without memory (%)</h4>
<div class="row"><span class="n">LIBERO-Plus</span><div class="bar"><i data-w="88.9" data-m="100"></i></div><span class="v">88.9</span></div>
<div class="row me"><span class="n">+ memory</span><div class="bar"><i data-w="90.4" data-m="100"></i></div><span class="v">90.4</span></div>
<div class="row"><span class="n">RoboCasa365</span><div class="bar"><i data-w="33.0" data-m="100"></i></div><span class="v">33.0</span></div>
<div class="row me"><span class="n">+ memory</span><div class="bar"><i data-w="38.4" data-m="100"></i></div><span class="v">38.4</span></div>
<div class="note">Cost: +0.1 ms per chunk, ~2 MiB GPU memory per past frame.</div>
</div>
</div>
</div>


<div class="pane" data-p="2">
<div class="seg" id="rk-seg">
<button class="btn on" data-b="lp">LIBERO-Plus</button>
<button class="btn" data-b="c2r">RoboTwin Clean2Rand</button>
<button class="btn" data-b="rc">RoboCasa365</button>
</div>
<div class="box" id="rk-bench"></div>
<div class="note">Success rate (%), as reported on Kyutai’s project page. Model sizes in parentheses.</div>
</div>


<div class="pane" data-p="3">
<div class="grid2">
<div class="box" style="grid-column:1/-1">
<h4>One action chunk on 1 H100, compiled (ms, lower is better)</h4>
<div id="rk-lat"></div>
<div class="note">Measured by Kyutai with LIBERO inputs and each model’s released checkpoint.</div>
</div>
</div>
</div>

<div class="ft">
<span>Sources: kyutai.org/reki · arXiv 2610.22178 · huggingface.co/kyutai/reki-2b</span>
<a href="https://www.marktechpost.com" target="_blank" rel="noopener">Built by Marktechpost</a>
</div>

<script>
(function(){
var R=document.getElementById(‘mtp-reki’);
function q(s){return R.querySelectorAll(s)}
function grow(scope){scope.querySelectorAll(‘.bar i’).forEach(function(b){b.style.width=’0′;setTimeout(function(){b.style.width=(parseFloat(b.dataset.w)/parseFloat(b.dataset.m)*100)+’%’},60)})}
function resize(){try{parent.postMessage({mtpRekiHeight:R.offsetHeight+40},’*’)}catch(e){}}
q(‘.tab’).forEach(function(t){t.onclick=function(){q(‘.tab’).forEach(function(x){x.classList.remove(‘on’)});t.classList.add(‘on’);q(‘.pane’).forEach(function(p){p.classList.toggle(‘on’,p.dataset.p===t.dataset.t)});var p=R.querySelector(‘.pane.on’);grow(p);setTimeout(resize,80)}});
var steps=["The robot sends 2 camera images (256×256) and a text instruction such as “put the bowl on the plate”.",
"A Qwen3.5-2B vision-language backbone (2.2B params) encodes views and instruction into one context.",
"In the action expert, 32 learned register tokens cross-attend this context. They never read the action tokens, so they are computed once per frame.",
"Register keys and values go into a rolling KV cache over the 2 previous frames. Reading them adds just 0.1 ms.",
"The 0.2B flow-matching expert reads current and past registers and outputs an action chunk in 10 Euler steps: 21.8 ms on 1 H100."];
var s=0,timer=null,nodes=q(‘.node’),dots=document.getElementById(‘rk-dots’);
steps.forEach(function(){var d=document.createElement(‘span’);d.className=’dot’;dots.appendChild(d)});
function show(){nodes.forEach(function(n,i){n.classList.toggle(‘act’,i===s);n.classList.toggle(‘done’,i<s)});dots.querySelectorAll(‘.dot’).forEach(function(d,i){d.classList.toggle(‘on’,i<=s)});document.getElementById(‘rk-desc’).textContent=steps[s]}
document.getElementById(‘rk-next’).onclick=function(){s=(s+1)%steps.length;show()};
document.getElementById(‘rk-prev’).onclick=function(){s=(s+steps.length-1)%steps.length;show()};
document.getElementById(‘rk-play’).onclick=function(){var b=this;if(timer){clearInterval(timer);timer=null;b.textContent=’Auto-play’;return}b.textContent=’Pause’;timer=setInterval(function(){s=(s+1)%steps.length;show()},2200)};
show();
var f=3,cache=document.getElementById(‘rk-cache’);
function regs(){var h=”;for(var i=0;i<16;i++)h+='<i></i>’;return h}
function draw(drop){var h=”;if(drop)h+='<div class="fr drop"><div class="t">t−’+’3 (dropped)</div><div class="regs">’+regs()+'</div><div class="t">frame ‘+(f-3)+'</div></div>’;
[2,1,0].forEach(function(k){h+='<div class="fr’+(k===0?’ cur’:”)+’"><div class="t">’+(k===0?’current t’:’cached t−’+k)+'</div><div class="regs">’+regs()+'</div><div class="t">frame ‘+(f-k)+'</div></div>’});cache.innerHTML=h}
draw(false);
document.getElementById(‘rk-adv’).onclick=function(){f++;draw(true);setTimeout(function(){draw(false)},900)};
var B={lp:[["REKI (2.4B)",90.4,1],["Qwen-RobotManip (4.7B)",89.0],["RLDX-1 (6.9B)",86.7],["π0.5 (3.3B)",85.7],["InternVLA-A1.5 (2.7B)",84.8],["ABot-M0 (4.6B)",80.5]],
c2r:[["Qwen-RobotManip (4.7B)",68.5],["REKI (2.4B)",65.8,1],["π0.5 (3.3B)",63.8],["ABot-M0 (4.6B)",55.7],["GR00T-N1.7 (3.1B)",35.5]],
rc:[["Xiaomi-Robotics-1 (5.1B)",57.4],["ABot-M0.5 (5B)",40.4],["REKI (2.4B)",38.4,1],["RLDX-1 (6.9B)",36.0],["Qwen-RobotManip (4.7B)",35.9],["π0.5 (3.3B)",16.9]]};
function bench(k){var h=”;B[k].forEach(function(r){h+='<div class="row’+(r[2]?’ me’:”)+’"><span class="n" title="’+r[0]+’">’+r[0]+'</span><div class="bar"><i data-w="’+r[1]+’" data-m="100"></i></div><span class="v">’+r[1].toFixed(1)+'</span></div>’});var el=document.getElementById(‘rk-bench’);el.innerHTML=h;grow(el);setTimeout(resize,80)}
q(‘#rk-seg .btn’).forEach(function(b){b.onclick=function(){q(‘#rk-seg .btn’).forEach(function(x){x.classList.remove(‘on’)});b.classList.add(‘on’);bench(b.dataset.b)}});
bench(‘lp’);
var L=[["REKI (2.4B)",21.8,1],["X-VLA (0.9B)",25.5],["π0.5 openpi (3.3B)",33.8],["ABot-M0 (4.6B)",46.1],["InternVLA-A1.5 (2.7B)",51.3]],lh=”;
L.forEach(function(r){lh+='<div class="row’+(r[2]?’ me’:”)+’"><span class="n">’+r[0]+'</span><div class="bar"><i data-w="’+r[1]+’" data-m="60"></i></div><span class="v">’+r[1]+'</span></div>’});
document.getElementById(‘rk-lat’).innerHTML=lh;
window.addEventListener(‘load’,resize);window.addEventListener(‘resize’,resize);setTimeout(resize,300);
})();
</script>
</div>
</body></html>”>

How does REKI compare with other VLAs?

Feature REKI (Kyutai) Qwen-RobotManip (Qwen) π0.5 (Physical Intelligence) ABot-M0 (AMAP)
Total size 2.4B 4.7B (per Kyutai) 3.3B (per Kyutai) 4.6B (per Kyutai)
VLM backbone Qwen3.5-2B Qwen3.5-4B Gemma-based Not disclosed
Pretraining data Public only Open-source + human video Includes own robot data Open-source (UniACT)
Memory 32 registers, 3 frames In-context variant None None
LIBERO-Plus 90.4 89.0 85.7 (Kyutai eval) 80.5
RoboTwin Clean2Rand (mean) 65.8 68.5 63.8 55.7
RoboCasa365 38.4 35.9 16.9 Not disclosed
H100 latency, compiled 21.8 ms Not disclosed 33.8 ms (openpi, Kyutai) 46.1 ms (Kyutai)
Weights Open, CC BY-NC-SA 4.0 Not released Open, Apache-2.0 repo Open, Apache-2.0 repo

Notes: Clean2Rand means are computed from the 6 conditions in Table 5 of the Qwen-RobotManip report. The Qwen report lists π0.5 at 84.4 on LIBERO-Plus.

What data was REKI trained on?

The mixture holds 1.0B frames plus 12.2M vision-language samples. Real-robot teleoperation provides 639.8M frames, simulation 193.9M and egocentric human video 170.9M. Sources include DROID, BridgeData V2, AgiBot World, EgoDex and EgoVerse. Pretraining ran 200,000 steps on 32 H100 GPUs. Kyutai keeps each dataset’s native control convention rather than remapping actions.

How do you deploy REKI?

Six checkpoints are listed: the pretrained base plus finetunes for LIBERO, RoboTwin (2 variants), RoboCasa365 and RoboCasa-GR1. Real-robot deployment uses the LeRobot async-inference gRPC protocol. On a UR5 arm, REKI was finetuned for 3k steps (1 hour) on 50 demonstrations per task.

from reki import RekiPolicy

policy = RekiPolicy.from_pretrained("kyutai/reki-2b-libero", device="cuda")
policy.reset()  # clears the register cache at episode start
actions = policy.predict(images={"camera_top": img0, "camera_wrist_left": img1},
                         state=proprio, task="put the bowl on the plate")

Key Takeaways

  • REKI is a 2.4B VLA pretrained only on public data.
  • It scores 90.4% on LIBERO-Plus, top in Kyutai’s comparison.
  • 32 cached register tokens give memory for 0.1 ms extra.
  • Memory cuts pose oscillations from 18.6% to 4.1% on RoboTwin.
  • Weights are open but non-commercial (CC BY-NC-SA 4.0).


Check out the Paper, Project Page, Model Weights and GitHub Repo. All credit goes to the researcher of this project. Also, feel free to follow us on Twitter and don’t forget to join our 150k+ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.

The post Meet Kyutai REKI: The 2.4B VLA Model Bringing Efficient Memory to Robot Manipulation appeared first on MarkTechPost.