前回の投稿(【ワイン画像識別2026】セグメンテーションの要件)で予告したように、今回は今までに生成したセグメンテーションモデルやエンベディングモデルを組み合わせて、ワインボトルの画像によりワインを照会する仕組みを試作してみました。
最新エンベディングモデルの精度
まず、最新のエンベディングモデルの精度に関して触れておきます。
前回の投稿時から、ハイパーパラメータを若干変更しています。
ただ、以下の結果はハイパーパラメータ変更の効果というよりは、AIあるあるの「学習の非決定性」による揺らぎの結果かと思っています(要は運よく「当たり」を引いたパターンと言うことです)。
全データ
| 閾値 | ポジティブ | ネガティブ | 適合率 | 再現率 | F1スコア | Fβスコア | |
| 前回 | 0.23 | 1119 | 0 | 1.0000 | 0.9991 | 0.9996 | 0.9998 |
| 今回 | 0.20 | 1120 | 0 | 1.0000 | 1.0000 | 1.0000 | 1.0000 |
テストデータ
| 閾値 | ポジティブ | ネガティブ | 適合率 | 再現率 | F1スコア | Fβスコア | |
| 前回 | 0.23 | 109 | 0 | 1.0000 | 0.9909 | 0.9954 | 0.9982 |
| 今回 | 0.20 | 110 | 0 | 1.0000 | 1.0000 | 1.0000 | 1.0000 |
ついに全ての指標において100%を達成しました!
まぁ、あくまで今回用意したデータ(112種・560画像)の範囲での話ですが。
ポジティブ・ネガティブの分布状況に関しても見てみましょう。
ポジティブ
| 平均値 | 中央値 | 最小値 | 最大値 | 標準偏差 | |
| 前回 | 0.0222 | 0.0161 | 0.0027 | 0.2643 | 0.0219 |
| 今回 | 0.0202 | 0.0144 | 0.0023 | 0.1957 | 0.0207 |
ネガティブ
| 平均値 | 中央値 | 最小値 | 最大値 | 標準偏差 | |
| 前回 | 1.0033 | 1.0067 | 0.2393 | 1.3203 | 0.0737 |
| 今回 | 1.0028 | 1.0063 | 0.2224 | 1.2671 | 0.0722 |
ポジティブの最大値が0.1957、ネガティブの最小値が0.2224であり、両者の分布に重なりがなくなりました。
なお、上記のように0.20〜0.22に空白地帯が存在するようになりましたので、一致判定の閾値をどのように選択するかと言う喜ばしい悩みが生じますが、以前からコメントしているようにFP(ネガティブをポジティブと勘違い)の方がFN(ポジティブをネガティブと勘違い)よりもダメージが大きいため、ネガティブ側にバッファを持たせるように閾値=0.20と厳しい数値を採用しています。
上記で最もハードなポジティブ・ネガティブとなったパターンも見てみましょう。
まずはポジティブから。
![]() | ![]() | 0.1957 |
ハードですかね?
人間の目で見る限り、普通に同じラベルだと認識すると思いますが。
ネガティブの方も見てみましょう。
![]() | ![]() | 0.2224 |
ハードですかね???
確かにラベル部分が刷毛でなぞったような模様で占められている点は共通していますが、でも右の方はど真ん中に大穴開いてますやん!
違いは一目瞭然だと思うのですが。
以前の投稿(【ワイン画像識別2026】SigLIP2)でSigLIP2ベースのモデルのことを「以前のモデルとは比較にならない精度と安定性(意味不明なハードサンプルがない)を持っている」と評したのですが、若干怪しくなってきました。
と言うのように、少々不穏な空気が漂ってはいますが、とりあえずは閾値=0.20で綺麗に線が引けるエンベディングモデルが生成できてはいるので、これを使用してワインの識別を行ってみることにします。
代表ベクトルと個別ベクトルの距離
前述のエンベディングモデルを前回紹介したセグメンテーションモデルと組み合わせ、指定した画像が既に登録(エンベディング)済みのワインのいずれかと一致するかどうかを照会する仕組みを作成しました。
なお、このような仕組みにおいて、事前に登録済みのデータを「Gallery」、それらと比較するために指定されるデータを「Query」と呼称するようなので、ここでもその表現を採用します。
また、エンベディングモデルの訓練時には個々の画像のエンベディング結果(ベクトル)相互を比較対象としていましたが、今回の仕組みにおいては同じワインの画像に関するベクトルから算術平均+正規化で代表ベクトルを決定し、Queryをこれら代表ベクトルと比較する方式を採用しています。
Galleryとしてはエンベディングモデルの訓練データ全て(112種・560画像)を登録してあります。
つまり、今回の仕組みではQueryが前述の112種類のワインのいずれかと一致するか不一致(該当なし)となるかの判定を行うことになり、その精度を確認することが今回の主目的となります。
と言うことで、実際にQueryとGalleryとの照合を行ってみたいと思いますが、まずは手っ取り早く上記訓練データ画像560枚をそのままQueryとして使用してみました。
QueryとGallery内の個別画像ベクトルとを比較する方法では、必ず同じベクトルが登録済であるため、全てのQueryに対して距離=0で照合できてしまい意味がないですが、今回の仕組みでは比較対象が代表ベクトルであるため、Galleryに含まれる画像をQueryとして使用しても一応の動作確認はできる訳です。
この操作は、各クラス(ワイン)を構成する個別の画像ベクトルと代表ベクトルの距離を確認する作業とも言えます。
で、結果ですが、560枚全てに関して、閾値=0.20以下の条件で、当該Queryが属するクラス(ワイン)を唯一(ネガティブの混同なし)の一致対象と認識できています。
個別ベクトル同士の比較において0.20未満のネガティブが存在していないので、当然と言えば当然ですが。
なお、1件当たりの照会時間は平均で0.7〜0.8秒程度であり、実用的にも問題なさそうです。
距離に関する集計結果は以下のようになりました。
| 平均値 | 中央値 | 最小値 | 最大値 | 標準偏差 |
| 0.0085 | 0.0060 | 0.0013 | 0.0816 | 0.0087 |
最大でも0.0816までの距離で照合できています。
分布も見てみましょう。
| 距離 | 該当 | 累積 | 再現率 |
| 0.00 – 0.01 | 428 | 428 | 76.43% |
| 0.01 – 0.02 | 97 | 525 | 93.57% |
| 0.02 – 0.03 | 18 | 543 | 96.96% |
| 0.03 – 0.04 | 6 | 549 | 98.04% |
| 0.04 – 0.05 | 4 | 553 | 98.75% |
| 0.05 – 0.06 | 5 | 558 | 99.64% |
| 0.06 – 0.07 | 1 | 559 | 99.82% |
| 0.07 – 0.08 | 0 | 559 | 99.82% |
| 0.08 – 0.09 | 1 | 560 | 100.00% |
かなり良い感じで代表ベクトル付近に個別ベクトルが凝縮されているようです。
Galleryにない画像の照会
代表ベクトルと個別ベクトルの距離感は分かりましたので、改めてGalleryに含まれない画像200件に関して照会を試みました。
使用する画像はセグメンテーションモデルの訓練時に使用していたもので、エンベディングモデルの訓練には全く関与していません。
ただし、セグメンテーション用画像、エンベディング用画像ともに撮影対象としたワインはランダムに選択しているため、ワイン自体は重複しているものもいくつかあります。
その結果、200件の内訳としては、ポジティブ(Galleryに含まれる)41件、ネガティブ(Galleryに含まれない)159件となっていました。
で、実際に照会を行った結果ですが、ポジティブに関しては問題になりそうなものはなく、最も遠いポジティブでも0.0588で、先に示した代表ベクトルと個別ベクトルの分布と比較しても十分に適正と言える範囲に収まっていました。
一方で、ネガティブに関しては怪しいものが4件発見されています。
以下に、Queryおよび最も近いと判断されたGallery側の画像と、両者(Gallery側の比較対象は代表ベクトル)の距離を示します。
| Query | Gallery | 距離 |
![]() | ![]() | 0.1200 |
![]() | ![]() | 0.1641 |
![]() | ![]() | 0.2153 |
![]() | ![]() | 0.2004 |
一番目は、絵柄は非常に似ていますが、ラベル右側に書かれた文字列が若干異なっています。
ただ、これは人間の目で見ても十分ハードな部類と考えて良いでしょう。
二番目は極めて不思議な組み合わせです。
人間の目で見れば違いは一目瞭然ですが、良く見れば、鶏のような絵が描かれていたり、「Bio」と言う文字列が3つ書かれていたり、「Merlot(MERLOT)」と言う文字列が書かれていたりと共通点を見つけることはできます。
もし上記根拠で両者を似ていると判断したのだとすれば、むしろ感心するレベルです。
三、四番目はラベルの形状、ボトルの形状と色、ラベルに書かれた文字列など似ている部分も多いですが、そのラベルに書かれた文字列でも部分的には違っていますし、ラベルの色も違っています。
やはり人間の目で見れば区別は容易と言えるでしょう。
なお、三番目と四番目の2つを比較した場合、四番目の方が色の違いが明確である点で区別しやすそうに思うのですが、距離としては四番目の方が若干近い(つまり区別しづらい)扱いになっています。
この辺も謎です。
先に示したように、Galleryに含まれる個別ベクトル同士の比較における最もハードな(つまり距離が小さい)ネガティブの組み合わせもかなり不思議なものでしたが、それでも距離は0.2224でした。
個別ベクトル同士の比較では極端なもの同士の比較になる場合もあるため、ネガティブの距離としては代表ベクトルとの比較の方が大きくなる(極端に小さいケースが減る)はずです。
しかし、前述した4つのケースは、いずれも距離が0.2224より小さくなっています。
特に最初の2ケースに関しては、個別ベクトル同士の比較におけるポジティブの最大距離0.1957と比較しても、より小さい値となっています。
つまり、個別ベクトル同士の比較から閾値とした0.20を基準とすると、最初の2ケースはFPとなり、後の2ケースも際どい距離にあると言えます。
「代表ベクトルと個別ベクトルの距離」で示した状況によれば、最小閾値=0.09で適合率・再現率100%が成立するので、この基準であれば前述の4ケースもネガティブとして問題なく排除できます。
多少再現率を犠牲にして、閾値=0.05(再現率99%弱)まで下げることで、FPが発生するリスクをさらに軽減させるように調整することも選択の余地ありです。
つまり、閾値を適正に選択すれば、少なくとも現在の手持ちのデータに関しては、現在のモデルでFPを発生させることなくラベル画像による照会を行うことはできそうです。
ただ、前述した際どいケースがどうにも納得できないんですよね…
特に二番目の距離0.1641はどう考えてもおかしいでしょう。
この点に目を瞑って、線の引き方で帳尻を合わせて良いものかどうかが非常に悩ましいところです。
まとめ
とりあえず、今までに生成したセグメンテーションモデルとエンベディングモデルを組み合わせて、ワイン照会システムを試作することはできました。
閾値を適正に設定することで、手持ちのデータでは十分な精度で照会を実現できます。
ただし、エンベディングの精度に関しては不安材料も残っています。
今後、未知のデータに対する弱さが露呈する可能性は否定できません。
この辺の弱さを克服するには、やはり112種560枚の学習データは貧弱なのかもしれません。
とは言うものの、直近に学習データを大幅に増やすことは厳しいですし、データが増えた分だけ学習に要する時間も長くなるため、試行錯誤が難しくなってしまいます。
よって、一旦は現状の(あるいはもう少し改善した)モデルで試運転を継続しつつ、問題となるデータが見つかった際にはそのデータを含めて現状のモデルに対して追加学習を行うような仕組みを考えるべきかもしれません。
その辺を次回のテーマにしたいと思います(あくまで予定ですが)。











