VLMにBBoxをSFTすると、モデルは一体何を学習しているのか?
約7分で読めます

VLMにBBoxをSFTすると、モデルは一体何を学習しているのか?


最近、VLM(Vision Language Model)に画像を入力し、物体のBounding Boxを出力させる実験をしている。

例えば、画像内にある物体について、次のような形式で出力させる。

[
  {
    "name": "connector_A",
    "bbox": [120, 340, 80, 50]
  }
]

BBoxの形式は [x, y, width, height]。座標は画像サイズに依存しないよう、0〜1000の範囲に正規化している。

ここで、VLMをLoRAでSFT(Supervised Fine-Tuning)すればBBoxの精度を改善できるのではないか、と考えた。画像と正解BBoxのペアを大量に用意して学習させる。一見すると、普通の物体検出モデルと同じように「画像内の位置」を学習してくれそうだ。

しかし、ふと疑問が湧いた。VLMにBBoxをSFTすると、モデルは一体何を学習しているのだろうか?

SFTで学習しているのは「正解文字列」

VLMのSFTをかなり単純化すると、やっていることは言語モデルの学習と同じである。例えば正解データが [120, 340, 80, 50] だったとする。モデルは [120,340,80,50] というトークン列を順番に予測する。

つまり損失関数は基本的にCross Entropy Lossであり、「次の正解トークンをどれだけ高い確率で予測できたか」を評価している。

ここで重要なのは、BBoxの幾何学的なズレを直接評価しているわけではないという点だ。

例えばGTが [100, 100, 200, 200] だったとする。

  • 予測1: [101, 101, 200, 200]
  • 予測2: [800, 800, 50, 50]

人間から見ると、予測1はほぼ正解である。一方、予測2は完全に外れている。物体検出の観点では、この2つは明らかに異なる。

しかし通常のSFTでは、100 → 101 が「座標的に少しだけズレた」ということを直接理解して損失を計算しているわけではない。あくまで正解トークンと違うトークンを出力したという問題として扱われる。つまりSFTのLoss空間と、BBox評価の空間にはズレがある。

IoUを見て学習しているわけではない

物体検出では、BBoxの評価にIoU(Intersection over Union)がよく使われる。予測BBoxとGT BBoxがどれくらい重なっているかを評価する指標だ。IoU=0.9ならかなり正確、IoU=0.0なら全く重なっていない。

YOLOなどの物体検出モデルでは、BBoxの位置やサイズに関するLossが明示的に存在する。モデルは「BBoxをもう少し右に動かした方がいい」「幅をもう少し広げた方がいい」という方向の勾配を受け取ることができる。

一方、VLMの通常のSFTではそうではない。GTが [500, 300, 100, 50] なのに [510, 300, 100, 50] と出力した場合でも、モデルに与えられるのは基本的に「500に対応する正解トークンを出せなかった」という言語モデルとしての誤差である。「10だけ右にズレています」という情報を直接Lossとして受け取っているわけではない。

ここが非常に面白い。VLMにBBoxを出力させていると、見た目は物体検出をしている。しかし学習の仕組みを見ると、実際には「BBoxを表現した文字列」を生成する学習をしている。

では、画像と座標の対応は学習できないのか?

ここまで読むと、「じゃあSFTでBBoxを学習させても意味がないのでは?」と思うかもしれない。もちろん、そんなことはない。

VLMにはVision Encoderが存在し、画像特徴がLanguage Model側に入力される。そのため、

画像特徴

物体がこの辺にある

対応する座標トークンを生成

という対応関係を学習すること自体は可能である。実際、Grounding系のVLMでは座標をテキストとして出力するモデルも存在する。

つまりSFTでも、**「この画像特徴のときは、この座標列を出力する」**という対応関係は学習できる。

ただし問題は、その学習効率だ。数字を通常のテキストトークンとして扱う場合、499・500・501 という座標の近さと、100・900 という座標の遠さが、BBoxの幾何学的な距離としてLossに反映されるとは限らない。モデルにとって重要なのはトークン予測である。人間が考える「座標空間」と、モデルが学習する「トークン空間」は同じではない。

loc tokenという考え方

そこで使われるのが、位置専用トークンである。例えば座標を0〜1000に正規化し、<loc_0> <loc_1> <loc_2><loc_999> のようなトークンを用意する。

BBoxを [120, 340, 80, 50] ではなく、<loc_120><loc_340><loc_80><loc_50> として出力する。

こうすることで、座標値を通常の数字ではなく「位置を表す専用語彙」として扱える。少なくとも、"120" という数字がTokenizerの都合で "1"+"20""12"+"0" のように分割される問題を避けやすい。

ただし、loc tokenを使えば自動的に <loc_120><loc_121> は近いとモデルが理解するわけではない。Cross Entropy Loss上では、基本的に別のクラスである。位置トークンの設計によってBBox生成を扱いやすくすることはできるが、IoU Lossと同じになるわけではない

結局、SFTは何を学習しているのか?

自分なりの現在の理解はこうだ。

VLMのBBox SFTは、物体検出器を学習しているというより、「画像特徴から位置表現を生成する方法」を学習している。

画像のどこに物体が存在するかという情報はVision Encoderから得る。そしてLanguage Modelは、その視覚情報を <loc_120><loc_340><loc_80><loc_50> という位置表現に変換する。つまり、

画像

視覚特徴

位置情報の推定

座標トークン列

という変換を学習している。

ただし最終的な学習目標はToken Lossである。こちらが本当に改善したい指標が、IoU・Precision・Recall・F1なのであれば、SFTの目的関数と最終評価指標にはズレがある。

そして新しい疑問が生まれる

現在、自分のタスクではGT BBoxと推論BBoxからIoUを計算できる。さらにBBoxをマッチングし、見逃し・過検知・IoU・Precision・Recall・F1までコネクタ単位で評価できる。つまりモデルの出力が良いBBoxなのか悪いBBoxなのかは評価できる。

では、この評価値を直接学習に使えないのだろうか。例えば、

  • IoUが高い → 高Reward
  • 見逃し → Penalty
  • 過検知 → Penalty

というRewardを設計する。SFTで「BBoxの出力形式」を学習させた後、BBoxの品質そのものをRewardとして最適化する。

こうすると初めて、「座標文字列を正しく生成する」ではなく「GTに近いBBoxを生成する」という目的でVLMを学習できるのではないか。

SFTだけでBBoxを学習させようとしていたが、考えれば考えるほど、これはSFTの問題というよりReward設計の問題なのかもしれない。

そしてここまで考えて、また一つ思う。

そこまでしてVLMにBBoxを出させる必要、本当にある? YOLOでよくない?