Skip to content

Benchmarks

Benchmarks of ruNNtime against the alternatives. Same model, same input, same browser, one engine at a time: ruNNtime zoo, ruNNtime through the transformers.js plugin, and stock transformers.js on ONNX Runtime, all on WebGPU. All tests were performed on an Apple M2 Pro.

Moonshine on 500 utterances of LibriSpeech test-clean, 66 minutes of speech. ruNNtime runs the f16 weights in half precision, its default. transformers.js runs the fp32 and q4 ONNX exports.

Seconds of audio transcribed per second. Higher is better.

  • ruNNtime tiny137×
  • ruNNtime tiny, tjs plugin139×
  • transformers.js tiny fp3220×
  • transformers.js tiny q420×
  • ruNNtime base78×
  • ruNNtime base, tjs plugin78×
  • transformers.js base fp3215×
  • transformers.js base q415×
  • ruNNtime streaming tiny123×

Decode time per generated token. Lower is better.

  • ruNNtime tiny1.8 ms
  • ruNNtime tiny, tjs plugin1.7 ms
  • transformers.js tiny fp3212.1 ms
  • transformers.js tiny q412.3 ms
  • ruNNtime base2.6 ms
  • ruNNtime base, tjs plugin2.6 ms
  • transformers.js base fp3216.3 ms
  • transformers.js base q415.9 ms
  • ruNNtime streaming tiny1.9 ms
ModelEnginePrecision× realtimems per token
tinyruNNtimef161371.8
tinyruNNtime, tjs pluginf161391.7
tinytransformers.jsfp322012.1
tinytransformers.jsq42012.3
baseruNNtimef16782.6
baseruNNtime, tjs pluginf16782.6
basetransformers.jsfp321516.3
basetransformers.jsq41515.9
streaming tinyruNNtimef161231.9

all-MiniLM-L6-v2 on 1000 Wikipedia paragraphs, 22 to 629 words each, in batches of 1, 8 and 32 paragraphs per call. ruNNtime runs the f16 weights in half precision, its default. transformers.js runs the fp32 ONNX export, its WebGPU default, plus the fp16 and q4 exports.

Higher is better.

  • ruNNtime596/s
  • ruNNtime, tjs plugin230/s
  • transformers.js fp3287/s
  • transformers.js fp16128/s
  • transformers.js q493/s

Milliseconds per paragraph.

EnginePrecisionBatch 1Batch 8Batch 32
ruNNtimef163.41.81.6
ruNNtimef324.12.52.3
ruNNtime, tjs pluginf165.53.54.2
transformers.jsfp327.87.010.8
transformers.jsfp166.85.07.9
transformers.jsq46.97.010.6

EmbeddingGemma 2 on text, images, audio and video. ruNNtime runs the f16 weights in half precision, its default, and the f32 weights. transformers.js runs the fp32 ONNX export, its WebGPU default, plus the fp16, q4 and q4f16 exports. The model is not in the plugin, so there is no plugin row.

1000 paragraphs in batches of 1, 8 and 32 paragraphs per call.

Higher is better.

  • ruNNtime40.5/s
  • transformers.js fp3210.2/s
  • transformers.js q49.2/s

Higher is better.

  • ruNNtime27.6/s
  • transformers.js fp3217.7/s
  • transformers.js fp1623.7/s
  • transformers.js q417.1/s
  • transformers.js q4f1620.5/s

Paragraphs per second.

EnginePrecisionBatch 1Batch 8Batch 32
ruNNtimef1627.639.840.5
ruNNtimef3220.526.026.6
transformers.jsfp3217.714.310.2
transformers.jsfp1623.721.916.2
transformers.jsq417.112.99.2
transformers.jsq4f1620.518.713.9

At batch 32, the transformers.js fp16 and q4f16 vectors do not match ruNNtime’s, so those two cells are not in the chart.

The first 100 COCO photos, one photo per call.

Higher is better.

  • ruNNtime1.73/s
  • transformers.js fp321.01/s
  • transformers.js fp161.52/s
  • transformers.js q40.95/s
  • transformers.js q4f161.35/s
EnginePrecisionms per imageImages per second
ruNNtimef165761.73
ruNNtimef327891.27
transformers.jsfp329851.01
transformers.jsfp166561.52
transformers.jsq410440.95
transformers.jsq4f167391.35

500 LibriSpeech clips, 66 minutes of speech, one clip per call.

Seconds of audio embedded per second. Higher is better.

  • ruNNtime69.5×
  • transformers.js fp3242.9×
  • transformers.js fp1661.9×
  • transformers.js q442.3×
  • transformers.js q4f1652.8×
EnginePrecisionms per clipClips per second× realtime
ruNNtimef1694.98.8169.5
ruNNtimef32134.76.4350.8
transformers.jsfp32159.35.4442.9
transformers.jsfp16109.07.8461.9
transformers.jsq4157.45.3642.3
transformers.jsq4f16131.06.6852.8

40 Wikimedia Commons clips, 4 to 14 s each, one frame per second, one clip per call.

Higher is better.

  • ruNNtime0.45/s
  • transformers.js fp320.23/s
  • transformers.js fp160.34/s
  • transformers.js q40.20/s
  • transformers.js q4f160.31/s
EnginePrecisionms per clipClips per second
ruNNtimef1622860.45
ruNNtimef3233350.30
transformers.jsfp3242610.23
transformers.jsfp1630620.34
transformers.jsq451190.20
transformers.jsq4f1633290.31

MobileNetV4 on 500 COCO photos, one photo per call, pixels in to class names out. ruNNtime runs the f16 weights, its only precision. transformers.js runs the fp32 ONNX export, its WebGPU default, plus the fp16 and q4 exports. Through the plugin, ruNNtime keeps transformers.js’s image preprocessing, which is most of that row’s time.

Higher is better.

  • ruNNtime407 fps
  • ruNNtime, tjs plugin109 fps
  • transformers.js fp3295 fps
  • transformers.js fp1696 fps
  • transformers.js q496 fps
EnginePrecisionms per imageFPS
ruNNtimef162.4407
ruNNtime, tjs pluginf169.0109
transformers.jsfp3210.195
transformers.jsfp169.996
transformers.jsq410.096

DepthART on 500 COCO photos, one photo per call, pixels in to a depth map out. ruNNtime runs the f16 weights, its only precision. Through the plugin, ruNNtime runs DepthART with transformers.js’s image preprocessing, which is most of that row’s time.

Higher is better.

  • ruNNtime74.0 fps
  • ruNNtime, tjs plugin23.0 fps
EnginePrecisionms per imageFPS
ruNNtimef1613.374
ruNNtime, tjs pluginf1641.423

YOLO26 on 500 COCO photos, one photo per call, pixels in to boxes out, in the n, s and m sizes. ruNNtime runs the f16 weights, its only precision. transformers.js runs the ONNX export of the same model in fp32, its WebGPU default, plus the fp16 and q4 exports.

Higher is better.

  • ruNNtime n77.1 fps
  • transformers.js n fp3224.7 fps
  • transformers.js n fp1625.9 fps
  • transformers.js n q424.3 fps
  • ruNNtime s43.6 fps
  • transformers.js s fp3219.5 fps
  • transformers.js s fp1621.1 fps
  • transformers.js s q419.9 fps
  • ruNNtime m25.1 fps
  • transformers.js m fp3211.8 fps
  • transformers.js m fp1614.3 fps
  • transformers.js m q411.9 fps
ModelEnginePrecisionms per imageFPS
nruNNtimef1612.977.1
ntransformers.jsfp3240.924.7
ntransformers.jsfp1638.125.9
ntransformers.jsq442.124.3
sruNNtimef1622.743.6
stransformers.jsfp3248.919.5
stransformers.jsfp1643.421.1
stransformers.jsq449.119.9
mruNNtimef1639.825.1
mtransformers.jsfp3284.911.8
mtransformers.jsfp1669.514.3
mtransformers.jsq483.711.9

The transformers.js rows run the same model and the same compute, but their boxes are wrong: the ONNX export’s config makes transformers.js score classes with softmax instead of sigmoid, so it keeps about 96 boxes per image where ruNNtime finds 4.5.

YOLO26 pose and YOLO26 segment on the same 500 COCO photos, one photo per call, in the n, s and m sizes. ruNNtime runs the f16 weights, its only precision. transformers.js has no pipeline for these models, so there is no row to compare with.

Higher is better.

  • ruNNtime n72.0 fps
  • ruNNtime s44.0 fps
  • ruNNtime m24.6 fps

Higher is better.

  • ruNNtime n60.3 fps
  • ruNNtime s34.1 fps
  • ruNNtime m16.4 fps

Pose:

ModelEnginePrecisionms per imageFPS
nruNNtimef1613.672.0
sruNNtimef1622.744.0
mruNNtimef1640.624.6

Instance segmentation:

ModelEnginePrecisionms per imageFPS
nruNNtimef1616.460.3
sruNNtimef1629.134.1
mruNNtimef1660.916.4

Privacy filter on 300 short messages with personal data, 9 to 76 words each, one message per call, text in to labelled spans out. ruNNtime runs the int8 weights, its only precision. transformers.js runs the ONNX exports of the same model in q4 and q4f16. Its q8 export finds almost none of the spans on WebGPU, so it is left out. Through the plugin, ruNNtime keeps transformers.js’s tokenizer.

Higher is better.

  • ruNNtime61.4/s
  • ruNNtime, tjs plugin62.1/s
  • transformers.js q413.3/s
  • transformers.js q4f1614.0/s
EnginePrecisionms per textTexts per second
ruNNtimeint816.461.4
ruNNtime, tjs pluginint816.262.1
transformers.jsq476.413.3
transformers.jsq4f1672.014.0
  • Machine: MacBook Pro, Apple M2 Pro, 16 GB, headless Chromium 156, WebGPU on Metal. Measured October 27 and 28, 2026.
  • Setup: ruNNtime as in Getting started, with subgroups and shader-f16, the hosted weights. transformers.js 4.3.1, device: 'webgpu', the onnx-community, Xenova and openai ONNX exports at the row’s dtype.
  • Timing: one engine loaded at a time, every input runs once untimed first. Reported numbers are medians.
  • Speech to text: the first 500 utterances of LibriSpeech test-clean, 65.8 minutes, 1.4 to 31.6 s per clip, 16 kHz mono, the same samples for every engine. Each clip is timed once, samples in to text out. × realtime is audio seconds over seconds taken, median over the 500 clips. ms per token is decode time over tokens produced, median over clips. Every transcript is checked against the reference.
  • Text embedding: the 1000 distinct paragraphs of SQuAD v1.1 dev, Wikipedia text, capped at 512 tokens, the same for every engine. Two passes per batch size, text in to unit-length vectors out. Paragraphs per second is the whole set over the time it took. ms per paragraph is the median call time over the batch size. Every vector is checked against the ruNNtime f32 output.
  • EmbeddingGemma 2: text as above, the first 100 COCO val2017 photos, the 500 LibriSpeech clips from speech to text, and 40 Wikimedia Commons clips of 4 to 14 s sampled at one frame per second, the same inputs for every engine. One input per call for images, audio and video. Every vector is checked against ruNNtime’s.
  • Vision tasks: image classification, depth estimation, object detection, pose and instance segmentation run on the first 500 COCO val2017 photos under a license that allows reuse, 69k to 410k pixels each, decoded once, the same for every engine. Four passes, RGBA pixels in, the task’s result out at each engine’s default threshold. FPS is the whole set over the time it took. ms per image is the median call time. Every result is checked against ruNNtime’s.
  • Privacy filter: 300 English messages, 9 to 76 words, with names, emails, phones, addresses, dates, URLs, account numbers and secrets, the same for every engine. Four passes, text in to labelled spans out. Texts per second is the whole set over the time it took. ms per text is the median call time. Every span set is checked against ruNNtime’s.