PyTorch-модель inpainting — в браузер за один день: как это сделал Claude Code
Как перенести PyTorch-модель inpainting в браузер без сервера: конвертация в ONNX, WebGPU-бэкенд, публикация весов на Hugging Face. Пошаговый гайд.

Саймон Уиллисон увидел Moebius на Hacker News утром и к вечеру уже запустил его в Chrome — без сервера, без CUDA, прямо в браузере. Если у вас есть небольшая PyTorch-модель и желание раздать её пользователям без бэкенда, этот гайд покажет, как устроен весь путь.
Почему именно Moebius и почему это вообще реально
Moebius (ECCV 2026) — модель inpainting весом 0.22B параметров. Inpainting — это когда вы закрашиваете область на фото, а модель дорисовывает, что там должно быть. Оригинальный репозиторий требовал PyTorch и NVIDIA CUDA, то есть запустить его мог только тот, у кого есть GPU-машина или платный облачный инстанс.
0.22B — это примерно 220 миллионов параметров. Для сравнения: GPT-2 small — 117M. Такой размер уже позволяет надеяться на WebGPU: браузерный API для работы с GPU, который поддерживают Chrome и Edge начиная с 2023 года. Именно это и решил проверить Уиллисон.
Подготовка: что нужно собрать до старта агента
Прежде чем запускать Claude Code, Уиллисон собрал все нужные материалы в одном месте. Агент работает лучше, когда у него под рукой есть исходники, веса и библиотеки — а не только URL.
```bash cd /tmp mkdir Moebius && cd Moebius
Исходный код модели
git clone https://github.com/hustvl/Moebius
Веса модели через Git LFS (флаг GIT_LFS_SKIP_SMUDGE=0 обязателен, иначе LFS-файлы не скачаются)
GIT_LFS_SKIP_SMUDGE=0 git clone \ https://huggingface.co/hustvl/Moebius Moebius-weights
Библиотеки для ориентации агента
git clone https://github.com/huggingface/transformers.js git clone https://github.com/microsoft/onnxruntime ```
Параллельно он спросил Claude.ai (с возможностью клонировать репозитории) о feasibility: можно ли портировать Moebius в Transformers.js или что-то похожее. Ключевая фраза в промпте — «muse on the feasibility» — просит модель порассуждать без конкретной цели, и это работает лучше, чем «сделай план».
Claude предложил использовать ONNX Runtime Web с WebGPU-бэкендом — уровень ниже Transformers.js, более гибкий. Этот ответ был сохранён в research.md и передан Claude Code как стартовый контекст.
Запуск Claude Code: промпты, которые реально работали
``bash mkdir /tmp/Moebius/moebius-web cd /tmp/Moebius/moebius-web git init git add research.md git commit -m "Initial research by Claude Opus 4.8" ``
Claude Code запускался из /tmp/Moebius — на уровень выше, чтобы видеть все подготовленные материалы. Первый промпт:
`` Read ./moebius-web/research.md - your goal is to port this model to ONNX and WebGPU so we can run it directly in a browser, with a simple UI ``
Второй промпт (с опечатками, как в оригинале — агент справился):
`` Build this in /tmp/Moebius/moebius-web and commit early and often, also maintain a notes.md file in there with notes about what you figure out along the way - also start by writing out a plan.md in there and update that plan as you work too ``
Два важных паттерна здесь: просьба коммитить часто (история помогает откатиться) и вести notes.md + plan.md. Эти файлы потом становятся контекстом для следующей сессии с агентом.
Конвертация весов и публикация на Hugging Face
Claude Code самостоятельно разобрался с конвертацией весов PyTorch → ONNX и опубликовал 1.24 ГБ ONNX-весов на Hugging Face. Для этого понадобился токен с правом записи в репозиторий:
```bash
Токен сохраняется в файл, чтобы агент мог его использовать
echo "hf_xxxxxxxxxxxxxxxxxx" > /tmp/Moebius/token.txt ```
Веса опубликованы по адресу huggingface.co/simonw/Moebius-ONNX. Браузерные демо умеют загружать файлы прямо с Hugging Face через обычный fetch — это стандартная практика для WebML-проектов.
Фронтенд (HTML + JS с ONNX Runtime Web) публиковался на GitHub Pages. При этом важно было явно указать агенту финальный URL:
`` I want to publish the moebius-web folder to GitHub, minus the large files (so maybe minus the models/ folder), such that when I turn on GitHub Pages for that repo navigating to https://simonw.github.io/moebius-web/ serves the UI ``
Финальный URL в промпте критичен: агент подставляет его в конфиги и пути к ресурсам, иначе в продакшне всё ломается из-за неправильных относительных путей.
Как устроен финальный инструмент
Рабочее демо живёт на simonw.github.io/moebius-web/. Пользователь открывает любое изображение (не квадратные добавляют letterbox-поля), рисует маску поверх области, которую нужно удалить, нажимает «Run inpaint» — и модель заполняет выделенное.
Стек целиком браузерный:
- ONNX Runtime Web — исполнение модели
- WebGPU backend — аппаратное ускорение через GPU пользователя
- GitHub Pages — хостинг HTML/JS
- Hugging Face — хостинг весов (1.24 ГБ ONNX)
Никакого сервера, никаких API-ключей, никаких расходов на инференс.
Где ломается
Кеширование весов. После первого запуска модель каждый раз заново скачивала 1.24 ГБ при перезагрузке страницы. Это типичная проблема браузерных ML-демо — нужно явно настраивать кеш через Cache API или Service Worker, иначе пользователи будут ждать загрузки при каждом визите.
WebGPU поддерживается не везде. Chrome и Edge на десктопе — работает. Firefox — нет (по состоянию на середину 2026 года WebGPU там в экспериментальном статусе). Safari — частично. На мобильных устройствах поддержка непредсказуема.
Размер весов. 1.24 ГБ — это много для браузера. Модель 0.2B в ONNX получается заметно тяжелее, чем можно ожидать от «маленькой» модели. Для продакшн-сценариев стоит смотреть в сторону квантизации (INT8/INT4 через ONNX Runtime).
LFS при клонировании. Без флага GIT_LFS_SKIP_SMUDGE=0 веса не скачиваются — получаете только указатели. Это неочевидно и ломает весь последующий процесс конвертации.
Что попробовать дальше
Если хотите повторить этот подход со своей моделью — начните с проверки размера: меньше 500M параметров обычно реально запустить в WebGPU. Следующие шаги: изучите ONNX Runtime Web и примеры в репозитории microsoft/onnxruntime, посмотрите на квантизацию весов для уменьшения размера загрузки, и настройте Cache API для весов — без этого демо неудобно использовать повторно.