OSSのアノテーションツールLabel Studioにコントリビュートした話

はじめに

こんにちは。データ部ML Product Devチームに所属している谷澤です。 ML Product Devチームは「機械学習を活用した競合優位性のあるプロダクト開発」をミッションとし、プロダクト開発チームと協力して日々開発を行っています。

現在参加しているプロジェクトではOCR技術を使用しており、アノテーションにはOSSのLabel Studioを利用しています。中でも機械学習モデルの推論結果を用いてアノテーションを支援する機能が非常に便利で重宝していましたが、特定の画像群で支援機能が働かないという不具合が発生しました。この不具合によってアノテーションの効率が落ちていたため、原因の調査と修正を行うことにしました。 今回のブログでは、どのようにしてこの不具合を修正し、Label Studioのリポジトリにコントリビュートしたかを共有します。

Label Studioのアノテーション支援機能

アノテーション支援機能のイメージ
Label Studioでアノテーションを行う際は、画像内に書かれている文字やその種類などのテキストメタデータを手動で入力する必要があります。このときアノテーション支援機能を使用すると、領域選択時に機械学習モデルが自動で推論を実行し、テキスト推論結果が自動的に入力されます。これによりアノテーション作業の負担を軽減できます。

不具合の発見

不具合に気づいたのは大量の文書の写真にアノテーションをしている最中のことでした。 大半の画像では支援機能が正常に動作するのですが、20〜30%ほどの画像では正常に動作しないのです。 不具合には再現性があり、問題がある画像では常に支援処理が失敗し、逆に問題がない画像では常に支援処理が成功していました。

原因の調査

まずは処理の流れを調査しました。 Label Studioのフロントエンド、バックエンドのソースコードを確認したところ、アノテーション支援機能は下記のような流れで処理が行われていました。

アノテーション支援機能の処理フロー
デバッグログの追加や処理途中の画像の保存などを行い精査したところ、支援処理が失敗する状況では「4.画像を送信」の処理でバックエンドが図の左側のような画像を受け取っていることがわかりました。
支援処理失敗時と成功時のクロップ結果の違い

BBOXは正常な状態でしたが、画像に意図しない回転が適用されてしまったことにより、画像をBBOXでクロップした結果が本来の意図とは異なる結果となっていました。

どうやら画像の回転に関して問題が発生していそうなことがわかりました。 調べてみると、画像の回転はJPEG画像の場合はExifメタデータで管理されているようです。

EXIF Orientation primer | Ameto

Exchangeable image file format - Wikipedia

早速手元の画像ファイルのExifメタデータを調査したところ、処理が失敗した画像には回転情報が付与されていること、処理が成功した画像には回転情報が付与されていないことを突き止めました。

不具合の修正

Exifメタデータで回転情報が付与されている画像について、フロントエンド側では正常に扱われるが、バックエンド側ではそうではないという不具合であることがわかりました。バックエンド側を修正する必要がありそうです。 ソースコードを追ったところ、バックエンド側はPillowライブラリを使って画像を読み込んでいるようでした。

PillowにはExifメタデータに応じて自動で画像を回転する ImageOps.exif_transpose() という処理があり、それを適用することで不具合が解消できることを確認しました。

Automatically rotates image based on EXIF, unexpected behaviour · Issue #5047 · python-pillow/Pillow · GitHub

ImageOps Module - Pillow (PIL Fork) 10.4.0 documentation

プルリクエストの作成

不具合が解消できた後、プルリクエストの作成に移りました。この作業において、特に以下の点を重視しました。

プロジェクトのルールに従うこと

手始めにプロジェクトのコントリビュートガイドラインを詳細に確認しました。Label Studioプロジェクトでは、機能追加や不具合修正を行う際にテストを作成することが推奨されており、私もそれに従うことにしました。

バグ修正時の手順を説明しているCONTRIBUTING.mdの項目

不具合の内容を理解してもらうこと

過去のissueを調べたところ、類似の問題についてissueが起票されていました。 そのためこの種の問題について既に開発者は知見を持っていると推測し、issueに細々とした検証結果を書くことは避け、「この過去のissueと類似の問題である」と説明する形に留めました。

github.com

修正の正しさを示すこと

修正が正しく動作することを示すためにテストを追加し、古いコードでは問題のある画像でも、新しいコードでは意図通りに処理されることを確認しました。

コードのメンテナンス性を保つこと

このプロジェクトを保守するのは私ではなく開発者の方々です。彼らがコードをメンテナンスしやすい状態を保つために、プロジェクトのコーディングスタイルやテストコードの書き方に従ってコードを修正しました。具体的には、既存のテストコードやコメントを参考にし、プロジェクトの標準に合わせたスタイルでテストを作成しました。

技術的負債を増やさないこと

テストを作成する中で、テスト用画像の扱いについてTODOコメントを見つけました。この箇所まで踏襲してしまうとTODOコメントを増やすことになりそうです。

テスト用画像の扱いに関するTODOコメント
可能であれば改善したスタイルでテストを書きたいと考え、どんなコードが望ましいか開発者に助言を求めました。数日後彼らから適切な方針が示されたため、それに従ったテストコードを作成しました。
開発者からの回答
また、今回の不具合と同じ不具合が他の箇所にも存在していることにも気づいたため、同時に修正を行いました。

最終的に、これらの項目を重視して作成されたプルリクエストは無事に受け入れられ、開発者から感謝のコメントを頂くことができました。

github.com

学んだこと

今回の不具合修正とプルリクエストの作成を通じて、プロジェクトのガイドラインを理解することの重要性を学びました。作業に入る前にCONTRIBUTING.mdやテストコードを確認したおかげで、プロジェクトの流れに沿った修正ができました。また、途中で疑問が生じた際に開発者に助言を求めたことで、技術的負債を増やすことなく修正を適用できたことも大きな学びとなりました。

OSSに貢献することで他の開発者やユーザーの役に立てたことを嬉しく思います。

アンドパッドでは一緒に働く仲間を大募集しています。

アンドパッドでは、「幸せを築く人を、幸せに。」というミッションの実現のため、一緒に働く仲間を大募集しています。 アンドパッドにおけるデータ活用の可能性は無限大で、AI・MLOps・データサイエンス・データアナリティクス・データエンジニアリング、どの切り口においても取り組むべき事柄がたくさんあります。様々な技術的課題にチームで挑戦する中で成長を遂げることができます。まずはカジュアル面談からでもご応募いただければより詳しい情報をお伝えできますので、是非ご応募いただければと思います。

機械学習エンジニア | 株式会社アンドパッド

hrmos.co

機械学習エンジニア(自然言語処理) | 株式会社アンドパッド

hrmos.co