はじめに
背景
以前、YOLO(後述)を使った高速物体検出を作ってみたことがありました。その際、ラズベリーパイ上で動くリアルタイム処理にこだわっていましたが、PC上では動作したのですが、ラズパイ上では動かず頓挫しました。最近、chatGPT-4Oの画像認識能力がとても高く、ラズパイにこだわらなければ、もっと楽に簡単に何か作れるのでは?と思い、一度、棚上げしていたアプリを作ろうと思いました。データを揃えるのは大変なので、私の趣味である釣り記録から、釣れた魚を判別できるアプリを作ってみようと思いました。
GPT4-Omni (2024年7月時点)
生成AIの進化は早いので来年になったらしょぼくなる可能性があるので、時期を書いておきます。使ってみた結果が以下です。すでに完璧に近い。GPTをAPIで使ってしまえば良いのでは?と思いましたが、万能の神に勝つには、局地戦しかありません。釣った魚だけに最適化されたものを作ってみようと無駄に触発されました。
【プロンプト】
この画像の魚を判別し、数を書き出して。
YOLOについて
YOLOは「You Only Look Once」の略で、高速な画像認識アルゴリズムとして知られています。従来の手法と比べて処理速度が非常に速いことが特徴です。分かりやすい動画があったので貼っておきます。
https://www.youtube.com/watch?v=CDmFPnH4lvk&t=1s
何かをカウントするのにとても役に立つ技術だと思います。2,3年前はv4当たりだった気がしますが、既にv9とかで進化の定点観測だけでも面白い。
今回は、リアルタイム性よりも高速に判定するためにYOLOを使ってます。
学習
YOLOのモデルを作成します。一般的には画像から、対象物を四角形で囲って、それに対して識別名をつけていきます。これをアノテーションと呼びます。例えば、画面内に魚が10匹いると、その魚を囲って、識別名をそれぞれつける。この作業をひたすらやる修行のようなものです。とても時間がかかるので、ツールは妥協した無くないということで、最適解かは分かりませんが、前回(前回何を使ったか覚えてないですが)よりも格段に使い勝手がよいRoboflowというのものw使ってみました。
Roboflow
HPは以下です。
- Roboflowの使用: Roboflowというツールを使用しました。非常に使いやすく、効率的にアノテーション作業ができました。アノテーションもですが、yoloの学習モデルも作ってくれます。
- データセット: 過去の釣果画像約80枚を使用しました。
下記にデータセットがおいてあります。
https://app.roboflow.com/fish-tihhk/fish_detector-doua9/deploy
- 作業時間: 約2時間程度で完了しました。
無料プランでも十分使えるレベル(モデルは3つまで確保できて、1万回/月のAPIが無料)です。ただ、で無料で何かを試してみたい方には十分すぎるプランだと思います。ですが、注意点として、 Roboflowの無料プランではデータが公開されることと、商用にできない点があります。なので、今回は広告なしのアプリで個人の顔などが含まれる画像は予め除外しました。
機能 | フリープラン | スタータープラン |
---|---|---|
価格 | 無料 | $249/月 |
データセットとモデルの公開性 | コミュニティに公開 | アカウント所有者のみのプライベート |
トレーニングクレジット | 3クレジット | 開始時10クレジット、毎月5クレジット追加 |
自動ラベル付けクレジット | 1,000/月 | 10,000/月 |
推論クレジット | 10,000/月 | 25,000/月 |
学習データ
中身はよくわかりませんが、収束していることが分かります。
mAPはmean Average Precisionで平均正解度といったところでしょうか。0.5という値はまぁまぁらしいです。
検証データ
まぁ、魚の数がタイ、ハマチ、アコウ、ガッシー(カサゴ or ホゴ)、コチ以外は釣ってないので、偏ってますね。
アプリについて
APIの使い方
こんな感じで様々なプラットフォームで使えます。pythonなら、数行で確認できます。
Androidアプリについて
詳しくは書きません。LLMと友人の力を借りて、なんとか作成しました。
一つだけ、サンプルソースを参考にしながらだとうまく動作しなかった点があったので書いておきます。
- 「image=」のプレフィックスを使用しないことが重要。
- データはバイト配列として送信する。
// 修正前
val postData = "image=$encodedImage"
val wr = DataOutputStream(connection.outputStream)
wr.writeBytes(postData)
wr.close()
// 変更した部分
val outputStream = connection.outputStream
outputStream.write(encodedImage.toByteArray())
outputStream.flush()
outputStream.close()
アプリのリリース
こちらに作成したアプリがあります。
瀬戸内海のボートフィッシング限定のアプリです。
【機能紹介】
- カメラを使って撮影したものを判別
- フォルダ内の画像を判別
chatGPT vs 自作YOLOの識別対決
自作の方が学習したデータも含まれるのでかなり優位ではありますが。
- (自作)タイを2匹スルー、アコウを5匹スルー、1誤検出
- (chatGPT4o) マダイ (Red seabream): 6匹
ホウボウ (Sea robin): 7匹
ブリ (Yellowtail): 1匹
GPTはアコウとホウボウを間違えて、アコウの数は2匹スルー。自作YOLOは重なってるアコウをかなり見逃してますね。これはGPT勝利にします。
- (自作YOLO):ハマチを3匹スルー
- (chatGPT4o):ブリ (Yellowtail): 7匹
マダイ (Red seabream): 2匹
ホウボウ (Sea robin): 4匹
GPTはアコウとホウボウを間違えてるのと、1匹だけメバルだとわかっていないですが、
ハマチの数をきちんとキャッチできてるのが良いですね。自作は検出理が弱いですね。これもGPTの勝利。
- (自作yolo) ハマチを2匹スルー
- (chatgpt4o)
サワラ (Spanish mackerel): 1匹
ブリ (Yellowtail): 5匹
マダイ (Red seabream): 2匹
chatGPTはハマチ3匹をスルーなので、自作が勝利したということにしましょう。
というわけで、割と拮抗していますが、現時点ではハンデあるのにも関わらずGPTの勝利でした。
ですが、自作GPTは誤り検出が1件だけなので、調整できるパラメータの正確性とオーバーラップ許容度を変更すれば、勝てそうな気がしてます。(負け惜しみ)
まとめ
- LLMについては、chatGPT-4とClaude 3.5 sonnet とJemini 1.5 Pro を併用していますが、Cladueがダントツで良い回答をくれます。chatGPTはサブスクしてるのでメインで使ってますが、コード書くなら、Claudeがとても良いです。ハレーション(嘘)が一番少ないのと、余計ないことを言わないので気に入ってます。
- YOLOの精度は思った以上に出てるなと思いながらも、やはりまだまだの点があるなと思いました。
- ほぼAPIを使ったアプリなのに時間がかかってしまった。やはりアプリよりもクラウドの方がやりやすい気がする。今後は腰を据えて勉強したいところ。