ComfyUI×M1 Proで画像生成実測、Geminiが最適解

レビュー・比較

はじめに——コスト削減から始まった検証

ブログ記事のアイキャッチ画像を自動生成したい。できれば費用を限りなくゼロに近づけたい——そんなごく現実的な動機から、この検証は動き出した。

1記事で生成するのは計12枚だ。アイキャッチ1枚+セクション画像、各3候補という構成になる。API課金は1枚あたり数円でも、月100記事を超えると数千円規模に膨らむ。「M1 Pro 32GBがあるなら、ローカルで完結できるのでは?」というのが、検証の出発点だった。

著者について:本記事は、AIコンテンツ生成パイプラインを自社運用する環境における実測値に基づいています。

結論を先に書く

長い記事なので、核心だけ先にまとめておく。

  • ローカル生成はM1 Pro 32GBには荷が重い。画質重視なら1記事35分、速度重視なら画質が破綻する
  • Gemini 2.5 Flash(画像生成)(gemini-2.5-flash-image)の無料枠が現状の最適解。画質はFLUX並で、500枚/日まで0円
  • ComfyUI環境自体は温存する価値がある(月末にAPIのCAP上限へ到達した際の逃げ道として)

以下、試した順に数字と実感を記録していく。

導入編:Imagen 4 Fastは思ったより課金されていた

MacBook Proでのローカル開発環境

もともと記事生成フローには Google の Imagen 4 Fast を使っていた。設定では imagen-4.0-fast-generate-001

1枚あたり $0.02(約 3 円)
1 記事 12 枚生成 = 約 36 円
月 100 記事書けば 3,600 円

月 3,600 円くらいなら悪くない、と思ってしばらく運用していた。だがある日の課金額を見てビビる。記事単位で見ると月額が見えにくいが、月次 CAP(AI Studio で設定できるスペンド上限)に 2 回ほど当たり、生成が止まっていた。

これをきっかけに、「ローカルで完結させられるなら、やりたい」と考え始める。Mac mini M1 8GB は常時稼働しているが SDXL すら厳しいので、手元の MacBook Pro M1 Pro 32GB を使う前提で検証開始。

ComfyUI インストール直後の罠:チェックポイントが NSFW 特化だった

目的別にAIモデルを選別することの重要性を示すイメージ

ComfyUI.app(デスクトップ版)を起動、最初に入っていた 23 個のチェックポイントのなかで default っぽかった hassakuXLIllustrious_v21fix.safetensors をそのまま使った。

生成してみたら…全部 NSFW 寄りの画像が出てきた。ブログのアイキャッチに使えるレベルじゃない。

Illustrious / Pony 系のアニメモデルは NSFW データで強く fine-tune されているので、弱いネガティブプロンプト(blurry, low quality, watermark, text, logo)では抜けられない。

チェックポイントの選び方——用途を先に決める

テック記事のアイキャッチ画像には、専門性を損なわない清潔感と高いSFW(Safe For Work)中立性が不可欠です。IllustriousやPonyといったアニメ系Finetuneモデルは表現力に優れる反面、学習データの特性上、意図しないNSFW要素が混入しやすいため、実務では厳格なネガティブプロンプト管理や、より中立的なFlux/SD3.5ベースモデルとの使い分けが重要になります。画質と安全性のトレードオフを考慮し、キャラクター性を前面に出す場合はアニメ系を、抽象的で洗練されたテック感を演出する場合はセミリアル・写真系を選択するのが、生成の試行回数を抑えつつクオリティを担保するための実務的な選定基準となります。

ブログのテック記事用途なら、Illustrious/Pony系は完全に避けるべきだ。代わりに以下から選ぶとよい。

  • バニラ: sd_xl_base_1.0.safetensors(中立、最小リスク)
  • セミリアル: perfectdeliberate_v30.safetensors(汎用、SFW 向き)
  • 写真系: xxmix9realisticsdxl_v10.safetensors(人物強いが使いどころ限定)

そしてネガティブプロンプトに SFW 強制ワードを追加する:

blurry, low quality, watermark, text, logo,
nsfw, nude, naked, sexual, explicit, suggestive,
revealing, underwear, lingerie, cleavage

教訓1:チェックポイント選びは用途を決めてから。 モデルの系統を確認しないまま使い始めると、最初の一枚で躓く。

FLUX.1 schnell に期待を込めて 17GB ダウンロード

大容量ファイルのダウンロード進行状況

SDXL でも base は素の状態で画質低い。Black Forest Labs の FLUX.1 が SDXL 世代より一段上だと聞いて試す。

schnell は Apache 2.0 ライセンスなので商用利用 OK。ComfyUI 公式が配布している all-in-one fp8 版をダウンロード:

cd ~/Documents/ComfyUI/models/checkpoints
curl -L -O https://huggingface.co/Comfy-Org/flux1-schnell/resolve/main/flux1-schnell-fp8.safetensors

17GB。回線速度にもよるが 10〜20 分。

立ちはだかる壁:MPS fp16 アップキャストと swap 地獄

生成を始めた瞬間、Activity Monitorがオレンジに染まった。実測値は以下の通りだ。

項目 数値
ComfyUIプロセス使用メモリ 17.57 GB
使用済みメモリ合計 27.11 GB / 32 GB
swap使用量 7.09 GB
圧縮メモリ 7.59 GB
メモリプレッシャー オレンジ(警告)

fp8 は名前に反して、MPS(AppleシリコンのGPU演算バックエンド)バックエンドでは fp16 にアップキャストされて計算される。結果、実メモリ 20GB 近く食う。M1 Pro 32GB だと他のアプリの分を引くと常に swap に出入りする状態。

1 枚生成して 203 秒。swap で I/O 待ちの時間が多い。

GGUF 量子化で逃げる:UNET Q5_K_S + T5 GGUF

fp8 が Mac で重い問題は、GGUF 量子化モデルと ComfyUI-GGUF カスタムノードで回避できる。llama.cpp が対応している量子化形式で、ComfyUI でも city96 氏が移植してくれている。

git clone --depth 1 https://github.com/city96/ComfyUI-GGUF.git \
  ~/Documents/ComfyUI/custom_nodes/ComfyUI-GGUF

~/Documents/ComfyUI/.venv/bin/python -m pip install --upgrade \
  gguf sentencepiece protobuf

# モデル(合計 ~12GB)
# UNET: 8GB
curl -L https://huggingface.co/city96/FLUX.1-schnell-gguf/resolve/main/flux1-schnell-Q5_K_S.gguf \
  -o ~/Documents/ComfyUI/models/unet/flux1-schnell-Q5_K_S.gguf

# CLIP L テキストエンコーダー: 246MB
curl -L https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/clip_l.safetensors \
  -o ~/Documents/ComfyUI/models/text_encoders/clip_l.safetensors

# T5 Q5_K_M: 3GB
curl -L https://huggingface.co/city96/t5-v1_1-xxl-encoder-gguf/resolve/main/t5-v1_1-xxl-encoder-Q5_K_M.gguf \
  -o ~/Documents/ComfyUI/models/text_encoders/t5-v1_1-xxl-encoder-Q5_K_M.gguf

# VAE: 335MB
curl -L https://huggingface.co/camenduru/FLUX.1-dev/resolve/main/ae.safetensors \
  -o ~/Documents/ComfyUI/models/vae/ae.safetensors

black-forest-labs/FLUX.1-schnell リポジトリは gated(HF ログイン必要)なので、VAE(ae.safetensors)だけは camenduru の非公式ミラーから取った。FLUX schnell/dev の VAE は同一。

T5 も GGUF 量子化版(Q5_K_M、3GB)を使うと 2〜3GB 追加で節約できる。

ComfyUI のワークフロー(FLUX GGUF)

UnetLoaderGGUF (UNET Q5)
       ↓
DualCLIPLoaderGGUF (T5 Q5 + CLIP L) → CLIPTextEncode (positive/negative)
                                                        ↓
EmptyLatentImage → KSampler (euler, simple, cfg=1, steps=4) → VAEDecode → SaveImage
                       ↑                                          ↑
                       └── model ───┘                        VAELoader (ae.safetensors)

schnell は distilled モデルなので CFG 不要(cfg=1 固定)・4 steps で OK。

量子化の効果——メモリは改善、速度は微改善にとどまる

UNET Q5 + T5 GGUF Q5_K_Mに切り替えた後の実測値を比較する。

項目 fp8版 GGUF版 差分
ComfyUIプロセスメモリ 17.57 GB 13.07 GB −4.5 GB
圧縮メモリ 7.59 GB 2.73 GB −4.9 GB
メモリプレッシャー オレンジ 緑(健全)
生成時間/枚 203秒 173秒 −15%

メモリは4GB以上節約できた。ただし生成時間の改善は15%どまりだ。M1 ProのGPUでFLUXを動かす場合、weightsを圧縮してもcomputeはfp16で実行される。ボトルネックはGPU演算能力そのものにあり、量子化では解消できない。

1枚173秒×12枚=約35分/記事。実用域には届いていない。

ここでの罠:候補画像が 1 枚しか保存されない

3 候補生成しているはずなのに、データベースには 1 枚しか残らない。ログを追うと:

  • 20:40:36 candidate 1 キュー投入 → サーバー側 180 秒でタイムアウト
  • 20:43:40 candidate 2 キュー投入 → 同じくタイムアウト
  • 20:46:43 candidate 3 キュー投入 → 178 秒で間に合い保存成功

ComfyUI 側では全部 197 秒〜173 秒で生成自体は完了しているのに、サーバーのポーリング上限が 180 秒だったため、最初の 2 枚は「孤児」になっていた。

修正:ポーリングタイムアウトを延長

// packages/server/src/services/image/comfyui-provider.ts

/**
 * ポーリング設定。
 *
 * Why: 1 プロンプトあたり複数候補を sequential に投入するケースで、
 * ComfyUI のキュー待ち + 生成時間の合計が 3 分を超えることがある
 * (特に FLUX 系)。保険として 10 分まで待つ。
 */
const POLL_INTERVAL_MS = 2000;
const MAX_POLL_ATTEMPTS = 300; // 最大10分待機

SD 3.5 medium は思ったほど軽くない

SD 3.5 medium——期待外れの生成時間

FLUXの35分/記事は重すぎる。SD 3.5 medium(11.6GB)に期待を込めて試した。Comfy-Orgのsd3.5_medium_incl_clips_t5xxlfp8scaled.safetensorsで計測する。

結果は1枚328秒。FLUXより1.5倍遅い。

理由は単純だ。SD 3.5の推奨ステップ数は30。FLUXのschnell(4steps)の7.5倍になる。モデルが小さくても、ステップ数で完全に押し切られる。画質もFLUXより一段下で、選ぶ理由が見当たらない。

SDXL base 1.0 は速度はマシだが画質が素

次に SDXL base。1 枚 98〜107 秒。

  • FLUX の約半分の時間
  • 12 枚 = 約 20 分/記事
  • だが画質は「base」そのもので、finetune 無しでは厳しい

SDXL finetune の perfectdeliberate_v30 も試した。速度はほぼ同じ(100 秒前後)、画質は base よりは良いが FLUX の領域には遠く及ばない。

ここで一度立ち止まる:ローカル生成の限界

試した結果をまとめる。

構成 1枚 12枚(3候補×4スロット) 画質
FLUX fp8 all-in-one 203s 40分
FLUX Q5_K_S GGUF 173s 35分
SD 3.5 medium 328s 65分
SDXL base 1.0 100s 20分 ×
perfectdeliberate_v30 100s 20分

どこを取ってもトレードオフから逃げられないのが、M1 Pro 32GB の現実だった。

クラウド API 比較:結局ここが本命だった

ローカルから撤退して、主要クラウド API を比較する。

プロバイダ/モデル 単価 1記事 (12枚) 無料枠 画質
Gemini 2.5 Flash(gemini-2.5-flash-image $0.04 $0.48 ~500枚/日(~40記事/日)
Gemini Imagen 4 Fast(imagen-4.0-fast-generate-001 $0.02 $0.24 無し
Gemini Imagen 4 Standard(imagen-4.0-standard-generate-001 $0.04 $0.48 無し
Gemini Imagen 4 Ultra(imagen-4.0-ultra-generate-001 $0.06 $0.72 無し ◎◎
OpenAI DALL-E 3 Standard $0.04 $0.48 無し
FLUX Schnell (Replicate) $0.003 $0.036 わずか
FLUX Pro (Replicate) $0.055 $0.66 わずか
Stability SD 3.5 Large $0.065 $0.78 わずか
Ideogram v2 $0.08 $0.96 わずか ◎(テキスト描画強い)
Cloudflare Workers AI (FLUX schnell) ほぼ0 ほぼ0 10,000 neurons/日(~10-20枚)

Gemini 2.5 Flash(gemini-2.5-flash-image)の無料枠が頭一つ抜けている。1日40記事まで$0で、画質はImagen 4 Fastと同等——この組み合わせは他のサービスにない。

注記: レート制限や無料枠の詳細は Google AI Studio 公式ドキュメント(本記事執筆時点:2026年5月7日)を参照してください。仕様は予告なく変更される可能性があります。

切替ハマりポイント:「エラー無しで画像が変わらない」

image.gemini_image_modelgemini-2.5-flash-image に変えて再生成。エラー出ないのに画像が切り替わらない。

原因は 2 つのバグが重なっていた:

バグ 1:DB の API キーが古いまま

const apiKey = imageConfig.geminiApiKey || config.geminiApiKey;

DB に暗号化保存された image.gemini_api_key が古い状態のまま残っていて、.env の現行キーにフォールバックしていなかった。

バグ 2:エラーが debug レベルに握り潰されていた

} catch (error) {
  this.logger.debug(
    { error: ..., index: i },
    "画像候補の取得に失敗(スキップ)",
  );
}

本番ログは warn 以上しか出力していないので、API key not valid が完全に silent。UI には成功扱いで返る。

対処

  1. 古いキーを削除(.env フォールバックに戻す):
    DELETE FROM settings WHERE key = 'image.gemini_api_key';
    
  2. エラーログを debugwarn に昇格(次回から可視化)

採用した運用構成

検証を経て決定した構成は以下の3層だ。

用途 使用モデル コスト
通常運用 Gemini 2.5 Flash(gemini-2.5-flash-image 無料(40記事/日まで)
CAP到達時・月末バースト時 FLUX.1 schnell Q5 GGUF(ローカル) 無料(35分/記事)
将来の選択肢 Cloudflare Workers AI(FLUX schnell) 無料枠(10〜20枚/日)

ディスク節約の後片付け

ローカル検証で集めた不要モデルは合計 32GB。

  • flux1-schnell-fp8.safetensors (16.1GB)
  • sd3.5_medium_incl_clips_t5xxlfp8scaled.safetensors (10.8GB)
  • t5xxl_fp8_e4m3fn.safetensors (4.9GB)

macOS の trash コマンドでゴミ箱に送り、Finder から空にして解放。

残すもの:

  • flux1-schnell-Q5_K_S.gguf (8GB) — FLUX 復帰用
  • t5-v1_1-xxl-encoder-Q5_K_M.gguf (3GB)
  • clip_l.safetensors (246MB)
  • ae.safetensors (335MB)

合計 11GB で FLUX 環境を温存できている。

まとめ:ローカル検証・クラウド移行・実システム修正を経た一気通貫の検証レポート

7時間の検証で出た結論は「クラウドAPIのほうが速くて安くて画質も良い」だった。薄々感づいていた答えを、数字で確認しただけとも言える。

手を動かしたことで分かったこと

それでも、得たものはある。

  1. ComfyUIのワークフロー構造(FLUX / SD3 / SDXLの違い)が体に入った
  2. MPSのfp16アップキャスト挙動と、GGUF量子化が解決する範囲・しない範囲が明確になった
  3. エラーをdebugレベルで握り潰す設計の危うさが身にしみた

設計への教訓

3つ目が一番刺さった。debugで良いのは「頻繁に起きる正常系の軽微な情報」だけだ。処理が失敗しているのにUIには成功に見えるようなパスは、必ずwarn以上にしなければいけない。

画像生成まわりに限らず、どんなシステムでも同じ原則が効いてくる。

独自性と実用性

この記事は、ローカル環境から実際のシステム運用への一気通貫の検証フロー——計測→試行→失敗→修正——を追ったものです。単なる「APIの比較表」ではなく、実装者が実際に踏む道、そしてそこで見落としやすい設計上の落とし穴を記録しています。M1 Pro のスペック、ComfyUI、FLUX、GGUF量子化と調べていった先で「やっぱりAPIのほうが早かった」と気づく——その検証時間を、読者が1時間に短縮できれば幸いです。

実際に試してみませんか?

Gemini 2.5 Flash の無料枠は月単位で更新されるため、スポット利用でも固定費ゼロを維持できます。記事のアイキャッチ生成から始めて、段階的に画像生成タスクを自動化してみてください。ComfyUI環境については、この記事の構成をテンプレートに、カスタマイズすることをお勧めします。試した結果や工夫した点はぜひコメントで教えてください——他の実装者の参考になります。


参考リンク

コメント