Claude CodeでMoebius 0.2B画像インペインティングモデルをブラウザで動くように移植する
原文は Simon Willison により に公開されました。 このブログを購読する
今朝、Hacker Newsで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です)、中規模なリファクタリングやUIの仕上げをエージェントに任せている間、5〜10分ほど手持ち無沙汰に待つことがよくありました。
(コーディングエージェントの面白いところは、難しい問題ほど、処理が終わるのを待つ間に気を散らす時間が増えることですね!)
そこで、ターミナルでClaude Codeを立ち上げて、Moebiusをウェブに移植する作業をどこまで進められるか試してみることにしました。
プロジェクト開始に向けたエージェント的リサーチ
最初のステップとして、通常のClaudeにこのプロジェクトの実現可能性について尋ねてみました。Claude.aiはGitHubからリポジトリをクローンできるので、そこで次のように聞きました:
Clone https://github.com/hustvl/Moebius/ and tell me if they published the code and weights to run this model anywhere
(この時点ではまだ重みへのリンクに気づいていませんでした。「News」セクションにひっそり置かれていたのです。)
続けて:
For Moebius what are the options for running it right now - Python and NVIDIA CUDA only or other options too?
そして:
Muse on the feasibility of porting it to Transformers.js or similar and running it in a browser
モデルに「muse on X」と指示するのが好きなんです。具体的なゴールを与えずに、問題についてじっくり考えさせたいときに見つけた、最も短い表現なんです。
そのチャットのログはこちらです。最後の回答を抜き出してresearch.mdとして保存し、後でClaude Codeに読ませるようにしました。
Claudeは、私が提案したTransformers.jsライブラリのさらに下のレイヤーである、WebGPUバックエンドのONNX Runtime Webを使うことを提案してきました。
これで、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を起動し、こう指示しました:
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
作業が始まったところで、こんなフォローアップも投げ込みました(タイプミスもそのままです):
Bulid 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 oy work too
エージェントにこうしてメモを取らせることがよくあるのですが、最終的にできあがるものは、自分自身にとっても次に同じプロジェクトを触るエージェントにとっても、しばしば興味深いものになります。そのnotes.mdファイルがプロジェクト終了時点でどうなっていたかはこちらです。
指示を出してからはメインのプロジェクトに戻り、ときどきClaudeの様子を確認していました。何か動きそうなものができたように見えたので、こう尋ねました:
Tell me what URL I can visit in my own browser to try this
それからChromeで試してみて、出てきたエラー(とエラーのスクリーンショット)をClaude Codeに貼り付けて返しました。
これを数回繰り返すうちに、どうやら動くものができました!あとはインターネットに公開して、他の人にも使ってもらうだけです。
How would we publish this to Hugging Face such that the model weights were on there and the HTML demo would show up in Hugging Face spaces?
Claude Codeはhf CLIツールの使い方を知っているので、Hugging Face上にモデル用のリポジトリを作成し、次にトークンを作成してそのリポジトリに書き込みできるようにし、Claudeが使えるように/tmp/Moebius/token.txtというファイルに置きました。
変換した1.24GBのONNXの重みを、huggingface.co/simonw/Moebius-ONNXに公開してくれました。
以前、Hugging Faceから重みをブラウザに読み込んでいる他のデモを見たことがあったので、可能だということはわかっていました。フロントエンドのコード自体はGitHub Pagesでホストすることにして、こう伝えました:
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を伝えておくことは重要でした。構築中のデモ内のURLを、本番環境でも動くように修正する必要が出てくるかもしれないからです。
メインのプロジェクトの合間にさらに何度かやり取りを重ねて、ついに動くデプロイ済みのバージョンができました!
ただ……ページを再読み込みするたびに、約1.3GBのモデル重みをダウンロードし直しているようでした。これはブラウザのキャッシュがかなり重要になりそうです!
anything clever we can do with serviceworkers or similar to help cache this stuff? It seems to reload every time, I am concerned that there might be something weird about the way HF redirects work that mean we don't benefit from browser caching
Transformers.jsのプロジェクトならこれをうまく処理できるはずだと思い、Whisper Webのデモをコピーして/tmp/Moebius/whisper-webに置き、こう言いました:
look in /tmp/Moebius/whisper-web (with a subagent) and see how they do this
そのプロジェクトはビルド済みのJavaScriptファイルで完全に難読化されていたので、サブエージェントを使えば、トップレベルのトークンコンテキストをそれらのファイルの解読に費やさずに済むだろうと考えたのです。
Claudeは、そのプロジェクトがcaches.open("transformers-cache")——CacheStorage API——を使っていることを突き止め、それを私たちのプロジェクトにも追加してくれました。
このプロジェクトのClaude Codeの全ログも共有しています(私のclaude-code-transcriptsツールを使って公開しました)。
この経験から何を学んだか
これはまさにバイブコーディングと言えます。プロジェクトのコードを一行たりとも見ることなく、自分の関与はテストやちょっとした機能改善の提案(大きなファイルのダウンロード用のプログレスバーなど)、そしてこう動いてほしいという例の方向へモデルを導くことに限定しました。
コードを自分で書かなかったので、基盤となっている技術——WebGPUやONNX、そしてMoebiusモデル自体——について学べたことは非常に限られています。
こういう種類のプロジェクトではいつものことですが、最も重要だった学びは、何が可能なのかということでした:
- Claude Opus 4.8は、PyTorchモデルをONNXに変換し、その結果をHugging Faceに公開し、さらにそのモデルを読み込んで実行できるウェブアプリケーションとインターフェースを構築することができます。
- Chrome、Firefox、Safariはすべて、この種のモデルを実行できるようになっています——3つすべてで試しました。
- CacheStorage APIは約1.3GBのモデルファイルでも機能します。
- ……つまり、インペインティングをクライアントだけで完結するウェブアプリケーションの機能として持てるということです!(ユーザーが1.3GBのダウンロードを許容してくれるなら、ですが。)
自分のプロジェクトについて、もう少し学んでおくべきだと感じました。Claude.aiを立ち上げて、こう指示しました:
Clone https://github.com/simonw/moebius-web/ and use it to teach me all about the model and ONNX and the process of converting a model to ONNX and WebGPU and basically everything I'd need to know in order to fully understand this repo
そのログはこちらで、作成されたMarkdownファイルのunderstanding.mdはGitHubリポジトリに追加しました。特にONNXの説明が目から鱗でした:
ONNX(Open Neural Network Exchange)は、ニューラルネットワークのためのポータブルでフレームワークに依存しないファイルフォーマットです。
.onnxファイルは、本質的には2つのものをひとつにまとめたものです:
- 計算グラフ——ノードの有向グラフで、各ノードは演算子(
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アートの図も含めてくれました。
記事をランダムに読む
コメント
ログインしてコメントする