Tu codes avec l’IA ?
Outils, agents et nouveautés dev IA décryptés, chaque soir en 5 min. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisis ton rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
Découverte de Moebius sur Hacker News
Ce matin, en parcourant Hacker News, j'ai découvert un modèle d'inpainting d'image nommé Moebius : 0.2B Lightweight Image Inpainting Framework. Ce modèle, bien que léger, promet des performances comparables à celles de modèles bien plus volumineux, atteignant le niveau 10B. Il est conçu pour permettre aux utilisateurs de sélectionner des zones d'une image à supprimer, puis de générer ce qui devrait remplir l'espace vide. Initialement, le modèle nécessitait l'utilisation de PyTorch et NVIDIA CUDA. Cependant, intrigué par sa description en tant que modèle 0.2B, j'ai décidé de tenter de le faire fonctionner via WebGPU dans un navigateur. Après quelques essais, j'ai réussi, et vous pouvez désormais essayer la démo sur simonw.github.io/moebius-web/.
Présentation de l'outil finalisé
Une vidéo de démonstration est disponible pour illustrer le fonctionnement de l'outil finalisé. Vous pouvez charger n'importe quelle image, même si elle n'est pas carrée, car elle sera ajustée automatiquement. Ensuite, il suffit de mettre en surbrillance les zones que vous souhaitez supprimer, de cliquer sur le bouton "Run inpaint" et d'attendre que le modèle fasse son travail.
Un projet parallèle avec Datasette
Mon projet principal de la journée était de finaliser une fonctionnalité majeure dans Datasette : une interface utilisateur pour créer et modifier des tables. Cela faisait suite à la fonctionnalité d'insertion et d'édition de lignes que j'avais publiée la semaine précédente. Je travaillais sur ce projet dans Codex Desktop et passais souvent 5 à 10 minutes à attendre que le système termine un refactoring de taille moyenne ou ajoute les touches finales à un changement de l'interface utilisateur.
Exploration avec Claude Code
Pendant ces périodes d'attente, j'ai décidé de lancer Claude Code dans une fenêtre de terminal pour voir jusqu'où je pouvais aller pour porter Moebius sur le web. Ma première étape a été de demander à Claude la faisabilité de ce projet. Dans Claude.ai, qui a la capacité de cloner des dépôts depuis GitHub, j'ai demandé :
- Clone https://github.com/hustvl/Moebius/ et dis-moi s'ils ont publié le code et les poids pour exécuter ce modèle quelque part.
- Pour Moebius, quelles sont les options pour l'exécuter en ce moment - uniquement Python et NVIDIA CUDA ou d'autres options aussi ?
- Réfléchis à la faisabilité de le porter sur Transformers.js ou similaire et de l'exécuter dans un navigateur.
J'ai l'habitude de demander aux modèles de "réfléchir à X", car c'est une manière concise d'exprimer que je souhaite qu'ils considèrent un problème sans leur fournir un objectif concret. Claude a suggéré d'utiliser ONNX Runtime Web sur le backend WebGPU, une solution plus adaptée que la bibliothèque Transformers.js que j'avais initialement envisagée.
Mise en place du projet
Convaincu par cette approche, j'ai décidé de poursuivre le projet. J'ai commencé par rassembler autant d'informations que possible dont l'agent de codage pourrait avoir besoin. Comme je ne m'attendais pas à ce que ce projet fonctionne réellement, j'ai tout fait dans mon dossier /tmp :
- Récupérer le code Python de Moebius
git clone https://github.com/hustvl/Moebius - Et les poids du modèle (Claude a compris cela) :
GIT_LFS_SKIP_SMUDGE=0 git clone https://huggingface.co/hustvl/Moebius Moebius-weights - Enfin, quelques bibliothèques que nous pourrions utiliser :
git clone https://github.com/huggingface/transformers.js git clone https://github.com/microsoft/onnxruntime
Lancement de Claude Code
J'ai créé un répertoire pour le reste du projet et exécuté git init afin que Claude puisse commencer à enregistrer des notes de code :
mkdir /tmp/Moebius/moebius-web
cd /tmp/Moebius/moebius-web
- Copier le research.md de plus tôt
git add research.md git commit -m "Recherche initiale par Claude Opus 4.8"
J'ai lancé une instance de Claude dans le dossier /tmp/Moebius, le niveau au-dessus de tous les matériaux de recherche que j'avais préparés pour lui. Je l'ai incité :
- Lis ./moebius-web/research.md - ton objectif est de porter ce modèle sur ONNX et WebGPU afin que nous puissions l'exécuter directement dans un navigateur, avec une interface utilisateur simple.
Alors qu'il commençait à travailler, j'ai ajouté ce suivi (fautes incluses) :
- Construis cela dans /tmp/Moebius/moebius-web et engage souvent, maintiens également un fichier notes.md là-dedans avec des notes sur ce que tu découvres en cours de route - commence aussi par rédiger un plan.md là-dedans et mets à jour ce plan au fur et à mesure de ton travail.
Je demande souvent aux agents de garder des notes comme ça—le résultat final est souvent intéressant, tant pour moi que pour la prochaine session d'agent qui touche le même projet. Voici à quoi ressemblait ce fichier notes.md à la fin du projet.
Publication sur Hugging Face
Comment publier cela sur Hugging Face de manière à ce que les poids du modèle y soient et que la démo HTML apparaisse dans les espaces Hugging Face ? Claude Code sait utiliser l'outil hf CLI, donc j'ai créé un dépôt de modèle sur Hugging Face, puis créé un token qui pouvait écrire dans ce dépôt et l'ai placé dans un fichier /tmp/Moebius/token.txt pour que Claude puisse l'utiliser.
Il a publié les 1.24 Go de poids ONNX convertis sur huggingface.co/simonw/Moebius-ONNX pour moi. J'avais déjà vu d'autres démos charger des poids dans le navigateur depuis Hugging Face, donc je savais que c'était possible. J'ai décidé d'héberger mon propre code frontend sur GitHub Pages, donc j'ai dit :
- Je veux publier le dossier moebius-web sur GitHub, à l'exception des fichiers volumineux (donc peut-être à l'exception du dossier models/), de manière à ce que lorsque j'active GitHub Pages pour ce dépôt, naviguer vers https://simonw.github.io/moebius-web/ serve l'interface utilisateur.
Indiquer l'URL finale était important au cas où il aurait besoin de corriger les URLs dans les démos qu'il construisait afin qu'elles fonctionnent lors du déploiement en production.
Optimisation du chargement
Après quelques autres itérations, entre le travail sur mon projet principal, nous avons obtenu une version déployée et fonctionnelle ! Sauf que... chaque fois que je rechargeais la page, il semblait télécharger environ 1.3 Go de poids de modèle. Le cache du navigateur semblait très important pour cela !
- Y a-t-il quelque chose d'intelligent que nous pouvons faire avec les service workers ou similaire pour aider à mettre en cache ces éléments ? Il semble que cela se recharge à chaque fois, je suis préoccupé par le fait qu'il pourrait y avoir quelque chose de bizarre dans la façon dont les redirections HF fonctionnent qui signifie que nous ne bénéficions pas du cache du navigateur.
Je savais que les projets Transformers.js pouvaient gérer cela correctement, donc j'ai pris une copie de la démo Whisper Web, l'ai placée dans /tmp/Moebius/whisper-web et j'ai dit :
- Regarde dans /tmp/Moebius/whisper-web (avec un sous-agent) et vois comment ils font cela.
Ce projet était entièrement obfusqué, construit à partir de fichiers JavaScript, donc j'ai pensé qu'utiliser un sous-agent éviterait de passer le reste de mon contexte de token de niveau supérieur à déchiffrer ces fichiers.
Claude a compris qu'il utilisait caches.open("transformers-cache")—l'API CacheStorage—et a ajouté cela à notre projet.
Réflexions finales
Cela compte définitivement comme du vibe coding : je n'ai pas regardé une seule ligne de code du projet, restreignant mon input à des tests, à la suggestion de petites améliorations de fonctionnalités (comme une barre de progression pour les téléchargements de fichiers volumineux) et à orienter le modèle dans la direction d'exemples de la façon dont je voulais que les choses fonctionnent.
Comme je n'ai pas écrit de code, la quantité que j'ai apprise sur les technologies sous-jacentes—WebGPU, ONNX, et le modèle Moebius lui-même—était très limitée. Comme c'est souvent le cas avec ce genre de projet, les choses les plus importantes que j'ai apprises concernaient ce qui était possible :
-
Claude Opus 4.8 est capable de convertir un modèle PyTorch en ONNX, de publier le résultat sur Hugging Face et ensuite de construire une application web et une interface qui peuvent charger et exécuter ce modèle.
-
Chrome, Firefox et Safari sont tous maintenant capables d'exécuter ce genre de modèle—je l'ai essayé dans les trois.
-
L'API CacheStorage fonctionne avec des fichiers de modèle d'environ 1.3 Go.
... ce qui signifie que nous pouvons avoir l'inpainting comme fonctionnalité d'une application web uniquement client ! (Si nos utilisateurs peuvent tolérer le téléchargement de 1.3 Go.)
J'ai eu l'impression que je devrais probablement essayer d'en apprendre un peu plus sur mon projet. J'ai lancé Claude.ai et l'ai incité :
- Clone https://github.com/simonw/moebius-web/ et utilise-le pour m'apprendre tout sur le modèle et ONNX et le processus de conversion d'un modèle en ONNX et WebGPU et fondamentalement tout ce que j'aurais besoin de savoir pour comprendre pleinement ce dépôt.
Voici la transcription et le fichier understanding.md en Markdown qu'il a créé, que j'ai maintenant ajouté au dépôt GitHub. J'ai trouvé l'explication d'ONNX particulièrement éclairante :
ONNX (Open Neural Network Exchange) est un format de fichier portable et neutre pour les réseaux de neurones. Un fichier .onnx est essentiellement deux choses regroupées :
-
Un graphe de calcul — un graphe dirigé de nœuds, où chaque nœud est un opérateur (Conv, MatMul, Add, Einsum, Softmax, Gather, Resize, …) reliés par des tenseurs nommés qui circulent entre eux. C'est la "recette" pour le passage avant.
-
Les poids — les tenseurs de paramètres appris (les noyaux de convolution, la table d'embedding, etc.), stockés comme initialisateurs dans ce même graphe.
De manière cruciale, ONNX décrit ce qu'il faut calculer, de manière abstraite, sans dire comment ou sur quel matériel. L'ensemble d'opérateurs est versionné par un numéro d'opset (ce dépôt utilise l'opset 18), ce qui précise exactement quels opérateurs existent et quelles sont leurs sémantiques.
Il s'avère que PyTorch a des mécanismes intégrés pour exporter vers ONNX, comme on le voit ici dans export_onnx.py :
torch.onnx.export(
dec, (lat,), dec_path, opset_version=args.opset,
input_names=["latent"], output_names=["image"],
dynamic_axes={"latent": {0: "B"}, "image": {0: "B"}},
)
Claude a également inclus un glossaire pratique et un diagramme en ASCII à peine cassé montrant comment le pipeline du modèle s'articule.





