返回 2026-06-24
📝 其他

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

simonwillison.net·2026-06-22

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 Opus 4.8 能够将 PyTorch 模型转换为 ONNX,将结果发布到 Hugging Face,然后构建出一个可以加载并执行该模型的 Web 应用程序和界面。
  • Chrome、Firefox 和 Safari 现在都能够运行这类模型——这三个浏览器我都试过了。
  • CacheStorage API 能够处理约 1.3GB 的模型文件。
  • ……这意味着我们可以将局部重绘(inpainting)作为纯客户端 Web 应用程序的一项功能!(前提是如果我们的用户能够忍受这 1.3GB 的下载量。)
  • 我觉得我大概应该尝试多了解一下我的项目。于是我打开了 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 艺术图,展示了模型流水线是如何组合在一起的。

    需要完整排版与评论请前往来源站点阅读。