マルチモーダル／ビジョン系モデルのローカル環境の構築方法

## 本記事の要約
　ある機会に「AIを使って製造ラインでの不良品検査の自動化がしたい」という話を聞き、マルチモーダルモデルの現状を調査したのがきっかけで最近３か月位の情報をまとめてみました。
　最近モデル続出のマルチモーダル／ビジョン系モデル（以下VLM）のローカル環境下での画像認識やファインチューニングのツール類を試した結果のまとめになります。試したツール類は以下の通りです。
　＜画像認識等のInference関係＞
 1. MLX-VML：　Mac用のAIフレームワークMLXをベースにしたVLM対応ツール
 2. Ollama :　ローカルLLM等のフレームワーク
 3. Transformers :　HuggingFaceのフレームワーク

 　＜日本語化や画像タスクのファインチューニング関係＞
 1.　MLX-VLM : ファインチューニング可能なモデルは[こちら](https://github.com/Blaizzy/mlx-vlm/blob/main/mlx_vlm/LORA.MD)
 2.　Transformers :　collaterを工夫するか、custom tarinerを作成して対応


## １．推論(Inference)
　現時点で各ツールが対応可能なVLMを以下にまとめました。

 | ツール | 対応モデル
|:-----------:|:------------:|
| [mlx-vlm](https://github.com/Blaizzy/mlx-vlm/tree/main/mlx_vlm/models)    |    Florence2, idefics2/3, llava/llava_bunny/llava_next, mllama, molmo, multi_modality, paligemma, phi3_v(phi3.5_vを含む), pixtral, qwen2_vl 等   |
| [Ollama](https://ollama.com/search?c=vision)  |    llama3.2-vision, llava, llava-llama3, bakllava, moondream, llava-phi3minicpm-v, qnguyen3/nanollava 等    | 125M/350M/600M/1B/1.5B | LlamaForCausalLM |CC-BY-NC 4.0|
| [Transformers](https://huggingface.co/docs/transformers/tasks/image_captioning)  |HuggingFaceの各モデル |


## ２．ファインチューニング
　現時点で各ツールが対応可能なVLMを推論同様に以下にまとめました。

 | ツール | 対応モデル
|:-----------:|:------------:|
| [mlx-vlm](https://github.com/Blaizzy/mlx-vlm/blob/main/mlx_vlm/LORA.MD)    |    Qwen2, LLaVA (except for LLaVA-Next), Pixtral, Idefics2, Deepseek-VL, Paligemma, Mllama (Llama-3.2-vision)   |
| [Transformers](https://huggingface.co/docs/transformers/tasks/image_captioning)  |HuggingFaceの各モデル

## ３．ローカル環境の構築例

　テキスト生成モデルと異なるのは、特にファインチューニングのツールに制約が多く、Macの場合には選択肢が余り無いのが現状です。自由度を求めるとどうしてもTransformersを選択せざるを得なくなります。もちろんTessorflowやtorchを駆使してやる方法も有りますが、かなりの知識と手間が必要になりそうです。ここではmlx-vlmとHuggingFaceのTransformersを中心に紹介します。

## 3-1. 推論
　まずはmlx-vlmをインストールします。
```
pip instal mlx-vlm
```
　mlx-vlmは下記のコマンドで推論できます。generateを使って--modelでモデルを指定し、--imageで認識したい画像のURL又はPathを指定すると、画像のキャプションが出力されます。

 ```
 python -m mlx_vlm.generate --model mlx-community/Florence-2-base-ft-4bit --max-tokens 100 --temp 0.0 --image http://images.cocodataset.org/val2017/000000039769.jpg
 ```
　pythonのプログラムから起動する場合は下記の様になります。
```
import mlx.core as mx
from mlx_vlm import load, generate
from mlx_vlm.prompt_utils import apply_chat_template
from mlx_vlm.utils import load_config

# Load the model
model_path = "mlx-community/Florence-2-base-ft-4bit"
model, processor = load(model_path)
config = load_config(model_path)

# Prepare input
image = ["http://images.cocodataset.org/val2017/000000039769.jpg"]
prompt = "Describe this image."

# Apply chat template
formatted_prompt = apply_chat_template(
    processor, config, prompt, num_images=len(image)
)

# Generate output
output = generate(model, processor, formatted_prompt, image, verbose=False)
print(output)
 ```
 
 Transformersを使った推論は各モデルのUsageを参照して下さい。

 ## 3-2. ファインチューニング
 mlx-vlmを使ったファインチューニングもコマンドラインで下記のようにloraで学習させることができますが、mlx-lmのfuse相当の機能が無いようなので、adapterとしての利用が前提のようです。またdatasetは"images"と"messages"のcolumnが必要になるので、テスト用でしたら私が用意したdatasetを使って試してみて下さい。
 ```
 python lora.py --dataset /path/to/your/dataset --model_path /path/to/your/model --epochs 2 --batch_size 4 --learning_rate 5e-5
 ```
 test用のdataset: huggingface_repo_id = [aipib/mlx-vlm-jp-01](https://huggingface.co/datasets/aipib/mlx-vlm-jp-01)~03

  Transformersを使って学習させる場合はフルパラメータとLoraの両方が選べますが、モデルによってはテキスト系の処理のようにtrlやSFTが使えないので、カスタムTrainerを書く必要があります。基本的な流れは下記の通りです。
  ① 必要なモジュールのimport（transformers、timm、einops、peft、datasetsなど）
  ② ビジョン系モデルの読み込みとデータセットの読み込み
  ③ 学習させるタスク（CAPTIONやOCRなど）に応じたDatasetクラスの定義とcoolate関数の定義
  ④ ③を使用してdataloaderを定義
  ⑤ Loraを使用する場合はpeftでLoraのConfigを定義
  ⑥ Vision Encoderのパラメータを凍結してメモリ等を節約
  ⑦ ④のdataloaderを使ってカスタムTrain関数を定義して、epochと学習率を設定して実行
  ⑧ モデルの保存・adapterのマージ・Huggingfaceにアップロード　等の後処理

　具体的なpythonコードは、データセットの編集処理も含めると本記事では長くなるので、Microsoft社のFlorence-2の日本語化用のファインチューニングをするために作成したコードを別途投稿予定ですので、そちらを参考にして下さい。

 ## 3-3. ローカル環境でのお勧めVLM

 　ビジョン系モデルの選択は利用用途により変わってくると思いますが、Ollama等の利用があまり期待できないので、実際に試した結果GPUやメモリを節約できる下記のような小規模モデルがお勧めです。
  ① Florence-2:largeとbaseの2種類があり、それぞれ各画像処理タスクを学習済みのlarge-ft/base-ftモデルもあります。基本は英語対応のみですが、私見ですが、base-ftで十分使えるので敢えてlargeを選択する必要は感じませんでした。GGUF・Ollamaは未対応ですが、mlx-vlmの推論は使えます。
  ② toshi456/llava-jp-1.3b-v1.1: 日本語が扱えるllava系のモデルです。[こちらで紹介されています](https://qiita.com/toshi_456/items/248005a842725f9406e3)。紹介記事に推論やファインチューニングのスクリプトのあるGitHubも記載されています。
  ③ qnguyen3/nanoLLaVA-1.5: 基本英語の対応ですが、専用のconvertスクリプトでGGUF化可能でOllamaで動かせます。またmlx-vlmの推論にも対応しており、処理系の選択肢が広いのがメリットです。　  参考：[Bee社さんのnanollavaに関するブログ](https://bee-u.com/column/column_20240710.html)
  ④ vikhyatk/moondream2: 基本英語の対応ですが、GGUF版も用意されておりOllamaでそのまま使えます。mlx-vlmには未対応。
  ⑤ その他: SmolVLM/SmolVLM2、phi-3.5-visionなど

## 3-4. デモ・検証用Web-GUI

 テキスト系LLMに関しては過去の[「全部盛り」](https://qiita.com/yosim/items/db392f2211cf3979b1d0)の記事で紹介したStreamlitを使用していましたが、少し処理が重たく画像表示も得意では無かったので、今回新たにgradioに乗り換えました。この領域は好みが分かれる所かと思いますが、画像系を軽めに処理したい方にはお勧めです。
 
 ## 4. ビジョン系モデルをローカルで扱う際のお勧めと注意点
 
 　最後にローカル系ビジョンモデル環境構築に関するお勧めと注意点です。
  
  ・テキスト系に比べてメモリとストレージをかなり消費するので、ColabやSageMaker等との併用がお勧めです。
  ・detasetのデータはParquetファイル等で圧縮し、HuggingFaceのdatasetsモジュールで読み込み、編集・加工、アップロードし、ローカルには極力保存しない方が良い。
  ・Llamaのような準標準的なモデルが無く、強いて言うとLlava系モデルが比較的多くなっているが、各モデルとも独自実装色が強いので、inferenceはまだしもFine Tuningになるとモデル毎の個別対応部分がかなりのウェイトを占めるようになる。
  ・テキスト系ではかなり便利なOllama等のプラットフォームもビジョン系で使えるモデルが現時点少なく、コードを自分で作成する必要が高くなるので、コード生成AIや先駆者の記事等を参考にした方が早い。
  ・DeepSpeed、flash_attention2、bitsandbytes、mixed_precision等の処理効率化や省メモリのツールが殆どMPS（Apple silicon）非対応で、mlx-lm/vlmも対象ビジョン系モデルが少ないので、多くのリソースを必要とするビジョン系モデルのファインチューニングはMacのMPSには向いて無いように思われます（間違っていたらご指摘下さい）。

  ＜追記＞
  Ollamaのビジョン系対応モデルが少ないと言いましたが、2025年5月15日のBlogでMeta Llama 4、Google Gemma 3、Qwen 2.5 VL、Mistral Small 3.1の追加対応が発表されました。Blogによるとビジョン系モデルはllama.cpp依存を脱却し、ビジョン系を最優先する新たなエンジンのサポートを開始したようで、今後のマルチモーダル系モデル対応の充実が期待できそうです（テキスト系はllama.cppを継続）。
　[参考：Ollamaのブログ](https://ollama.com/blog/multimodal-models)