LM Studioにおける統合されたマルチモーダルMLX
エンジンアーキテクチャの紹介
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
のビジョンモデル実装は、テキストモデルが理解できる画像埋め込みを生成するための「アドオン」としてモジュール的に使用されています。
新しいmlx-engine
の統合されたビジョンモデルアーキテクチャ。mlx-lm
テキストモデルはmlx-vlm
ビジョンアドオンで拡張されます。
これにより、マルチモーダルMLX
VLM (例: GoogleのGemma 3) を使用する際のパフォーマンスとユーザーエクスペリエンスが大幅に向上します。例えば、VLMとのテキストのみのチャットでもプロンプトキャッシングの恩恵を受けられるようになりました。これは以前はテキストのみのLLMに限定されていた機能で、その結果、後続の応答が劇的に高速化されます。これにより、MLX
VLMはテキストタスクにおいてテキストのみのLLMとシームレスに交換可能になり、さらにビジョン機能をおまけとして提供します。
👓 問題、解決策、そしてLM StudioのMLX
エンジンでこの統一アーキテクチャをどのように実現したかについて、技術的な詳細を読み進めてください。
マルチモーダルLLMは、複数の入力モダリティを受け取ることができるLLMです。これは、テキスト入力の処理に加えて、画像や音声入力も受け入れることができることを意味します。
新しいMLXエンジンはまだ音声を扱っていませんが、このアプローチが音声入力にも機能するように計画しています。
一般的に、ビジョン対応LLMは以下のフローで画像入力を取り込みます
マルチモーダルビジョンLLMの一般的な運用フロー:画像をテキストモデルが理解できる埋め込みに変換し、テキストモデルで出力を生成する
"これは何ですか?"
→ [0.83, 0.40, 0.67, ...]
image.png
→ [0.28, 0.11, 0.96, ...]
[0.83, 0.40, 0.67, ...]
+ [0.28, 0.11, 0.96, ...]
→ [0.83, 0.40, 0.67, ..., 0.28, 0.11, 0.96, ...]
プロンプトに画像がない場合、「結合された埋め込み」は単にテキスト埋め込みとなります。
MLX
Pythonのエコシステムには、Apple Silicon上でLLMと対話するためのモデル実装とインフラを提供する2つの主要なライブラリがあります
歴史的に、mlx-lm
はマルチモーダル機能を持たないテキストのみのモデルの実装を含んでいましたが、mlx-vlm
はMLX
VLM実装の事実上の本拠地となっています。
mlx-lmとmlx-vlmにおけるモデル実装コンポーネント。黄色 = テキストモデルコンポーネント。青 = ビジョンモデルコンポーネント。
LM Studioのmlx-engine
は、当初、テキストのみのモデルとビジョン対応モデルの両方をサポートするために、シンプルな「フォークされた」アーキテクチャで開発されました。
旧mlx-engine
のフォークされたビジョンモデルアーキテクチャ。黄色 = テキストモデルコンポーネント。青 = ビジョンモデルコンポーネント。
モデルがビジョン対応の場合、mlx-vlm
のモデル実装(テキスト+ビジョン)が排他的に使用されます。モデルがテキストのみの場合、mlx-lm
のモデル実装(テキスト)が排他的に使用されます。
各パスでは、異なるテキストモデル実装(mlx-lm
またはmlx-vlm
のいずれか)が使用されていました。
mlx-engine
のナイーブなフォークされたアーキテクチャには、以下の問題がありました。
mlx-lm
とmlx-vlm
の機能が完全に同等ではない、または動作に微妙な違いがある場合、どちらを使用すべきでしょうか?mlx-lm
とmlx-vlm
のどちらを使用するかをどのように一貫して選択すればよいでしょうか? リクエストに応じて(複雑な方法で)これら2つのロードをホットスワップすべきでしょうか?同じテキストモデルの2つの異なるバージョンが存在する
私たちは、mlx-lm
とmlx-vlm
のコアコンポーネントを組み合わせて、すべてのMLX
LLMおよびVLM向けに「統一された」(フォークなしの)推論エンジンを作成しようとしました。
@awniと@Blaizzyとの貴重な議論の後、以下の貢献を通じてこれを実現しました。
mlx-lm
mlx-vlm
新しい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-lm
のstream_generate()
関数の新しいinput_embeddings
引数に入力できる画像埋め込みを生成します(mlx-lmへのコミットを参照)。
現在、Gemma 3(Gemma3VisionAddOn)とPixtral(PixtralVisionAddOn)が、統一アーキテクチャに移行された唯一の2つのモデルです。しかし、このアーキテクチャは、より多くのVisionAddOns
がmlx-engine
のvision_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をご覧ください。
mlx-engine
リポジトリ(https://github.com/lmstudio-ai/mlx-engine)をご覧いただくか、ご貢献ください。