On descend d'un cran : #002.1 complément, l'Arc en f16
Ce complément prolonge l'article #002 le même compilateur sur un GPU, publié le 18 octobre, que je ne modifie pas. Il y avait un cas où Herbert perdait nettement : le GPU Arc 140V d'un portable Core Ultra 7 258V, en f16 contre f16. Au prefill sur 759 tokens, Herbert faisait ×0,89 de llama.cpp Vulkan sur Qwen3.5-0.8B et ×0,57 sur le 4B. J'écrivais que ses multiplications de matrices ne tiraient pas tout de la carte, que je n'avais pas encore eu le temps de chercher pourquoi, mais que ça allait me plaire.
Ça m'a plu.
Ce qui a changé
Trois choses, toutes propres à cette carte.
Les matrices que la carte sait faire. Sous le pilote Mesa ANV, les unités matricielles de l'Arc 140V ne proposent qu'une forme : des tuiles de 8 × 16 × 16 en f16, sur des sous-groupes de 16 invocations. Les noyaux d'Herbert attendaient les tuiles de 16 × 16 × 16 sur 32 invocations des cartes NVIDIA et AMD. Faute de les trouver, l'attention du prefill retombait ici sur des noyaux qui n'utilisaient pas du tout les unités matricielles. Elle travaille maintenant sur des tuiles de 8 lignes, la forme que la carte offre.
La taille des tuiles. C'est le gros du gain. Une multiplication de matrices se découpe en blocs : chaque groupe de travail calcule un bloc de la sortie, et charge pour cela une bande de chacune des deux matrices d'entrée. Plus le bloc est grand, plus chaque valeur chargée sert à de calculs. Sur cette carte, Herbert calculait des blocs de 32 × 64 sorties par groupe de 64 invocations : 2 048 sorties pour 96 lignes et colonnes lues à chaque pas. Il calcule maintenant des blocs de 128 × 128 par groupe de 512 invocations : 16 384 sorties pour 256 lignes et colonnes lues, soit trois fois plus de calcul par valeur lue. Le bloc de sortie ne tient plus dans les 48 Kio de mémoire partagée du groupe, alors les résultats s'écrivent directement depuis les accumulateurs.
J'ai mesuré 31 découpages sur la carte avant de retenir celui-là. Chacun des 32 sous-groupes y porte 2 × 2 matrices. Au-delà, le débit tombe à moins de la moitié. Un bloc encore plus grand, 256 × 128, gagne 6 % sur un modèle et en perd 6 sur un autre. Le découpage retenu a la même forme que celui de llama.cpp sur cette carte.
Un défaut trouvé en route. Le chemin qui écrit directement depuis les accumulateurs existait déjà, mais il n'était pas utilisé par défaut. Il cachait un défaut : la projection du Gated DeltaNet de Qwen3.5 fait 8 224 colonnes, ce qui n'est pas un multiple de 128, et les dernières matrices de chaque ligne atterrissaient sur la ligne suivante. C'est corrigé : Qwen redonne exactement les mêmes tokens qu'avec l'ancienne écriture.
Les chiffres
Même carte, mêmes prompts, même protocole que la campagne d'octobre, cinq tours alternés, f16 contre f16. En face, le llama.cpp de l'article, 08ffba21e, à son meilleur réglage, et celui du 2 novembre, 4e910a86e, à son réglage par défaut.
| prefill sur 759 tokens, f16 contre f16, tokens par seconde | Herbert, 2 novembre | llama.cpp du 2 novembre | Herbert / llama.cpp du 2 novembre | llama.cpp de l'article | Herbert / llama.cpp de l'article | Herbert / llama.cpp, le 18 octobre |
|---|---|---|---|---|---|---|
| Arc 140V, 0.8B | 4 113 | 2 629 | ×1,56 | 2 216 | ×1,86 | ×0,89 |
| Arc 140V, 4B | 804 | 619 | ×1,30 | 594 | ×1,35 | ×0,57 |
Sur le 4B, Herbert passe de 328 à 804 tokens par seconde. Le llama.cpp de l'article redonne ses vitesses d'octobre, 573 tokens par seconde à son réglage par défaut. Celui du 2 novembre a gagné de 8 à 19 % : Herbert reste devant.
Au client commun, sur le 4B à 4 105 tokens, en f16, Herbert donne maintenant son premier token en 7,75 s, contre 17,5 s le 18 octobre. llama.cpp du 2 novembre le donne en 10,70 s, celui de l'article en 11,14 s. Ce sont des médianes de 15 requêtes. Au décodage, rien ne change.
Une précision que je n'avais pas écrite
Sur cette carte, pour des poids en f16, llama.cpp accumule ses produits de matrices en f16 (matmul_f16_f16acc). Herbert accumule en f32. « f16 contre f16 » veut donc dire les mêmes poids et les mêmes activations, avec un accumulateur plus précis du côté d'Herbert. Les deux fichiers GGUF sont en F16, sans aucun tenseur quantifié.
Les limites
Cette mesure ne vaut que pour l'Arc 140V, sous Mesa 26.0.8 et le noyau Linux 7.0.0. Le code mesuré est la version 0.2.0 de herbert-vk-f16 (tag v0.2.0), publiée avec ce complément. Avant de la publier, je l'ai repassée en non-régression : sur la RTX 4080 et les deux GPU intégrés AMD, elle donne les mêmes tokens que la version de l'article, partout où le chemin de calcul n'a pas changé. Le reste de l'article #002 tient tel qu'il est publié, y compris les cas où Herbert est à égalité ou plus lent : le 4B sur la RTX 4080 face au meilleur réglage de llama.cpp, et le 4B sur les GPU intégrés AMD.
On descend d'un cran, ou plusieurs...
- On descend d'un cran : #000 un moteur d'inférence qui écrit son propre code · 03-oct-2026
- On descend d'un cran : #001 un compilateur pour moteur de LLM · 11-oct-2026
- On descend d'un cran : #002 le même compilateur sur un GPU · 18-oct-2026
- On descend d'un cran : #002.1 complément, l'Arc en f16 · 02-nov-2026
- On descend d'un cran : #003 ce que CUDA a et que Vulkan n'a pas · 25-oct-2026
- On descend d'un cran : #004 le même compilateur sur les puces d'Apple · 01-nov-2026