LM Studioにおける統合されたマルチモーダルMLXエンジンアーキテクチャの紹介

2025-05-30

undefined

LM StudioのMLXエンジン (MIT) は、Apple Silicon Mチップ上でLLMを効率的に実行するための2つの強力なPythonパッケージを活用しています。テキスト生成にはmlx-lm (@awni、@angeloskath、Apple作)、ビジョン対応言語モデルにはmlx-vlm (@Blaizzy作) が使用されています。

mlx-engineのコミットf98317e (アプリ内エンジンv0.17.0以降) から、これらの各パッケージの基盤となるコンポーネントを統合した新しい統一アーキテクチャに移行しました。現在、mlx-lmのテキストモデル実装が常に使用され、mlx-vlmのビジョンモデル実装は、テキストモデルが理解できる画像埋め込みを生成するための「アドオン」としてモジュール的に使用されています。

undefined

新しいmlx-engineの統合されたビジョンモデルアーキテクチャ。mlx-lmテキストモデルはmlx-vlmビジョンアドオンで拡張されます。

これにより、マルチモーダルMLX VLM (例: GoogleのGemma 3) を使用する際のパフォーマンスとユーザーエクスペリエンスが大幅に向上します。例えば、VLMとのテキストのみのチャットでもプロンプトキャッシングの恩恵を受けられるようになりました。これは以前はテキストのみのLLMに限定されていた機能で、その結果、後続の応答が劇的に高速化されます。これにより、MLX VLMはテキストタスクにおいてテキストのみのLLMとシームレスに交換可能になり、さらにビジョン機能をおまけとして提供します。

👓 問題、解決策、そしてLM StudioのMLXエンジンでこの統一アーキテクチャをどのように実現したかについて、技術的な詳細を読み進めてください。

👷 LM StudioのMLXエンジンへのオープンソース貢献は大歓迎です! 統一アーキテクチャをより多くのモデルに拡張するのにご協力いただける場合は、このGitHubイシューを良い出発点としてご覧ください。

マルチモーダルモデルとは?

マルチモーダルLLMは、複数の入力モダリティを受け取ることができるLLMです。これは、テキスト入力の処理に加えて、画像や音声入力も受け入れることができることを意味します。

新しいMLXエンジンはまだ音声を扱っていませんが、このアプローチが音声入力にも機能するように計画しています。


一般的に、ビジョン対応LLMは以下のフローで画像入力を取り込みます

undefined

マルチモーダルビジョンLLMの一般的な運用フロー:画像をテキストモデルが理解できる埋め込みに変換し、テキストモデルで出力を生成する

  • プロンプトはテキストと画像で入力されます
  • (1a) モデルの「テキスト」部分がテキストをモデルの埋め込み空間にエンコードします
    • "これは何ですか?"[0.83, 0.40, 0.67, ...]
  • (1b) モデルの「ビジョン」部分が画像をテキストモデルの埋め込み空間にエンコードします。これにより、画像はテキストモデルが理解できる形式に変換されます。
    • image.png[0.28, 0.11, 0.96, ...]
  • (2) テキストと画像の埋め込みが結合されます
    • [0.83, 0.40, 0.67, ...] + [0.28, 0.11, 0.96, ...][0.83, 0.40, 0.67, ..., 0.28, 0.11, 0.96, ...]
  • (3) 結合された埋め込みはテキストモデルに渡され、モデルはテキストと画像の両方からの情報に基づいてテキストを生成します。

プロンプトに画像がない場合、「結合された埋め込み」は単にテキスト埋め込みとなります。


MLXエコシステムにおけるモデル実装

MLX Pythonのエコシステムには、Apple Silicon上でLLMと対話するためのモデル実装とインフラを提供する2つの主要なライブラリがあります

  • mlx-lm: テキストモデルの実装と、それらと対話するためのインフラ
  • mlx-vlm: テキストモデルの実装、ビジョンモデルの実装、そしてそれらと対話するためのインフラ

歴史的に、mlx-lmはマルチモーダル機能を持たないテキストのみのモデルの実装を含んでいましたが、mlx-vlmMLX VLM実装の事実上の本拠地となっています。

undefined

mlx-lmとmlx-vlmにおけるモデル実装コンポーネント。黄色 = テキストモデルコンポーネント。青 = ビジョンモデルコンポーネント。

LM Studioのmlx-engineは、当初、テキストのみのモデルとビジョン対応モデルの両方をサポートするために、シンプルな「フォークされた」アーキテクチャで開発されました。

undefined

mlx-engineのフォークされたビジョンモデルアーキテクチャ。黄色 = テキストモデルコンポーネント。青 = ビジョンモデルコンポーネント。

モデルがビジョン対応の場合、mlx-vlmのモデル実装(テキスト+ビジョン)が排他的に使用されます。モデルがテキストのみの場合、mlx-lmのモデル実装(テキスト)が排他的に使用されます。

各パスでは、異なるテキストモデル実装(mlx-lmまたはmlx-vlmのいずれか)が使用されていました。

問題点:フォークされたアーキテクチャ

mlx-engineのナイーブなフォークされたアーキテクチャには、以下の問題がありました。

  • mlx-lmmlx-vlmの機能が完全に同等ではない、または動作に微妙な違いがある場合、どちらを使用すべきでしょうか?
    • マルチモーダルモデルとテキストのみのモデルとの対話体験における乖離をどのように抑制できるでしょうか?
    • ある実装が他方よりも性能が良い、または他方にはないバグを含んでいると仮定します。mlx-lmmlx-vlmのどちらを使用するかをどのように一貫して選択すればよいでしょうか? リクエストに応じて(複雑な方法で)これら2つのロードをホットスワップすべきでしょうか?
  • 両者を切り替えたり、マルチモーダルモデルのテキストのみのバリアント(例: このGemma 3テキスト専用モデル)の使用をサポートしたりすると、特定のモデルにおけるバグとメンテナンスの範囲が2倍になります。これは、同じ基盤となるモデルを推論するために、条件付きで使用される2つの共存する実装があるためです。したがって、LM Studioでバグのないエクスペリエンスを提供するためには、2つの別個のモデルがバグフリーであることを保証する必要があります。
undefined

同じテキストモデルの2つの異なるバージョンが存在する

私たちの解決策:両方の利点を活用する

私たちは、mlx-lmmlx-vlmのコアコンポーネントを組み合わせて、すべてのMLX LLMおよびVLM向けに「統一された」(フォークなしの)推論エンジンを作成しようとしました。

@awni@Blaizzyとの貴重な議論の後、以下の貢献を通じてこれを実現しました。

mlx-lm

mlx-vlm

undefined

新しいmlx-engineの統合されたビジョンモデルアーキテクチャ。mlx-lmテキストモデルはmlx-vlmビジョンアドオンで拡張されます。

この統一アーキテクチャでは、マルチモーダルLLMのコアテキストモデルを常にmlx-lm(2)からロードし、mlx-vlmからわずかに異なるテキストモデルをロードする可能性はなくなりました。

その後、mlx-vlmの機能(3,4)を使用してmlx-lmテキストモデルが理解できる画像からの埋め込みを生成するVisionAddOnを条件付きでロードします(mlx-engine内のGemma3VisionAddOnの実装を参照)。

この設定により、マルチモーダルモデルを合理化された単一パス方式で推論できるようになりました。これにより、LM StudioのMLXエンジンをよりクリーンで保守性の高いものとして、パフォーマンスを向上させてリリースすることができます。

Gemma 3 12B QAT、両方ともM3 MacBook Pro上でMLX 4ビット。統一アーキテクチャにより、後続のTTFTが約25倍高速化。


詳細: mlx-engineにおけるVisionAddOns

LM Studioの新しいmlx-engine統一アーキテクチャの要点は、すべてのマルチモーダルモデルに対してmlx-lmのテキストモデル実装を使用できる一方で、mlx-vlmのビジョンモデルコンポーネントを活用してテキストモデルが理解できる画像埋め込みを生成できる点にあります。

これは、マルチモーダルモデルの画像埋め込みを生成するために使用できるモジュラーコンポーネントであるVisionAddOns(ソース)を導入することで実現されます。これらのVisionAddOnsは、BaseVisionAddOn抽象クラスによって定義された共通インターフェースを実装します。例えば

class BaseVisionAddOn:
    """
    Base class that defines the interface for a VisionAddOn.
    """

    @abstractmethod
    def __init__(self):
        """
        Where load of vision model components is intended to occur.
        """

    @abstractmethod
    def compute_embeddings(
        self,
        text_model: nn.Module,
        prompt_tokens: mx.array,
        images_b64: List[str],
    ) → mx.array:
        """
        Returns input embeddings for the language model after
        text/image merging of the prompt
        """

VisionAddOnsは、mlx-lmstream_generate()関数の新しいinput_embeddings引数に入力できる画像埋め込みを生成します(mlx-lmへのコミットを参照)。

現在、Gemma 3(Gemma3VisionAddOn)とPixtral(PixtralVisionAddOn)が、統一アーキテクチャに移行された唯一の2つのモデルです。しかし、このアーキテクチャは、より多くのVisionAddOnsmlx-enginevision_add_onsディレクトリに簡単に追加でき、その後こちらModelKitに組み込まれるように設計されています。

    VISION_ADD_ON_MAP = {
        "gemma3": Gemma3VisionAddOn,
        "pixtral": PixtralVisionAddOn,
    }

私たちのオープンソースリポジトリhttps://github.com/lmstudio-ai/mlx-engineでこのパターンを拡張する貢献は大変歓迎します! 例として、mlx-engineのイシューExtend VisionAddOn Pattern to Qwen2.5VL #167をご覧ください。


フィードバックと貢献