Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AIを活用した柔軟かつ効率的な社内リソース検索への取り組み

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for Cygames Cygames PRO
September 09, 2024

 AIを活用した柔軟かつ効率的な社内リソース検索への取り組み

Avatar for Cygames

Cygames PRO

September 09, 2024
Tweet

More Decks by Cygames

Other Decks in Technology

Transcript

  1. 7/63 リソース管理ツールにAI検索を実装 ◼ テキストで画像を検索 ◼ 画像で画像を検索 ◼ 色で画像を検索 AIを使えば テキストで直接画像検索できる

    ◼ 画像のアップロード時に検索用情報を登録 ◼ 検索時には登録された情報を使って検索 登録と検索
  2. 13/63 AI画像検索の原理(その4) 1. あらかじめ「検索対象の全画像」をベクトルに変換 2. 検索テキストをベクトルに変換 3. 2のベクトルに近い順に画像のベクトルをソート テキストで画像を検索 1.

    あらかじめ「検索対象の全画像」をベクトルに変換 2. 検索画像をベクトルに変換 3. 2のベクトルに近い順に画像のベクトルをソート 画像で画像を検索
  3. 23/63 実装 : デプロイ環境、ベクトル検索エンジン ◼ サーバレスで扱いやすい ◼ コストが低い ◼ リソース管理ツールとは別に実装(後で役に立った)

    ◼ Lambdaの詳しい話は次のデプロイのところで AWSのLambda上にデプロイ ◼ ベクトル間の距離を高速に求める ◼ Meta社のfaissを利用 https://github.com/facebookresearch/faiss ◼ 今回は検索件数が数万の単位なので必須ではない ベクトル検索エンジンを利用
  4. 24/63 実装 : ベクトル検索エンジン faiss ◼ C++実装なので高速 ◼ 多様な検索方法、GPUサポート(今回はCPU版を利用) 特徴

    ◼ コサイン類似度:2つのベクトルのなす角のコサイン値(同じベクトルの場合1) ◼ faiss.IndexFlatIPがコサイン類似度で検索 ◼ 削除時:検索インデックスを再作成(削除機能がないため) 今回はコサイン類似度が近いものを検索 ◼ 検索前:ベクトルを追加して「検索インデックス」を構築 ◼ 検索時:「検索したいベクトル」と「検索インデックス」から検索 ◼ 検索結果は距離が近い順のインデックス値 [2,3,1,…] 検索インデックスを構築 > 検索
  5. 25/63 実装 : faissはベクトルしか格納できない ◼ 同じ順番でfaissのインデックスを作成 ◼ faissの検索結果を使って、リソースIDを取得 ◼ 「ベクトル間の距離が近い順」の「リソースIDのリスト」を返す

    ◼ Pythonのpickle形式で保存 (リソースID:ベクトル)の配列を別に持つ 検索結果 リソースリスト リソースID1, 画像のベクトル1 リソースID2, 画像のベクトル2 リソースID3, 画像のベクトル3 faissの検索インデックス 画像のベクトル1 画像のベクトル2 画像のベクトル3 検索
  6. 26/63 実装 : APIごとの処理 ◼ 画像の登録時 > 検索インデックスの登録処理 ◼ 画像の検索時

    > 検索してソートされたリソースIDのリストを返す リソース管理ツールからAPIを呼び出す
  7. 27/63 実装 : 登録時の処理 1. 登録する画像をCLIPでベクトルに変換 2. リソースリストを読み込む 3. リソース名とベクトルのペアをリソースリストに追加

    4. リソースリストを使ってfaissのインデックスを再作成 インデックスの追加 faissの検索 インデックス インデックス 再作成 • ベクトル • リソースID リストに 追加 リソースリスト 画像 CLIPで ベクトル変換
  8. 28/63 実装 : 検索時の処理 1. テキストor画像をCLIPでベクトルに変換 2. faissのsearch関数で検索 3. コサイン距離が近い順に配列のインデックスのリストが返る

    4. リソースリストからリソースIDのリストを取得して返す faissの検索+リソースIDのリストを返す faissの検索 インデックス リンゴ テキスト ベクトル Search関数で 近いベクトルを検索 リソースIDの リストを取得 CLIPで ベクトル変換 リソースリスト
  9. 30/63 デプロイ上の問題点と解決策 ◼ 合計15万枚を登録 ◼ 1回のAPI呼び出しで20枚登録 ◼ 1分間に1回実行 ◼ 5日以上

    アップロード済みの画像を登録 ◼ 同時アクセスで検索インデックスが壊れる ◼ AIのモデルがインフラの帯域制限に引っかかってしまう ◼ 制限時間内に処理が終わらない 実行すると問題が多数発生
  10. 38/63 検索インデックスが同時アクセスで壊れる ◼ Faissの検索インデックスのファイルをEFSに保存 ◼ 登録時、検索時にロード&セーブ ◼ 同時アクセスするとファイルが破損! 当初の実装 ◼

    ネットワークファイルシステムなのでアクセス制御してくると思っていた EFSは同時アクセスの制御はしてくれない ◼ fcntl.LOCK_EXで排他ロック ◼ ロックファイルはサービスごとに作成(EFSに作成) ◼ サービス単位での同時アクセス数が少ないので問題なかった シンプルにファイルロックで回避
  11. 42/63 faissのファイルも帯域制限に引っかかる ◼ faissの検索インデックスをEFSに保存 ◼ 画像登録・検索ごとにEFSからロード 当初の実装 ◼ faissの検索インデックスは数十MB ◼

    数千回EFSから読み込むと制限がかかって遅くなる こちらも最初は問題なく動くが……! ◼ 関数呼び出しごとにS3から/tmpへ検索インデックスをコピー ◼ 更新後はS3へ戻す ◼ 最終的にEFSはロックファイル置き場としてのみ利用 同じ方法で解決
  12. 43/63 画像の登録処理が制限時間内に終わらない ◼ 画像の登録処理は20件まとめて行う ◼ Lambda内部では1件の登録処理を20回呼ぶ実装 ◼ モデルを20回S3から転送するので遅い! ◼ API

    Gatewayの制限のため30秒以内に終わらせたい 当初の実装 1. S3からモデルをコピー 2. 20件まとめて画像をベクトルに変換 3. faissにベクトルを登録 4. faissの検索インデックスをS3へコピー まとめて処理する実装に変更
  13. 44/63 開発期間 ◼ Japanese CLIPとfaissを使った実装 1週間 ◼ Lambdaでの初期実装 2週間 ◼

    リソース管理ツールへの組み込み 1ヶ月(別の担当者) ◼ デプロイ時のトラブル対応 1ヶ月 初期実装からリソース管理ツールへの組込みまで ◼ 基本構成は過去のAI機能と同じ ◼ AWSのインフラ構成も同じ ◼ AWS CDKのコードを流用 過去のAI機能の実装を使い回す
  14. 48/63 別のアプリケーションでも使いたい ◼ シナリオライターがゲーム中の背景画像を指定 ◼ 数百枚以上ある背景画像を検索したい ◼ タグやファイル名を知らないと探せない ◼ 埋もれている背景がある

    社内のシナリオ執筆ツールに導入してほしい ◼ リソース管理ツールとは独立している ◼ 別のサービスからでもAPIを呼び出せる 独立した実装になっているので導入が簡単
  15. 50/63 検索システムの改善 ◼ 「赤いリボンを付けたキャラクターA」で検索できるとさらに便利 ◼ Japanese CLIPのファインチューニングが必要 ◼ ファインチューニングの実装コードがない キャラクター名でも検索したい

    ◼ とあるカンファレンスで開発者の講演があった ◼ 講演後に話をして教えてもらった ◼ OpenAIのCLIPと同じ方法でファインチューニング可能 開発者に直接質問できた
  16. 51/63 ファインチューニングを行ってみた(その1) ◼ リソース管理ツールにはキャラクター名がタグで付いている ◼ 画像とキャラクター名の対応は取れるのでこれを学習 ◼ キャラクター名は学習できるが、学習済みの情報が失われてしまう キャラクター名を学習 ◼

    ファインチューニングで学習した知識は増えるが、他の知識を忘れる現象 ◼ 両者のバランスを維持するファインチューニング手法 ◼ PAINT ◼ Patching open-vocabulary models by interpolating weights ◼ 参考文献:深層学習による画像認識の基礎 オーム社 菅沼 雅徳 破滅的忘却
  17. 52/63 ファインチューニングを行ってみた(その2) ◼ LLaVA1.5は画像に対してテキストで問い合わせを行えるモデル ◼ キャラクターの名前+画像の説明テキストを学習 ◼ 「(キャラクター名)の画像です。ギターを持った女性がいます」 ◼ 出力は英語なので日本語に翻訳して適用

    ◼ 学習してみたが精度が上がっていかなかった ◼ 生成テキストが学習に向いていなかった可能性 LLaVA1.5モデルで画像からテキストを生成 画像 テキスト 「画像を説明して」 プロンプト LLaVAモデル 「ギターを持った 女性がいます」
  18. 55/63 音声版のCLIP : CLAP ◼ 画像以外を扱うCLIPモデルが多数公開済み ◼ 今回はLAION-AI/CLAPモデルを利用 音声版のCLIPを使えば可能! ◼

    CLAP : Contrastive Language-Audio Pretraining ◼ 楽曲、効果音を扱えるCLIP(英語のみ) ◼ 商用利用可能なライセンス ◼ 精度が高い ◼ 先頭の10秒のみ利用(10秒以下の場合はリピート) ◼ 楽曲用の事前学習モデルを利用 LAION-AI/CLAP
  19. 56/63 楽曲の自動タグ付け ◼ CLAPをクラス分類に適用 ◼ ジャンル : クラシック、カントリー、ジャズ、…… ◼ テンポ:速い、普通、ゆっくり

    ◼ ムード:クール、楽しい、ロマンティック、悲しい、…… ジャンル、テンポ、ムードを自動タグ付け ◼ ジャンル分類の場合 ◼ 例:this audio is {ジャンル名} sound ◼ ジャンル名 : 'classical', 'country', 'jazz’ , … ◼ 「テキスト」と「楽曲」の距離が近いものへ分類 テキストのテンプレートを利用してクラス分類 ◼ 途中でテンポやムードが変わる曲は扱えない 実際の運用に使える精度
  20. 58/63 Lambdaでの実装 ◼ モデルファイルがrinna社のCLIPより大きい ◼ 初期化に時間がかかる 同様にAWS Lambdaで実装 ◼ LAION-AI/CLAPはモデルのファイルサイズが2.2GB

    ◼ これをS3から毎回転送するのは時間がかかる ◼ モデルを16bitに変換すると383MB(精度変わらず) モデルファイルが大きい ◼ 特定のクラスのインスタンス化に数秒かかる ◼ インスタンスをPythonのpickle形式で保存 ◼ 毎回S3から転送して読み込むことで高速化 初期化に時間がかかる
  21. 62/63 まとめ : AIを使ったリソース検索を開発 ◼ 「いままで発掘できなかった画像が見つかった」など ◼ タグは使わずに、テキストで直接検索 ◼ 担当者ごとの感覚の違いに影響されない

    AI画像検索は評判がよかった ◼ 同様の仕組みで楽曲・効果音も検索できる ◼ 工夫すればクラス分類も実装可能 楽曲・効果音の検索にも利用可能 ◼ 原理は極めてシンプル ◼ サーバレスでの実装には工夫が必要 ◼ 独立したシステムにすると他でも使える サーバレスでの実装は少し大変
  22. 参考文献 ◼ MERT: Acoustic Music Understanding Model with Large- Scale

    Self-supervised Training ◼ https://github.com/yizhilll/MERT MERT ◼ Patching open-vocabulary models by interpolating weights ◼ https://arxiv.org/abs/2208.05592 PAINT
  23. クラス分類の精度を向上できないか? ◼ テキストor楽曲による検索がメイン ◼ 開発者がクラス分類は得意でないとコメント LAION-AI/CLAPはクラス分類は得意ではない ◼ タスクごとのモデルの精度を見れるサイト ◼ Music

    Auto-Tagging ◼ Music Genre Recognition ◼ Music Question Answering ◼ Music Classification Papers with Codeで探す ◼ 楽曲生成はかなり盛り上がっているのに…… 楽曲分類は人気がない