【ワイン画像識別2026】今更ながらPyTorch

Date:

Share post:

2026年もこのネタ、ということで相変わらずラベル画像からワインの識別を行うべく悪戦苦闘中です。

前回の投稿(2025年はワイン画像識別と共に始まり、そして暮れゆく)でも少し触れましたが、昨今は過学習の軽減(できれば解消)が最大のテーマでした。
ハイパーパラメータの調整では十分な成果が得られず、以下のような改修を加えたところ、逆に精度が落ちてしまったというのが前回までの状況です。

  • オプティマイザをAdamからAdamWに変更
  • Projection Headの追加
  • 勾配クリッピングの導入
  • Batch NormalizationのFreeze

上記に関しては「Batch NormalizationのFreeze」が原因だったようで、この処理を除外したところ問題はある程度解消したのですが、言い換えれば目の覚めるような改善もなく、上記施策では過学習対策としては不十分であるとの結論に至りました。

加えて、もう一つ気になる点は、学習済モデルでのエンベディング結果において距離がかなり遠いと見做されるポジティブが存在することです。
0.5以上のものが数個から数十個レベルで存在し、極端なケースでは1.0前後のものもありました。
最もハードなネガティブが0.01〜0.03程度になる場合が多いことを考えると、ポジティブで0.5はかなりの遠さです。
記録が残っている18回の学習のうち、0.5を超えたポジティブが存在しなかったケースは2回のみで、それ以外は程度の差はあるものの、0.5以上のポジティブが存在していました。

学習データにおいては、あえて酷似したネガティブ(ハードネガティブ)が含まれるようにしていますので、極端に近いと見做されるネガティブが存在してしまうことは理解できます。
しかし、ポジティブに関しては、ある程度違って見えるように撮影条件を変えてはいるものの、所詮は同じラベルを撮影したものであり、人間の目で見れば普通に同じ(あるいは似ている)と認識できます。
それが0.5以上の距離となると、かなりの違和感があります。

この辺のことをAI先生方に相談したところ、話が思わぬ方向に転がってしまったというのが今回の内容です。
なお、昨今ではCursorの中の人としてOpus先生を指名し、実装や分析を伴わない質疑はGemini先生に答えてもらっています。
しかし、下記で言及する見解がどちらの先生から出たものか、今となっては明確ではないので、大雑把にAI先生の意見としてまとめました。
また、AI先生方の見解が必ずしも正しいとは限らない点は周知かと思いますので、その前提でお読みください。

EfficientNetV2Lって…

前述した問題も含めて精度向上策を相談していたところ、AI先生から「EfficientNetV2Lの能力の限界」説が出てきました。

EfficientNetV2Lは「CNN(Convolutional Neural Network)」という方式で画像を理解する画像認識モデルです。
加えて、今まで使用してきたEfficientNetV2LはImageNetという「約1400万枚の画像、1000種類のカテゴリが含まれる世界で最も有名なデータセット」で事前学習したものです。
この「ImageNet育ちのCNN」という背景に問題があるようです。

以下、AI先生の見解です。

  1. 「意味の不変性(Invariance)」が裏目に出ている
    ImageNetの学習目標は、「多少のノイズや個体差があっても、それが何であるか(犬か、車か)を当てる」ことであり、例えば「ゴールデンレトリバーの毛色が多少明るくても、耳の形が少し違っても、それは同じ『犬』である」と教え込まれる。
    この「些細な違いを無視して同一視する能力」が、ラベルに表記された葡萄の品種やビンテージのような細かな違いを「些細なノイズ」として無視する方向に働いてしまっている可能性がある。
  2. Poolingの問題
    CNNは、層が深くなるにつれて画像を圧縮し、情報を抽象化していく(Pooling)。
    抽象化の過程で、「どこに何があるか」という正確な位置情報や、非常に小さな文字(年号)のディテールが削ぎ落とされる。
    モデルにとっては「全体的に同じ色使いのラベル」というマクロな情報が支配的になり、数ピクセル単位の差である「年号」の情報が、上位層に到達する頃には消失してしまう。
  3. 「色」と「形」に対する頑健性の欠如
    ImageNetで学習したモデルは、実は「色(テクスチャ)」に過度に依存する傾向がある(Texture Bias)。
    照明が変わってラベルの色味が少し黄色っぽくなると、ImageNetベースのモデルはそれを「大きな変化」として捉えてしまう。
    ラベルがボトルに貼られて湾曲していると、CNNはその「形状の歪み」を正しく補正できず、別のテクスチャとして認識しがち。

上記の真偽は定かではありませんが、現状手詰まりである点は変わらないので、結論としては「EfficientNetV2Lに変わるモデルを探す」方向で話がまとまりました。

ResNet50から切り替えた時には大幅な性能向上に喜んだものですが、短い付き合いだったようです。
さらば、EfficientNetV2L。

TensorFlowって…

次のモデル候補となったのはConvNeXtなるモデルでした。
ConvNeXtの特徴は「細粒度認識(Fine-Grained Recognition)に優れた設計」とのことで、「Vision Transformer(ViT)の設計原理をCNNに取り入れ、局所的なパターン認識と大域的な文脈理解のバランスが良好」だそうです。
期待が高まります!

で、実際に実装してみたところエラー発生。

原因は以下とのこと。

ConvNeXtは7×7のdepthwise convolutionを使用。
Apple Silicon (Metal) の TensorFlow 実装ではこの操作がサポートされていない。
これはプラットフォーム互換性の問題。

技術的な部分は十分理解できていませんが、どうもMac(Apple Silicon)上でのTensorFlowの動作には色々と制約があるようです。
気を取り直して他のモデルに関する調査を始めたところ、そこでも「Macで動作するか事前に確認が必要」というような話が出てきます。
その辺の話を詰めていたところ、AI先生から「Keras3のマルチバックエンド機能を活かし、PyTorchをバックエンドとして使用したら?」との大胆な意見が出てきました。
つまり、TensorFlowとの決別です。

以下、Mac(Apple Silicon)とPyTorchの関係に関するAI先生の見解です。

Mac(M4チップ)での開発において、現状ではPyTorchの方がTensorFlowよりも「相性が良く、開発体験がスムーズ」であるという評価が一般的です。

以前はMacでのディープラーニングといえばTensorFlow一択の時期もありましたが、現在はAppleとコミュニティの注力により、PyTorchの最適化(MPSバックエンド)が非常に成熟しています。

MPS(Metal Performance Shaders)の成熟
PyTorchはAppleのエンジニアと密接に連携しており、GPUを叩くためのMPSバックエンドの完成度が非常に高いです。以前は「特定の計算がGPUで動かずCPUにフォールバックして遅くなる」という現象が多発していましたが、現在はViTのような複雑なTransformerモデルもほぼ全ての工程がGPU(Metal)上で完結します。

Keras3との親和性
最新のKeras3はPyTorchをバックエンドとして選べるようになりました。これにより、「Kerasの書きやすさ」を維持したまま、「PyTorchの安定したMac用実行エンジン」を利用できるという、Macユーザーにとって最強の組み合わせが可能になっています。

加えて、

どうしてもGoogle系のライブラリや古い既存コードを動かす必要がある場合はTensorFlowを選択しますが、環境構築でのエラー(依存関係の競合)を覚悟する必要があります。

とまで言い出す始末。
いや、今まで1年間TensorFlowを使ってきたんですが…

そもそも、TensorFlowを選択した理由は、当時の投稿(画像データのエンベディング)にあるようにGemini先生の鶴の一声だったので、個人的な思い入れがある訳でもなく、PyTorchに切り替えることに異存はありません(どうせ作業自体はCursor先生にお任せですし)。
さらば、TensorFlow。

Kerasって…

前述したように、当初推奨されのはKeras3のバックエンドとしてPyTorchを使用する方法でした。
今更ですが、KerasとTensorFlow, PyTorchの関係が今ひとつ理解できていなかったので、改めて整理しておきます(当然ながら解説はAI先生)。

Keras3とTensorFlow, PyTorchの関係は、車の「ハンドル・ダッシュボード(操作画面)」と「エンジン」の関係に例えると非常に分かりやすくなります。

Keras3は「マルチバックエンド・フレームワーク」と呼ばれます。それ単体で計算を行うのではなく、背後にある強力な計算エンジンを動かすための 共通インターフェース(窓口) です。

TensorFlow, PyTorchは、実際にGPU(MPS)やTPUを使って数学的な計算(行列演算)をバリバリこなす実行部隊です。

かつてのKeras(v2まで)はTensorFlow専用の「おまけ」のような存在でした。しかし、Keras3からは TensorFlow, PyTorchのどれでも好きなエンジンに差し替えられる「独立した強力なツール」へと進化しました。

上記を見る限り、もし再びTensorFlowに戻りたい事情が生じた場合も柔軟に対応できそうです。
これは期待ができます!

と思って調査を進めていくと、再び暗雲が。
Keras3経由でPyTorchを使う場合のデメリットとして以下のような話が出てきました。

  1. モデルの選択肢がtimm(PyTorch Image Models)に比べれば少ない。
  2. PyTorch特有の非常に細かい制御(特定のテンソル操作など)をしたい時に、Kerasの層を挟んでいることが逆に障壁になることがあり得る。
  3. PyTorchを直接使用した方が、Apple Silicon(MPS)上での動作トラブルが少なく、コミュニティの解決策も豊富。

本投稿における一連の流れの最終目的はラベル画像の識別に適したモデルの選定であり、そこでの選択肢は多い方が良いです。
後々、有望なモデルが使用できないと泣きを見る羽目になることを考えると、ここは断腸の思いでKeras3を切っておいた方が良さそうです(AI先生も賛同)。
さらば、Keras。

今更ながらPyTorch

ということで、今更ながらPyTorchを使うように、既存処理全般を書き換えることになった訳です。

自力でこの作業を行う場合、どれ程大変でしょう?
まずはPyTorch自体の学習が必要になりますし、その上でTensorFlow/Kerasで書かれた既存処理をPyTorchに翻訳していく作業が発生します。
AI先生のざっくりした見積もりでは、(あくまで人間が作業する前提で)8〜12日程度要するのではないかとのことでした。

まぁ、当然ながら自力では作業しないんですけどね。

Cursor先生にお願いしたところ、数分で書き換えてくれました。
若干不具合もありましたし、TensorFlow/Keras時代から挙動が変わってしまっているような箇所もありますが、細かな点は追々調整するとして、概ね動作する状態になるのに要した時間は半日程度でしょうか。
AI万歳。

まとめ

思わぬ大鉈を振るうことになりましたが、なんとかPyTorch化ができました。
後出しになりますが、今までの学習においてPythonが異常終了していたケースが時々ありまして、この辺が前述したMacとTensorFlowの相性問題に関連しているのだとすれば、PyTorch化での改善が期待できるかもしれません。

肝心のモデル選択ですが、PyTorch化で選択肢が増えた結果、現状はDINOv2なるモデルが良いのではないかということで話が進んでいます。
ConvNeXtが「Vision Transformer(ViT)の設計原理を取り入れたCNN」であったのに対し、DINOv2は純粋にViT構造を採用したモデルとのこと。
CNNとViTの優位性に関しては色々と議論があるようですが、要はラベル画像からワインを適切に識別してくれる方式であることが重要です。
黒い猫でも白い猫でも鼠を捕るのが良い猫、ってところですかね。
この辺に関しては次回の投稿で報告できるかと。

Related articles

Packerを使用してVagrant Boxを作成...

久しぶりの投稿になってしまいました・・...

マルチポイント対応のイヤホンが便利すぎる

スマートフォンで音楽を聴きながら仕事...