🤩

MLX Swift Examples で高クオリティ!カスタム Stable Diffusion モデル追加ガイド

に公開

はじめに


今回の作業で生成できた画像です。

こんにちは、インターン生の王です。
この記事は延長線です。
https://zenn.dev/open_developers/articles/63af60422ea2ee

試行錯誤を経て様々なカスタムモデルで画像生成ができるようになりました。

私が作業したリポジトリは下に載せます。
https://github.com/autoro-io/intn-mlx-study

今回はApple Silicon 搭載の Mac や iPad で動く機械学習フレームワーク「MLX」を使ったサンプル集 mlx-swift-examples には、画像を生成できる Stable Diffusion のデモが含まれています。このデモはとても素晴らしいものですが、「もっと綺麗な画像を出したい!」「特定のアニメ風の絵が欲しい!」と思うことがあると思ういます。

画像出典:https://note.com/shu223/n/n79c96c10d054

この記事は、mlx-swift-examples の Stable Diffusion で、インターネット上で配布されている、より高性能なカスタムモデルを追加して画像生成の質を上げる方法を、試行錯誤の経緯も踏まえながら解説します。


画像出典:https://generativeai.pub/how-to-install-and-run-stable-diffusion-on-your-macos-90eedfa62a48

なぜカスタムモデルを使用するのか

mlx-swift-examples に最初から含まれているモデル(例: SDXL Turbo, Stable Diffusion 2.1 Base)も十分使えますが、世の中に特定の目的に特化したり、より高画質・高機能になるように学習されたモデルがたくさんあります。

  • Hugging face Hub: AI モデルの巨大なリポジトリ。さまざまな研究機関や個人がモデルを公開しています。
  • Civitai: 特に画像生成AIのコミュニティサイトで、アニメ風、フォトリアル風など、多種多様なカスタムモデル(チェックポイントファイル)が見つかります。

これらのサイトからモデルを探し、mlx-swift-examples に追加することで、生成できる画像の幅と質を大きく向上させることができます。

カスタムモデル追加への道:試行錯誤の記録

高性能なモデルを使いたい! と思ったとき、主に2つの方法でアプリに組み込むことを試しました。

アプローチ1: ローカルファイルから読み込む方法(最初の挑戦)

まずは自分のMacで試してみよう」と考え、以下の手順を試しました。

前提条件:

  • Python環境
  • Hugging Facediffusersライブラリ
  • 変換スクリプト: convert_original_stable_diffusion_to_diffusers.py

インストール(AnacondaやvenvでもOK)

pip install diffusers transformers safetensors
wget https://raw.githubusercontent.com/huggingface/diffusers/main/scripts/convert_original_stable_diffusion_to_diffusers.py

変換用の設定ファイル(YAML)を準備します
safetensors モデルがどのStable Diffusionのバージョンをベースにしているかによって、YAML形式の設定ファイルが必要になります。

モデルの種類 設定ファイル
SD1.5 v1-inference.yaml
SD2.1 v2-inference.yaml
SDXL sdml.yaml(対応モデルによって異なる)

もし、SDXLモデルの変換がyamlファイルが見つからないことが多いと思うますのでここにyamlファイルがなくても変換できるpythonコードを掲載します。

# coding=utf-8
from diffusers import StableDiffusionXLPipeline
import torch
import os

# --- 設定値 ---
checkpoint_path = "/path/to/your/sdxl_model.safetensors" # ★変換元ファイルパス★
save_directory = "/path/to/save/sdxl_diffusers_safetensors" # ★保存先フォルダパス★
# -------------

print(f"Loading single file SDXL model from: {checkpoint_path}")
try:
    # 単一ファイルからSDXLパイプラインをロード
    pipe = StableDiffusionXLPipeline.from_single_file(
        checkpoint_path,
        torch_dtype=torch.float16, # Ponyモデルは多くの場合 float16 です
        use_safetensors=True
    )
    print("Pipeline loaded successfully.")
except Exception as e:
    print(f"Error loading pipeline from single file: {e}")
    exit()

print(f"Saving pipeline to Diffusers format (with safetensors) at: {save_directory}")
try:
    # .safetensors 形式で保存
    pipe.save_pretrained(save_directory, safe_serialization=True)
    print(f"Conversion finished successfully. Check the folder: {save_directory}")
except Exception as e:
    print(f"Error saving pipeline: {e}")

  1. モデルのダウンロード: Hugging Face や Civitai から好みのモデルファイル(多くは .safetensors という拡張子の単一ファイル)をダウンロードします。
  2. 形式変換 (重要!): mlx-swift-examples は、モデルが特定のフォルダ構造(unet/, vae/, text_encoder/ など)に分かれた「Diffusers形式」になっていることを期待します。ダウンロードした単一ファイルはそのままでは使えないため、Pythonスクリプトを使ってDiffusers形式に変換する必要がありました。
python convert_original_stable_diffusion_to_diffusers.py \
    --checkpoint_path "/path/to/your/original_model.safetensors" \
    --from_safetensors \
    --original_config_file "/path/to/your/v1-inference.yaml" \
    --dump_path "/path/to/your/output_diffusers_folder" \
    --to_safetensors \ 
    --device cpu
  • 変換ツール: Hugging Face の diffusers ライブラリに含まれる convert_original_stable_diffusion_to_diffusers.py スクリプトや、ライブラリの機能 (StableDiffusionPipeline.from_single_file など) を使います。
  • 出力形式: この変換時に .safetensors 形式で重みファイルが出力されるように指定するのが重要です。.bin 形式だと mlx-swift-examples で読み込みエラーが発生しました。
  • 注意 (特にSDXL): 変換スクリプトによっては、Tokenizer(文字を扱う部品)やScheduler(生成プロセスを制御する部品)のファイルが自動で含まれない場合があります。その場合は、元のベースモデル(例: runwayml/stable-diffusion-v1-5stabilityai/stable-diffusion-xl-base-1.0)から、不足しているファイル (tokenizer/, tokenizer_2/, scheduler/scheduler_config.json) を手動でコピーして補完する必要がありました。(ただし、使った変換方法によっては自動で含まれることもありました。)
  1. ローカルに配置: 変換して必要なファイルが揃ったフォルダを、Macの分かりやすい場所(例: 「書類」フォルダの中)に置きます。

  2. Swiftコード修正:

    • Load.swift 内で、使いたいモデル用の StableDiffusionConfiguration プリセットを追加します。
    • id には、Hugging Face IDではなく、ステップ3で置いたフォルダの絶対パス(例: "/Users/your_username/Documents/MyModelFolder")を指定します。
    • ファイルパスを解決する resolve 関数を、ローカルパスを扱えるように書き換えます。
    • ContentView.swift 内のモデルダウンロード処理 (configuration.download(...)) をコメントアウトします。
  3. 動作確認 (Mac): Mac上で実行し、動作を確認しました。途中でファイルアクセス権のエラーが出ましたが、システム設定で許可を与えることで解決しました。

この方法のメリット・デメリット

  • ◎ Mac上で素早くテストできる。
  • × Swiftコードの変更箇所が多く、少し複雑。
  • × iPadで動作せる場合は、モデルファイルをアプリにバンドする必要があります。もし複数のモデルを追加した場合はアプリのサイズが大きくなりすぎます。
  • × モデルごとにフォルダを管理する必要がある。

アプローチ2: Hugging Face Hub リポジトリを使う方法(推奨)

ローカルでの動作確認後、「これって毎回ユーザーが手動でダウンロード・設定するの?」「iPadではどうするの?」という疑問が出てきました。調べてみると、もっとスマートな方法がありました。
ステップ1、2は自分の好みに合わせてやったりやらなくてもいいです。
具体的に言いますと、自分でカスタマイズや再学習をする予定がある人はやったほうがいいです。
もしそうでないなら、hugging face に公開してあるモデルのリポジトリをそのまま使ったほうが楽です。

  1. モデルのダウンロードと変換(ここはもし自分で再学習する予定があるならば): アプローチ1のステップ1、2と同じです。Diffusers形式で .safetensors の重みファイルを持つフォルダを用意します。(不足ファイルの補完も忘れずに)

  2. Hugging Face Hub にアップロード(ここはもし自分で再学習する予定があるならば):
    変換済みのモデルフォルダの中身を、自分自身(または会社組織)の Hugging Face Hub リポジトリにアップロードします。
    これには git と git-lfs (大きなファイルを扱うツール) を使う必要がありました。5GBを超えるファイルがある場合は、リポジトリ設定で LFS の大容量ファイルサポートを有効にする必要もありました。
    会社の組織リポジトリにアップロードする場合、適切な権限が必要でした。

  3. Swiftコード修正:
    Load.swift 内で、使いたいモデル用のStableDiffusionConfiguration プリセットを追加します。
    id には、ローカルパスではなく、Hugging Face Hub のリポジトリID(例: "your-username/your-model-repo""your-org/your-model-repo")を指定します。
    files: ディクショナリには、リポジトリ内のファイルへの相対パスを指定します(.safetensors 形式であることを確認)。
    ローカル読み込みのために書き換えた resolve 関数やコメントアウトした download 処理を、元の状態に戻します。

// (Load.swift/StableDiffusionConfiguration)

// --- SDXLモデル (例: Pony) のプリセット追加例 ---
public static let presetCyberrealisticPony = StableDiffusionConfiguration(
    id: "YourOrg/YourPonyRepo", // Hub ID
    files: [
        .unetConfig: "unet/config.json",
        .unetWeights: "unet/diffusion_pytorch_model.safetensors",
        .vaeConfig: "vae/config.json",
        .vaeWeights: "vae/diffusion_pytorch_model.safetensors",
        .textEncoderConfig: "text_encoder/config.json",
        .textEncoderWeights: "text_encoder/model.safetensors",
        .textEncoderConfig2: "text_encoder_2/config.json",       // SDXL Key
        .textEncoderWeights2: "text_encoder_2/model.safetensors", // SDXL Key
        .diffusionConfig: "scheduler/scheduler_config.json",
        .tokenizerVocabulary: "tokenizer/vocab.json",
        .tokenizerMerges: "tokenizer/merges.txt",
        .tokenizerVocabulary2: "tokenizer_2/vocab.json",         // SDXL Key
        .tokenizerMerges2: "tokenizer_2/merges.txt",           // SDXL Key
    ],
    defaultParameters: { EvaluateParameters(cfgWeight: 5.0, steps: 25, latentSize: [128, 128]) },
    factory: { hub, sdConfiguration, loadConfiguration in
        let sd = try StableDiffusionXL( // ★ SDXL を使用 ★
            hub: hub, configuration: sdConfiguration, dType: loadConfiguration.dType)
        // ... quantization ...
        return sd
    }
)

// --- 非SDXLモデル (例: Beautiful Realistic) のプリセット追加例 ---
public static let presetBeautifulRealisticV7 = StableDiffusionConfiguration(
    id: "YourOrg/YourRealisticRepo", // Hub ID
    files: [
        .unetConfig: "unet/config.json",
        .unetWeights: "unet/diffusion_pytorch_model.safetensors",
        .vaeConfig: "vae/config.json",
        .vaeWeights: "vae/diffusion_pytorch_model.safetensors",
        .textEncoderConfig: "text_encoder/config.json",
        .textEncoderWeights: "text_encoder/model.safetensors",
        .diffusionConfig: "scheduler/scheduler_config.json",
        .tokenizerVocabulary: "tokenizer/vocab.json",
        .tokenizerMerges: "tokenizer/merges.txt",
        // ★ SDXL用のキーは含めない ★
    ],
    defaultParameters: { EvaluateParameters(cfgWeight: 7.0, steps: 30, latentSize: [64, 64]) }, // latentSize例
    factory: { hub, sdConfiguration, loadConfiguration in
        let sd = try StableDiffusionBase( // ★ Base を使用 ★
            hub: hub, configuration: sdConfiguration, dType: loadConfiguration.dType)
        // ... quantization ...
        return sd
    }
)
  1. 動作確認 (Mac / iPad):
    アプリを実行すると、最初にモデルが選択されたときに、アプリが自動的に Hugging Face Hub から必要なファイルをダウンロード(またはキャッシュから読み込み)してくれます。
    開発者やユーザーが事前に手動でモデルをダウンロードする必要はありません。
    MacでもiPadでも同じように動作します。

この方法のメリット・デメリット:

  • ◎ アプリの使い勝手が良い(ユーザーはモデルを選ぶだけでOK)。
  • ◎ MacでもiPadでも動作する。
  • ◎ モデルの管理がHugging Face Hub上で一元化できる。
  • △ 最初にモデルを変換してHubにアップロードする手間がかかる。
  • △ プライベートリポジトリを使う場合は、アプリ側での認証(トークン設定など)が必要になる。

モデルの再学習について

既存のモデルをベースに、自分で追加学習(ファインチューニング)させて、独自のモデルを作ることもできます。その場合も流れは似ています。

  1. ベースとなるモデル(Diffusers形式)をダウンロード。
  2. 追加学習を行う(これには通常Pythonと専門知識が必要です)。
  3. 学習済みの新しいモデル(単一ファイルかDiffusers形式)ができる。
  4. 必要ならDiffusers形式 (.safetensors)に変換。
  5. 選択肢:
    • Macのローカルファイルとして使う(アプローチ1)。
    • Hugging Face Hub にアップロードして使う(アプローチ2)。

[重要] ライセンスの確認を忘れずに!
Hugging Face や Civitai で配布されているモデルには、それぞれライセンス(利用規約) が定められています。特にカスタムモデルを使う場合や、自分でファインチューニングしたモデルを扱う場合は、元のモデルのライセンスを必ず確認してください。

  • 公開・再配布の可否: モデルファイルを(たとえ変換したものでも)Hugging Face Hubなどで公開 (Public) して良いかどうか。
    商用利用の可否: 生成した画像を商用目的で使って良いか、モデル自体を商用サービスで使って良いか。
    利用制限: 特定の用途(例: モデルホスティングサービスでの利用禁止など)が制限されていないか。
    今回使った dreamlike-photoreal-2.0 のように、「ウェブサイト等でのホスティングや推論利用は禁止(許可が必要)」といった厳しい制限がある場合もあります。ライセンスが不明な場合や、公開・商用利用を考えている場合は、モデルの作者に問い合わせるか、利用を控えるのが安全です。安易に公開リポジトリにアップロードすると、ライセンス違反になる可能性があります。プライベートリポジトリで、組織メンバー内だけで使うのが無難な場合も多いです。

結果

今回実験で生成した画像一覧
上がstable-diffusion-2-1-base、下がDreamlikePhotoreal。
Prompt: A white bald man, wearing a (black)suit, mortnobody15, ((red tie))

Negative Prompt: ((sunglasses:1)),((glasses:1))


Prompt: Majestic snow-capped mountains reflecting in a clear alpine lake, dramatic golden hour lighting, cinematic, photorealistic, detailed, sharp focus, 8k uhd.

Negative Prompt: cartoon, drawing, illustration, sketch, anime, low quality, blurry, deformed peaks, unrealistic water, text, signature, watermark


Prompt: Close-up portrait of an elderly librarian with kind eyes and intricate wrinkles, sitting in a dimly lit library, Rembrandt lighting, detailed skin texture, sharp focus, photorealistic.

Negative Prompt: illustration, painting, drawing, sketch, cartoon, anime, young man, woman, deformed face, extra limbs, blurry, low quality, signature, text.


Prompt: Cyberpunk street in Tokyo at night during heavy rain, vibrant neon signs reflecting on wet asphalt, atmospheric, cinematic wide angle, highly detailed, photorealistic, Blade Runner style.

Negative Prompt: drawing, sketch, illustration, cartoon, anime, day time, dry pavement, empty street, low quality, blurry, text, signature, watermark.


Prompt: Vintage typewriter on a rustic wooden desk next to a stack of old books and a steaming cup of tea, soft morning sunlight streaming through a window, macro photography, detailed textures, nostalgic atmosphere, photorealistic.

Negative Prompt: illustration, drawing, painting, sketch, anime, modern laptop, digital camera, messy, low quality, blurry, unrealistic steam, text, signature.

まとめ

mlx-swift-examples でより高品質な画像生成を楽しむには、Hugging Face や Civitai からカスタムモデルを導入するのが有効です。モデルは Diffusers形式 (.safetensors 重み) に変換し、Hugging Face Hub にアップロードしてアプリからリポジトリIDで利用するのが、Mac/iPad両対応で使い勝手の良い方法と言えるでしょう。ただし、モデルのライセンス確認は非常に重要ですので、必ず事前に行いましょう。

オープン開発チーム

Discussion