Dify で Mac 専用 MLX 版 Qwen2-VL を使う (たぶん、LM Studio のバグ技)

前回 Pixtral (Mistral 社のビジョンモデル) の日本語コミュニケーション能力と画像認識の性能の高さに感動しつつも、画像の中の日本語は読めないことを知り傷心したボク。Ollama のバージョンアップで正式に利用できるようになった Meta 社の画像認識モデルである Llama3.2 Vision 11B こそが本命であるはずだ!と早速試したんですが、あまりのぱっとしなさに記事にすることもありませんでした。ローカルで「使える」オープンモデル・ウェイトのビジョンモデルの登場はまだ先なのか、または画像内の日本語が認識できる LLM なんて 32GB RAM の Mac には一生やってこないのか、っていうか OCR したいなら普通に macOS 標準のプレビューでいいじゃんか、ということなのか。なんて思っていたら、普通にありました。とっくに出てました。しかもボクが最近何かとメインで使っている Alibaba 社の Qwen ファミリーに。そう、Qwen2-VL です。

パラメータ数は 2B、7B、72B
はい、日本語正式サポートしてるぅ (上のサイトを Safari で日本語に翻訳してもらった一部のキャプチャ)
画像内の日本語認識が不要なら、Pixtral がオススメ

簡単に使うなら、やはり LM Studio 単体で

LM Studio の虫眼鏡アイコンで “qwen2-vl” と打ち込み、横のチェックボックスで MLX を選べば mlx-community にて変換された MLX 版の Qwen2-VL がずらずら出てきます。一番大きい 7B-Instruct-bf16 でも 16.60 GB なので、32GB RAM の Mac でも問題無く動きそうですが、そこはビジョンモデル、テキストオンリーのモデルと違ってメモリを喰います。BF16 はたまに CPU を使ったり頻繁にハルシネーションをおこしたりするヤンチャ坊主なので、オススメは 7B-Instruct-8bit です。というわけで、LM Studio で動けばそれでヨシ、という方はこれ以降読まなくて大丈夫です。ステキなビジョンモデルライフをエンジョイください。

bf16 のスクリーンショットですが、オススメは Qwen2-VL-7B-Instruct-8bit

Ollama では動かない

さて、普段はローカル LLM のモデルプロバイダとして使っている Ollama をなぜ使わないのかということを説明します。Ollama はバックエンドに llama.cpp を使っていますが、llama.cpp は (今のところ) ビジョンモデルに対応していません。Llama3.2 Vision は、Ollama の開発者が llama.cpp に依存せずに 頑張ってどうにか動くようにした (?) らしいです。が、Llama3.2 Vision 11B のパフォーマンスが 32GB RAM の M2 Max ではイマイチでして、ボクはすぐに使うのやめちゃいました。英語だけで OK の方は良いのかもしれないですね。

Safetensor は MPS で動かすこともできる

↓の Zenn に投稿された金のニワトリさんの記事に、MPS でサンプルコードを動かす方法が紹介されています。Llama3.2 Vision にガッカリしていたときに試したので、えらく感動しました。Mac の GPU で素のビジョンモデル Qwen2-VL が動いていたので。

https://zenn.dev/robustonian/articles/qwen2_vl_mac

さて、API で利用するにはどうするか?

macOS で Qwen2-VL を動かすには、元の Safetensor 版か、MXL 版のどちらか、ということがわかったわけですが、やっぱり Dify から使いたくなってしまいます (よね?)。本家の GitHub にあるワンライナーの API サーバ起動方法は vllm という Python のライブラリを使用しており、残念ながら Mac 未対応です。他の方法を探ると、言語モデルの MLX 用なら割といろんな API サーバライブラリがあるのですが、ビジョンモデルに対応したものとなるとかなり絞られました。さらにそこから実際に Qwen2-VL を使おうとすると、そもそも Dify に登録できなかったり、無理矢理登録できても例外しか発生しないという悲しい状況が 2週間ほど続きました。

同じように MLX のビジョンモデルである Pixtral は LM Studio が API サーバとなり Dify から使えるのに、Qwen2-VL を OpenAI コンパチモデルとして登録しようとすると、最初の ping (モデルが本当につながるかどうかのテスト) に画像が含まれないために Qwen2-VL がエラーを返してきて登録ができません。あらゆる方法を自分なりにいろいろと試しては失敗し、を繰り返していたある日、突然でたらめな組み合わせで動き始めました。詳細は以下に続きます。

成功した構成とバージョン

LM Studio または Dify の新しいバージョンではバグが潰されてこの方法が使えなくなるか、はたまた正式にサポートされて普通に動くようになるかわかりませんが、とりあえず ↓ の構成&バージョンで動作が確認できています。

  • Dify: 0.11.2 (0.11.1 でも動いた実績あり)
  • LM Studio: 0.3.5 (Build 2)
  • Pixtral: mlx-community/pixtral-12b-8bit
  • Qwen2-VL-7B: mlx-community/Qwen2-VL-7B-Instruct-8bit (FastMXL でダウンロードしたモデル)
  • Qwen2-VL-2B: mlx-community/Qwen2-VL-2B-Instruct-4bit (LM Studio でダウンロードしたモデル)
  • macOS: Sequoia 15.1.1 (上記アプリが動けば、多分何でも大丈夫)

Dify から LM Studio の Qwen2-VL を使う方法

やり方は、ほぼ前回の記事と同じです。異なっているのは、LM Studio には Qwen2-VL をロードしておくだけです。Dify のアプリで使うモデルは mlx-community/pixtral-12b-4bit のままで構いません。というか、上記バージョンでは Dify に LM Studio 上の Qwen2-VL を登録できないので、Dify は Pixtral を呼び出しているつもり、LM Studio は読み込み済みの Qwen2-VL を使って推論をする、という状況になります。本来 LM Studio は指定されたモデルを読み込むはずなので、バグだと思いますが、これで動きます。

実行サンプル

いくつか参考となりそうな画像を貼っておきます。

テキストの日本語が怪しいことは多いです
提灯の文字を読んで「雷門」と回答したわけでは無いらしい。っていうか「唐傘 (提灯)」って
文字だけなら手書きの日本語を読めます
結構がんばってる。Markdown の罠でインデックス番号が各行に振られているところと、写真一番下のテキストが斜めになってしまっているところは読めていないのが残念。ラウンドを繰り返すか、プロンプトを工夫すれば精度はあがるかも

感想

性能的には、画像認識の精度や知識は Llama3.2 Vision モデルよりは良いけど、Pixtral ほどじゃ無いです。日本語 OCR メインの用途なら macOS のクイックルックやプレビューの方が相当優れています。というわけでやはり、期待したほどでは無いな、というのが正直な感想です。大量の RAM を積んでいる方が 72B のモデルを動かすと、また違う感想になるかもしれません。ビジョンモデルの使いどころも定まっていないボクにとっては、「普通には動かせないものを動かす」というハッカー的欲求を満たせたのでとりあえず満足、という感じですかね。

ところで最近のローカル LLM はほとんど Qwen2.5 シリーズしか使ってません。日本語チャットは qwen2.5:14b-instruct-q8_0 (15GB) もしくは qwen2.5:32b-instruct-q4_K_M (19GB)、コーディングは qwen2.5-coder:14b-instruct-q8_0 (15GB) もしくは qwen2.5-coder:32b-instruct-q4_K_M (19GB) です。速度や大きなコンテキスト長を扱いたいとき (注) は 15GB サイズのモデル、精度が欲しいときは 19GB のモデルを使っています。欧米のモデルよりも日本語が得意というのもありますが、各種リーダーボード (日本語オープン、日本語総合コーディング) でも Qwen シリーズは高評価ですので、未体験の方はゼヒ。

ついでにですが、最近リリースされた推論 (reasoning) 重視モデルの QwQ-31B-Preview も普通に Ollama でダウンロードして使えます。32GB RAM の M2 Max での生成速度は速くない (7.5 TPS 程) ですが、性能というか、考え方の方向性がこれまでとかなり違い、ヤバいです。次元が違う感じ。

(注: 大きなサイズのモデルだとコンテキスト長を小さくしないと遅くなります。詳しくはこちらの記事をご覧ください:)

最後に、ビジョンモデルの活用法を一つ思いつきました。大量の素材用写真が無造作にフォルダに入っているみたいな状況があれば、それぞれの写真の特徴を macOS の「情報を見る」のコメント欄に書き込んでくれるスクリプトなんてよさそうですね。Spotlight で検索できるようになるし。Qwen2-VL はビデオの読み込みもできるらしいので、整理に困っている大量の画像・映像を持っている人は良いかもですね。

Image by Stable Diffusion (Mochi Diffusion)

Pixtral の記事のトップ絵に対抗した内容で、登場人物を alibaba にし、場所を Alibaba Cloud 社があるらしい中国の Yu Hang にしてみました。きっと本当はこんな町並みでは無いのでしょうが、ボクの想像と概ね近いものを選びました。

Date:
2024年11月27日 23:59:11

Model:
realisticVision-v51VAE_original_768x512_cn

Size:
768 x 512

Include in Image:
masterpiece, intricate, realistic, sharp focus, photograph, alibaba walking in Yu Hang, china

Exclude from Image:

Seed:
1426778725

Steps:
20

Guidance Scale:
20.0

Scheduler:
DPM-Solver++

ML Compute Unit:
CPU & GPU

Mac のローカルオンリー環境で、画像認識 AI の Pixtral 12B MLX 版を使う (LM Studio 編)

フランスの生成 AI 企業のトップである Mistral 社が、画像認識にも対応したマルチモーダル モデルの Pixtral 12B を Apache 2.0 ライセンスでリリースしています。画像を読み込ませると、何が映っているかを答えてくれるタイプの AI ですね。こちらを、ボク得意の Mac ローカルオンリー環境で実行した方法を共有します。今回使ったのは、LM Studio と Dify です。Pixtral を実行するだけなら LM Studio の 0.3.5 以上で OK ですが、Dify から API 経由で LM Studio を利用してみたので、後半にはその設定方法を紹介してます。

環境について

Mac

ボクの M2 Max Mac Studio には 32GB しか RAM が積まれていないので、Dify だけは別の M1 Mac Mini で動かしています。これから Mac (M4 搭載 Mac Mini とか MacBook Pro とかいいですな〜) を買う方でローカル LLM も試したいと考えている方は、頑張って 64GB 以上の RAM (ユニファイドメモリ) を搭載した機種を買いましょう。それより少ない RAM 容量で LLM を楽しむのはいろんな工夫や妥協が必要で苦労します。本ブログにはそんな切ない記事があふれています。

RAM が少ないと、こんな感じのやりくりが必要になります

LM Studio

v0.3.0 で、インターフェイス含め大幅なアップデートがありました (v0.2 シリーズを使っている場合は、新規でインストールが必要)。その後も着々とバージョンアップが進められ、API 経由で他のアプリから LLM を利用できるようになり、Mac の GPU 用に最適化された MLX バージョンの LLM が動くようになり、v.0.3.5 で Pixtral に対応しました。また、同バージョンでは、メモリ喰い気味の GUI を閉じてサーバだけ動かす Headless mode にも対応したということで興奮したのですが、実際は LLM (pixtral-12B@4bit) がロードされると LM Studio Helper が 12~20GB ほどメモリを使用し続けるので、現状はまだ Ollama のような使い勝手は望めません。残念。

その他 LM Studio v0.3.5 の詳細はこちらをどうぞ: https://lmstudio.ai/blog/lmstudio-v0.3.5

Ollama

2024年 11月 4日現在、Ollama では Pixtral がサポートされていません。Llama 3.2 vision が動くらしい v0.4.0 は pre-release されているので、正式リリースや Pixtral のサポートも時間の問題かもしれません。

Ollama v0.4.0 に関してはこちらをどうぞ: https://github.com/ollama/ollama/releases/tag/v0.4.0-rc6

Dify

これから始める方は最新版になっちゃうんでしょうが、最近、リリース直後は多くのバグで悩むケースが散見されています。ボクはまだ v0.9.1-fix1 を使用しているため、v0.10 以降のファイル添付方法が変わったバージョンでは見た目や使い方が違う可能性があります。Dicord での情報収集が良いと思います。

LM Studio で MLX 版 Pixtral を動かす

LM Studio v0.3.5 以上のインストールは完了してる前提で

無料の Mac 用アプリがここからダウンロードできます。

Pixtral 12B 4-bit をインストール

32GB RAM の Mac では 4-bit (量子化) 版をオススメします。LM Studio 込みでオンメモリで動きます。もっと RAM を積んでいる方は、お好みで 8bit や bf16 版をどうぞ。

虫眼鏡アイコンの Discover → 検索窓に「pixtral」と入力 → MLX だけにチェックを入れる (GGUF を外す) → モデル名やファイルサイズを確認 → Download ボタンクリック

ボクのインターネット環境の問題かわかりませんが、ダウンロード中何度もタイムアウトしていました。左下のボタンでたまに確認し、下のような Timed-out が出ていたら再読み込みボタンをクリックしましょう。

他のエラーで止まることもありますが、再読込で進められます

Chat で試す

Dify で使う必要が無い方 (え?みんなそう?) は、そのまま LM Studio で Pixtral が楽しめます。

吹き出しアイコンの Chat → Select a model to load ドロップダウンから、ダウンロードした Pixtral を選択 → Load Model ボタンクリック

例として、以前没にしたトップ絵をドラッグアンドドロップして「この画像について教えてください」としたところが以下画像です。Pixtral は Mistral Nemo 12B をベースにしていると言うことで、上手な日本語でやりとりができます。ちなみに、Nejumi さんのリーダーボードでは、Mistral Nemo 12B は elyza/Llama-3-ELYZA-JP-8B より日本語性能が上らしいです。確かに。

LM Studio への日本語入力には難あり。エンターは確定+送信になり、最後の確定部分がチャット窓に残ります

他にもいくつか AI による生成画像を読み込ませてみたところ、大体 30 TPS (トークン/秒) で、正しく詳細な回答が得られました。個人的に画像認識 AI の正しい使い道は見つけられていないのですが、想像以上の性能です。

というわけで、Mac のローカル環境で画像認識マルチモーダル LLM を試したいだけ、という方はお疲れ様でした。いろいろとお試しください。

以降は Dify から API で LM Studio のモデルを使う方法になります。

LM Studio API サーバ設定

基本

Developer アイコンから設定します。全ての Off/On スイッチが表示できていないと思うので、まずは Developer Logs の境界線をつかんで下に押し広げましょう。Start ボタンで API サーバが利用できますが、確認しておいた方がよさそうな設定は以下となります。

  • Server Port: デフォルトで 1234
  • Server on Local Network: 他の Mac から API アクセスするなら、On
  • Just-in-Time Model Loading: Dify からモデルを選択したいなら、On
これで Start をクリックすれば、API サーバは起動します
LAN に公開した場合はこのポップアップが出るので、許可します

ヘッドレスモード (GUI 無し API サーバのみ)

右下のギアアイコンまたはコマンド+カンマで App Settings を開き、Local LLM Service (headless) を有効にします。これで、GUI を Quit しても API サーバは動き続けます。

GUI を開いたり、サーバを停止したりするには、メニューバーのアイコンを開きます。メモリを解放するなら、Unload All Models または、Quit LM Studio を選びましょう。

Dify から LM Studio API サーバに接続できるようにする

モデルプロバイダーにある、OpenAI-API-compatible に登録します。

MLX 版の Tanuki 8B も登録済みの図

設定内容はこんな感じです:

  • Model Name: モデル名 (例: mix-community/pixtral-12b-4bit)
  • API Key: 無し
  • API endpoint URL: 例 http://192.168.1.10:1234/v1 とか http://localhost:1234/v1 (ポート番号/v1 を忘れずに)
  • Completion mode: Chat
  • Model context size 2048
  • Upper bound for max tokens: 2048
  • Function calling: Not Support
  • Streaming function calling: Support
  • Vision Support: Support
  • Delimiter for streaming results: \n\n (区切り文字が入力必須ですが、とりあえず改行二つのこれで動きます)

Dify で動く超シンプル画像認識アプリ

DSL ファイルを下に貼っておきますが、チャットボットの Chatflow を作り、機能で「画像アップロード」を有効にして、モデルとして Pixtral を選んでいるくらいの単純なものです。

DSL を開く

app:
description: 32GB RAM オンメモリで動作するビジョンモデル。Pixtral は MLX 版で、LM Studio で実行中。事前に LM Studio
サーバを実行しておくこと
icon: eyes
icon_background: ‘#D5F5F6’
mode: advanced-chat
name: Pixtral 12B 4Bit (MLX)
use_icon_as_answer_icon: true
kind: app
version: 0.1.2
workflow:
conversation_variables: []
environment_variables: []
features:
file_upload:
image:
enabled: true
number_limits: 3
transfer_methods:
– local_file
– remote_url
opening_statement: ”
retriever_resource:
enabled: false
sensitive_word_avoidance:
enabled: false
speech_to_text:
enabled: false
suggested_questions: []
suggested_questions_after_answer:
enabled: false
text_to_speech:
enabled: false
language: ”
voice: ”
graph:
edges:
– data:
isInIteration: false
sourceType: start
targetType: llm
id: 1730552831409-source-llm-target
source: ‘1730552831409’
sourceHandle: source
target: llm
targetHandle: target
type: custom
zIndex: 0
– data:
isInIteration: false
sourceType: llm
targetType: answer
id: llm-source-answer-target
source: llm
sourceHandle: source
target: answer
targetHandle: target
type: custom
zIndex: 0
nodes:
– data:
desc: ”
selected: false
title: 開始
type: start
variables: []
height: 54
id: ‘1730552831409’
position:
x: 30
y: 253.5
positionAbsolute:
x: 30
y: 253.5
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
– data:
context:
enabled: false
variable_selector: []
desc: ”
memory:
query_prompt_template: ‘{{#sys.query#}}’
role_prefix:
assistant: ”
user: ”
window:
enabled: false
size: 10
model:
completion_params:
temperature: 0.7
mode: chat
name: mlx-community/pixtral-12b-4bit
provider: openai_api_compatible
prompt_template:
– id: 9011766a-9f0d-45d2-87bb-8f2665ad80db
role: system
text: ”
selected: true
title: Vision
type: llm
variables: []
vision:
configs:
detail: high
enabled: true
height: 98
id: llm
position:
x: 334
y: 253.5
positionAbsolute:
x: 334
y: 253.5
selected: true
sourcePosition: right
targetPosition: left
type: custom
width: 244
– data:
answer: ‘{{#llm.text#}}’
desc: ”
selected: false
title: 回答
type: answer
variables: []
height: 107
id: answer
position:
x: 638
y: 253.5
positionAbsolute:
x: 638
y: 253.5
selected: false
sourcePosition: right
targetPosition: left
type: custom
width: 244
viewport:
x: 49.4306562198135
y: 352.30093613089844
zoom: 0.7237754523423506

アプリを公開するとチャットウィンドウに画像をドラッグアンドドロップできるので、画像と質問を入力すれば回答が返ってきます (初回の LLM のロードが行われる時はタイムアウトするかもしれません。少し待って再度コメントを投げると返事が来ます)。Dify から使うと若干スピードが落ち、何度か試した後確認すると、20 TPS 以下でした。実行時のメモリプレッシャーはこんな感じ ↓ です。モデルがロードされた後のメモリの使用量が、ロード前ほど下がらないことがわかると思います。この時で LM Studio Helper のメモリ使用量は 12GB ほどでした。

以前の記事で使った画像を読ませたところ ↓

追加質問の余地がないほどの回答

Pixtral さんは画像の中の日本語は読めない (日本語 OCR としては使えない)

チャットでは流ちょうな日本語でやりとりできるのですっかりその気になっていたのですが、画像の中の日本語は読めないみたいです。ベーマガのペーパー・アドベンチャーをスキャンして遊びやすくしようと思っていたのですが、そういう用途には使えないようです (注意: 雑誌のスキャンを無許可で公開すると著作権侵害となります)。

なんかそれっぽいことが書いてあるけど、実際見比べると全然違う

雷門が歌舞伎町に見えてしまえば、文字だってそう読めてしまいます。

大提灯を指摘すれば気づいてくれるかも、との期待は打ち砕かれました

かわいい手書き文字でもテスト。うーむ、日本語 OCR として使うのは諦めた方がよさそうです。

念のため英語とフラ語でも聞いてみました。

ちょっと!誰よ、ひとみって!
朝起きたら、質問の前にあいさつをしよう

面白かったのでいくつも画像を貼ってしまいましたが、日本語 OCR 能力は無いという結論に変更はありません。アルファベットなら手書きもまーまーイケそうなので残念ですが、このパラメータ数 (12B) ですし日本語に特化しているわけでもないわけですから、欲しがりすぎてはいけませんね。

(おまけ) Mac で OCR するなら、写真の文字をなぞってコピーするだけ

話はそれますが、Mac なら画像や写真の文字部分をなぞればほぼコピーできちゃいます。素のままでできるはずですが、うまくいかないときはプレビューで開いて、ツールからテキスト選択選べばほぼイケるかと。

ペーパー・アドベンチャーの写真の一部を選択した状態

全文載せると著作権侵害になるので、冒頭部分のみ (関係者の方からご指摘あれば削除いたします)。適当に iPhone で撮影した写真でもこの認識力。改行位置の的確さもほぼ OK。これが OS レベルで実装されているのですごい。すごいありがたい macOS。

1 あなたは今、この町に入るための道に立っている。
北→7 西→26
2 君は必死に怪物と戦ったがあと一歩というところで殺されてしまった。
GAME OVER
3
君は逃げきれず、つかまってしまった。
GAME OVER
4
5
ここは森の入口だ、入れ。→109小さな木の箱があった。開けると、ダイヤ,サファイヤ、ルビーがあった。】
つだけ持っていってもよい。
ダイヤ→90 サファイヤ→39
ルビー→53
6
怪物半魚人が現れた。水中なので逃げられない。戦え。
体力が9以上→28 9未満→2
7怪物ゾンビーが現れた。戦うか,逃げ
るかさめよ。
戦う→37
逃げる→61
8
ここは武器屋だ。きみは金貨を50枚持っている。なにか買え。
剣,金貨50枚→16号,金貨40枚→69

Apple Inteligence もまもなく使えるようですし、AI スタートアップで収益上げるって難しそうだな、と思いました。

Image by Stable Diffusion (Mochi Diffusion)

おフランスをパリジェンヌが歩いているおしゃれな画像を期待して描いてもらいました。

Date:
2024年11月3日 15:13:32

Model:
realisticVision-v51VAE_original_768x512_cn

Size:
768 x 512

Include in Image:
masterpiece, intricate, realistic, sharp focus, photograph, woman walking in Paris

Exclude from Image:

Seed:
2526772693

Steps:
23

Guidance Scale:
20.0

Scheduler:
DPM-Solver++

ML Compute Unit:
CPU & GPU

© Peddals.com