Porting the Moebius 0.2B image inpainting model to run in the browser with Claude CodePorting the Moebius 0.2B image inpainting model to run in the browser with Claude Code
Porting the Moebius 0.2B image inpainting model to run in the browser with Claude Code
Simon Willison
2026年6月22日
今天早上在 Hacker News 上,我看到了《Moebius:具有百亿级性能的 2 亿参数轻量级图像修复框架》(Moebius: 0.2B Lightweight Image Inpainting Framework with 10B-Level Performance),它介绍了一个小而高效的图像修复模型——在这个模型中,你可以标记图像中需要移除的区域,然后模型会想象出应该用什么内容来填补空白。发布的模型需要 PyTorch 和 NVIDIA CUDA,但由于它宣称只有 0.2B 参数,我决定尝试使用 WebGPU 在浏览器中运行它。长话短说(TL;DR):我成功让它跑起来了,你可以在 simonw.github.io/moebius-web/ 上试用这个演示。详情请继续往下读。
完成后的工具
这是该工具完成后的视频演示:
你可以在其中打开任何图像(非正方形图像会加上黑边),高亮显示要移除的区域,点击“Run inpaint”按钮,然后等待模型展现它的魔力。
一个平行的智能体副业项目
我今天的主要项目是在 Datasette 中落地一个重要功能:一个用于创建和修改表格的 UI,这是我上周发布的“插入和编辑行”功能的后续。
当时我正在 Codex Desktop 中做这件事(这是对应的 PR),我经常发现自己要花 5 到 10 分钟无所事事地等待它完成中等规模的重构,或者为 UI 的更改做最后的润色。
(关于编程智能体,有一个有趣的现象:问题越难,你在等待它们运算完毕时可以分心的时间就越多!)
于是我决定在终端窗口中启动 Claude Code,看看能把 Moebius 移植到 Web 端推进到什么程度。
启动项目的一些智能体研究
我的第一步是询问常规版 Claude 这个项目的可行性。在 Claude.ai 中,它具备从 GitHub 克隆仓库的能力:
克隆 https://github.com/hustvl/Moebius/ 并告诉我他们是否在任何地方发布了运行此模型的代码和权重
(我当时还没发现权重的链接,它被藏在“News”部分里。)
接着:
对于 Moebius,目前有哪些运行选项——是仅限 Python 和 NVIDIA CUDA,还是有其他选择?
以及:
思考一下将其移植到 Transformers.js 或类似框架并在浏览器中运行的可行性
我喜欢让模型“思考 X(muse on X)”,这是我发现的最简短的表达方式,意在让它们为我深思熟虑一个问题,而不给它们设定具体目标。
这是那次聊天的记录。我复制了最后一个回答并将其保存为 research.md,以便 Claude Code 稍后读取。
Claude 建议在 WebGPU 后端使用 ONNX Runtime Web——这位于我之前建议的 Transformers.js 库的底层。
这足以让我相信,放开手脚让 Claude Code 去做,看看它能进展到哪一步,是值得的。
我通常在启动这类项目时,会尽可能多地收集编程智能体可能需要的信息。因为我本来也没指望这个项目真能成功,所以我所有的操作都在 /tmp 文件夹里进行:
cd /tmp
mkdir Moebius
cd Moebius
# Grab the Moebius python code
git clone https://github.com/hustvl/Moebius
# And the model weights (Claude figured this out):
GIT_LFS_SKIP_SMUDGE=0 git clone \
https://huggingface.co/hustvl/Moebius Moebius-weights
# Finally a couple of libraries we might use:
git clone https://github.com/huggingface/transformers.js
git clone https://github.com/microsoft/onnxruntime启动 Claude Code
我为项目的其余部分创建了一个目录,并在其中运行了 git init,这样 Claude 就可以开始提交代码笔记了:
mkdir /tmp/Moebius/moebius-web
cd /tmp/Moebius/moebius-web
git init
# Copy in that research.md from earlier
git add research.md
git commit -m "Initial research by Claude Opus 4.8"我在 /tmp/Moebius 文件夹中启动了一个 claude 实例,该文件夹位于我为它准备的所有研究材料的上一级。我输入了提示词:
阅读 ./moebius-web/research.md - 你的目标是将此模型移植到 ONNX 和 WebGPU,以便我们可以直接在浏览器中运行它,并提供一个简单的 UI
当它开始工作时,我发去了这条后续指令(包含拼写错误):
在 /tmp/Moebius/moebius-web 目录下构建这个项目,尽早并频繁地提交代码,同时在该目录下维护一个 notes.md 文件,记录你在过程中发现的内容——此外,一开始就在那里写一个 plan.md,并在你工作时不断更新该计划
我经常要求智能体像这样做笔记——最终的结果往往很有趣,无论是对我自己,还是对处理同一项目的下一个智能体会话来说都是如此。以下是项目结束时那个 notes.md 文件的内容。
我启动了任务,然后回到我的主要项目中,偶尔查看一下 Claude 的进展。当看起来它似乎已经做出了可用的东西时,我提示道:
告诉我可以在自己的浏览器中访问哪个 URL 来试用这个
然后我在 Chrome 中进行了测试,并将一些错误(以及错误截图)粘贴回了 Claude Code 中。
经过几轮这样的操作后,我们有了一个看起来可以运行的版本!是时候把它部署到互联网上,以便其他人可以使用了。
我们该如何将这个发布到 Hugging Face,使得模型权重保存在那里,并且 HTML 演示能显示在 Hugging Face Spaces 中?
Claude Code 知道如何使用 hf CLI 工具,所以我在 Hugging Face 上创建了一个模型仓库,然后创建了一个可以写入该仓库的 token,并将其放入 /tmp/Moebius/token.txt 文件中,以便 Claude 使用。
它为我将 1.24GB 转换后的 ONNX 权重发布到了 huggingface.co/simonw/Moebius-ONNX。
我以前见过其他演示从 Hugging Face 将权重加载到浏览器中,所以我知道这是可行的。我决定将自己的前端代码托管在 GitHub Pages 上,所以我说:
我想将 moebius-web 文件夹发布到 GitHub,但不包含大文件(所以也许应该排除 models/ 文件夹),这样当我为该仓库启用 GitHub Pages 时,访问 https://simonw.github.io/moebius-web/ 就能提供 UI 界面
告诉它最终的 URL 很重要,以防它需要修复正在构建的演示中的 URL,从而确保它们在部署到生产环境时能够正常工作。
在处理我的主要项目之余,经过几轮迭代,我们终于得到了一个可以正常运行并部署的版本!
只是……每次我重新加载页面时,似乎都要下载大约 1.3GB 的模型权重。对于这个项目来说,浏览器缓存似乎非常重要!
我们能否利用 Service Workers 或类似技术做一些巧妙的处理来帮助缓存这些内容?它似乎每次都在重新加载,我担心 HF 重定向的工作方式可能有些奇怪,导致我们无法利用浏览器缓存
我知道 Transformers.js 项目能够妥善处理这个问题,所以我复制了一份 Whisper Web 演示,将其放入 /tmp/Moebius/whisper-web 中,并说道:
查看 /tmp/Moebius/whisper-web(使用子代理),看看他们是如何实现这一点的
那个项目完全是混淆过的、构建后的 JavaScript 文件,所以我认为使用子代理可以避免消耗我剩余的顶层 token 上下文去解密这些文件。
Claude 发现它使用了 caches.open("transformers-cache")——即 CacheStorage API——并将该方法添加到了我们的项目中。
我已经分享了这个项目完整的 Claude Code 对话记录(使用我的 claude-code-transcripts 工具发布)。
我从这一切中学到了什么?
这绝对算得上是“vibe coding”:我没有查看项目中哪怕一行代码,而是将我的参与仅限于测试、建议一些小功能的改进(例如为大文件下载添加进度条),并为模型指明我希望其运作方式的示例方向。
由于我没有编写任何代码,所以我对底层技术(WebGPU、ONNX 以及 Moebius 模型本身)的了解非常有限。
正如这类项目的常态一样,我学到的最重要的东西是关于哪些功能是可能实现的:
我觉得我大概应该尝试多了解一下我的项目。于是我打开了 Claude.ai 并输入了以下提示词:
克隆 https://github.com/simonw/moebius-web/ 仓库,并用它来教我关于该模型、ONNX、将模型转换为 ONNX 的过程、WebGPU 的知识,以及为了完全理解这个仓库我需要了解的几乎所有内容。
这是它生成的对话记录和创建的 understanding.md Markdown 文件,我现在已经将它们添加到了 GitHub 仓库中。我发现其中对 ONNX 的解释特别具有启发性:
ONNX(Open Neural Network Exchange)是一种用于神经网络的、可移植且与框架无关的文件格式。一个 .onnx 文件本质上包含两部分内容:一是计算图——由节点组成的有向图,其中每个节点都是一个算子(如 Conv、MatMul、Add、Einsum、Softmax、Gather、Resize 等),这些算子通过在它们之间流动的命名张量连接在一起。这就是前向传播的“配方”。二是权重——学习到的参数张量(如卷积核、嵌入表等),作为初始化器存储在同一个图中。关键在于,ONNX 以抽象的方式描述了“计算什么”,而没有说明“如何计算”或在“什么硬件”上计算。算子集通过 opset 编号进行版本控制(本仓库使用 opset 18),这明确规定了存在哪些算子以及它们的语义是什么。
事实证明,PyTorch 具有导出为 ONNX 的内置机制,正如在 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 还提供了一个实用的术语表,以及一个略微有些瑕疵但基本能用的 ASCII 艺术图,展示了模型流水线是如何组合在一起的。
需要完整排版与评论请前往来源站点阅读。