Modèle / jeu de données
cactus-compute/cactus avatar
cactus-compute/cactus

Cactus : une pile d'inférence edge complète, du noyau ARM au handoff cloud

Quantization, kernels, runtime and inference engine for mobiles, wearables, smart home and robots.

6 017 étoiles502 forksC++NOASSERTION

En bref

De quoi s’agit-il ?
Cactus empile quantification, noyaux CPU/GPU, graphe de calcul et API compatible OpenAI dans un seul dépôt C++. La documentation est dense mais inégale, et la licence n'est pas identifiée par GitHub.
À qui s’adresse-t-il ?
Cactus convient aux équipes qui embarquent déjà du C ou du C++ sur ARM et qui acceptent de convertir leurs poids avec cactus convert plutôt que de partir d'un format déjà pris en charge. Il ne convient pas à qui veut du Python pur ou un modèle servi depuis un serveur.
Puis-je l’utiliser commercialement ?
À vérifier. La licence de ce dépôt n’entre pas dans les catégories que nous classons automatiquement : lisez son fichier LICENSE avant tout usage commercial.
Est-il encore maintenu ?
Oui. Les derniers commits datent d’il y a 7 jours.
En quel langage est-il écrit ?
Principalement C++, d’après les statistiques de langage de GitHub.

Ces réponses reposent sur les données GitHub du projet (dernière synchronisation le 15 septembre 2026) et sur notre analyse. Elles ne constituent pas un avis juridique.

ANALYSE OPEN SOURCE APPROFONDIE

Le problème : faire tenir un transformer sur un téléphone, pas sur un serveur

Cactus vise les appareils où la mémoire vive se compte en centaines de mégaoctets et où le réseau n'est pas garanti : téléphones, montres, domotique, robots. Le dépôt couvre toute la chaîne plutôt qu'une seule couche. La quantification produit des poids compressés, les noyaux ARM NEON les exécutent, le graphe organise les opérations, et le moteur expose le tout derrière une API de complétion. Le README décrit une pile à quatre étages, du moteur jusqu'aux quants. Cette intégration verticale est le vrai argument du projet : on ne branche pas une bibliothèque de quantification sur un runtime existant, on adopte l'ensemble. Le public visé est donc étroit. Il faut écrire du C ou du C++ et savoir lire un fichier d'en-tête. Les bindings Swift, Kotlin, Flutter, React Native, Python et Rust existent, mais ils enveloppent une API C dont la signature ressemble à cactus_init(model_path, rag_path, bool) puis cactus_complete(model, messages, response, size, options, tools, callback, user_data, pcm, pcm_size). Dix paramètres, dont quatre pointeurs nullables dans l'exemple du README. Ce n'est pas une interface conçue pour être découverte par tâtonnement.

Quatre couches, un flux qui va du fichier de poids au JSON de réponse

Le chemin est lisible dans le README. cactus_init reçoit un dossier de poids et, en deuxième argument, soit un fichier texte soit un répertoire de textes pour l'auto-RAG. Le troisième argument est un booléen non documenté dans l'extrait fourni. Ensuite cactus_complete prend un tableau JSON de messages au format chat, un tampon de sortie de taille fixe, une chaîne d'options JSON, et une série de pointeurs optionnels pour les outils, le streaming, les données utilisateur et un tampon audio PCM. La réponse n'est pas du texte brut : c'est un objet JSON qui contient le texte, mais aussi cloud_handoff, function_calls, segments, confidence, confidence_threshold, et une série de compteurs (time_to_first_token_ms, prefill_tps, decode_tps, ram_usage_mb). Le champ confidence associé à confidence_threshold est le point d'articulation de Cactus Hybrid : quand la confiance locale passe sous le seuil résolu, la requête part vers le cloud et cloud_handoff vaut true. Le seuil est décrit comme dépendant du modèle. Sous le moteur, Cactus Graph expose une construction explicite : graph.input avec une forme et une Precision, puis matmul, transpose, set_input, execute, get_output, hard_reset. Le README qualifie ce graphe de zéro-copie. C'est là que se joue la différence avec un framework de tenseurs classique : les données saisies via set_input sont censées ne pas être recopiées avant exécution.

Mise en route : une commande Homebrew, puis cactus run

Sur Mac, le README donne deux étapes. brew install cactus-compute/cactus/cactus, puis cactus run. La commande run accepte un nom de modèle HuggingFace et le télécharge ou le convertit s'il est absent. Pour un modèle absent du catalogue, cactus convert [HF-Name] fait la conversion, que le README qualifie explicitement d'expérimentale. Les familles Liquid, Gemma, Whisper, Parakeet et Qwen sont décrites comme particulièrement testées, ce qui laisse entendre que le reste est plus incertain. cactus download [HF-Name] récupère les modèles déjà publiés sur le compte HuggingFace de l'organisation. Pour mesurer, cactus benchmark, avec les options --ios ou --android. Le modèle de tool calling maison s'obtient avec cactus run Cactus-Compute/needle --tools my_tools.json, au format de function calling d'OpenAI. Les benchmarks publiés couvrent Mac M5 Max, M4 Pro, M3 Pro, iPad et Vision Pro M5, iPhone 17 Pro et iPhone 15 Pro, avec des chiffres de prefill et de decode en tokens par seconde, plus le pic de RAM sur un contexte de 1k. Le README précise que ces mesures se font sans speculative decode ni MTP.

La quantification CQ : ce que les tableaux de précision disent vraiment

Cactus Quants est décrit comme une technique de quantification par rotation et codebook, du 4 bits au 1 bit, appliquée à tous les tenseurs de poids. Le README publie un tableau de qualité de sortie sur Gemma-4-E2B-it, moyenné sur trois graines, avec deux familles : CQ2, CQ3 et CQ4 uniformes, CQ3.26 et CQ2.54 en précision mixte. C'est le passage le plus utile du dépôt, parce qu'il montre où la compression casse. En CQ4, les écarts avec le F16 sont faibles sur la plupart des tâches, et HumanEval monte même de 54,88 à 57,11, ce qui suggère un bruit de mesure plutôt qu'un gain réel. En CQ3.26, GSM8K tombe de 73,67 à 66,20 et HumanEval de 54,88 à 53,66. En CQ2.54, l'effondrement est net : GSM8K à 22,00, HumanEval à 15,24, BFCL Parallel à 30,00. En CQ2 uniforme, GSM8K atteint 0,40 et HumanEval 1,02. Autrement dit, les tâches de raisonnement et de code sont les premières à céder, bien avant les tâches de connaissance générale comme ARC-E, qui reste à 68,20 en CQ2.54 contre 73,80 en F16. Un déploiement qui repose sur du function calling doit regarder la ligne BFCL Simple : 18,75 en CQ2, contre 92,00 en F16. C'est une chute d'un facteur cinq sur une capacité que le projet met pourtant en avant avec Needle.

Ce que le README ne tranche pas

Trois points restent ouverts à la lecture du matériel fourni. D'abord la licence : GitHub renvoie NOASSERTION, ce qui signifie que l'outil n'a pas su classer le fichier LICENSE. Aucune information sur les obligations de redistribution, sur un usage commercial ou sur une clause de brevet n'est disponible ici. Pour un composant qui finit compilé dans un binaire mobile distribué sur l'App Store ou le Play Store, c'est le premier point à lever, avant même de mesurer les performances. Ensuite le troisième argument de cactus_init, un booléen sans nom dans l'exemple, n'est pas expliqué dans l'extrait fourni. Enfin le README mentionne un fichier docs/cactus_quants.md pour les résultats complets, mais la section « Using this repo » est tronquée, donc la procédure de build depuis les sources, les dépendances et la façon de lier la bibliothèque ne sont pas vérifiables ici. La conversion depuis HuggingFace est par ailleurs annoncée comme expérimentale, ce qui déplace le risque : un modèle qui se convertit sans erreur peut quand même produire des sorties dégradées, et le tableau de qualité ne couvre qu'une seule famille, Gemma-4-E2B-it.

Face à llama.cpp : même cible, découpage différent

Le sujet edge et le tag llamacpp du dépôt rendent la comparaison inévitable. llama.cpp s'est construit autour du format GGUF et d'un écosystème de convertisseurs et de quants largement repris par des outils tiers. On choisit un fichier GGUF déjà publié, on le charge, on exécute. Cactus prend le chemin inverse : il impose sa propre pile de quantification CQ, ses propres noyaux, son propre graphe. En échange, il propose des choses que llama.cpp n'expose pas de la même façon : un graphe de tenseurs avec Precision par entrée, une API de complétion qui renvoie des métriques structurées, un mécanisme de handoff cloud fondé sur un score de confiance, et un modèle de tool calling de 26M paramètres conçu pour l'appareil. La différence pratique se joue au moment du choix du modèle. Avec llama.cpp, la contrainte est de trouver un GGUF adapté. Avec Cactus, la contrainte est de faire passer le modèle par cactus convert, avec le risque que la conversion soit expérimentale, puis d'accepter les chiffres de qualité CQ tels que publiés. Si votre modèle est déjà disponible en GGUF et validé, Cactus vous fait perdre cet acquis.

Coût de maintenance et rythme de publication

Le dépôt a publié v2.0.1 en juillet 2026, v2.1.0 en août, puis v2.2.0 le 8 septembre 2026, jour du dernier push. Trois versions mineures ou correctives en deux mois, sur une bibliothèque C++ qui touche à des noyaux assembleur et à un format de quantification propriétaire. Ce rythme a deux conséquences. La première est que les poids convertis avec une version antérieure peuvent devoir être reconvertis, puisque le format CQ évolue avec les versions. La seconde est que les chiffres du tableau de qualité et ceux du tableau de performances correspondent à un état daté du projet, et qu'aucun historique de compatibilité entre versions de quants n'apparaît dans le matériel fourni. La surface à maintenir est large : quatre couches, six bindings, deux plateformes mobiles plus macOS. Une équipe qui n'a personne pour lire du C++ ARM NEON et du code de quantification dépend entièrement du rythme amont. C'est un coût réel, indépendant de la licence, et qui doit être mis en face du gain de latence obtenu en supprimant l'aller-retour réseau.

Conclusion éditoriale

Cactus convient aux équipes qui embarquent déjà du C ou du C++ sur ARM et qui acceptent de convertir leurs poids avec cactus convert plutôt que de partir d'un format déjà pris en charge. Il ne convient pas à qui veut du Python pur ou un modèle servi depuis un serveur. À vérifier avant tout engagement : le fichier LICENSE réel, puisque GitHub renvoie NOASSERTION, et le contenu de docs/cactus_quants.md pour savoir si CQ4 tient sur votre tâche, sachant que CQ2 fait chuter GSM8K de 73,67 à 0,40.

Sources officielles

  1. cactus-compute/cactus on GitHub
  2. Issues
  3. Project website
  4. README
  5. Releases
Notes de la communauté

Notes de la communauté