ぽっぺんしゃんにょろりんこ

匿名・非追跡型アダルト動画検索エンジンの設計ノート

イメージ画像から検索用タグを自動生成するというお話:①BLIP編

こんにちは、にょろりんこの技術備忘録ブログです。

今回は『イメージ画像から画像検索用のタグを自動生成する』というお話のうち、最初のステップである、『BLIPで画像から自然文のキャプションを生成する』編です。

このシリーズのお話は、Sae-Porns の裏側でひそかに動いていた「画像→タグ変換処理」の話です。

“動いていた”と過去形にしたのには理由がありまして……この処理、動くには動くのですが、画像を解析する必要があるため帯域消費が重く、せっかく作ったものの、実運用では一旦見送りになったという経緯があります。

軽さと精度はある程度トレードオフ

このへんを手探りで探っていくのも、個人開発ならではの醍醐味ですね。

ティアラ_人差し指を立てる


話を戻します。

たとえば、ある動画のサムネイル画像を見たときに「金髪の少女」「ベッドルーム」「逆光の夕日」みたいなイメージが浮かぶとしますよね。

この「人間が感じるイメージ」を、AIにやらせるにはどうしたらいいのか?

その答えが、今回紹介する「BLIP × MythoMax × Sudachi」を組み合わせた多段変換のしくみです。

続きでは以下のような章構成で進められます:

  • AIが画像から文章をつくる(BLIP)←今回はこれ。
  • 英語キャプションを日本語に翻訳(MythoMax)
  • 形態素解析で語句を抽出(SudachiPy)
  • フィルタ&整形して、検索タグとして格納

「画像からタグを自動生成する」っていうと簡単そうに聞こえるかもしれませんが、実際には細かい正規化や意味フィルタリングをかなり丁寧にやっています。

Sae-Pornsの画像タグ生成パイプラインの最初のステップでは、「BLIP(Bootstrapped Language Image Pretraining)」というAIモデルを使って、画像から自然なキャプションを生成しています。

以下のコードでは、サムネイル画像を BLIP に渡して、画像の説明文を生成しています。

そうすることで、『日光の差し込む部屋でほほ笑む金髪の女の子の画像』から『a blonde girl smiling in a sunlit room 』のような英語の説明文が自動で返ってきます。

ここが、検索可能なキーワードをつくる第一歩です。

■caption_to_tags.py

def generate_caption(image):
    processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
    model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base")
    inputs = processor(images=image, return_tensors="pt")
    output = model.generate(**inputs, max_new_tokens=50)
    return processor.decode(output[0], skip_special_tokens=True)

■main.js

function runPythonAndGetWords(imageUrl) {
 return new Promise((resolve, reject) => {
  const proc = spawn('./llm-env/bin/python3', ['caption_to_tags.py', imageUrl]);

  let output = '';
  proc.stdout.on('data', data => { output += data.toString(); });
  proc.stderr.on('data', data => console.error(`Python stderr: ${data}`));

  proc.on('close', code => {
   if (code !== 0) {
    return reject(new Error(`Python script exited with code ${code}`));
   }
   try {
    const result = JSON.parse(output.trim());
    resolve(result.words || []);
   } catch (e) {
    reject(new Error(`JSON parse error: ${e.message} / Raw: ${output.trim()}`));
   }
  });
 });
}

※半角の『(』を2個連続で書くと脚注になってしまうはてなの仕様?のため『(』は全角にしてあります。使用する場合は半角に戻してお使いください。

補足:使用モデルのバージョン

BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base")

使用モデル:Salesforce/blip-image-captioning-base

※Hugging Face 上で広く使われている軽量で高精度なモデルです。

まとめ

「画像→英語キャプション」の生成を担うのは generate_caption() 関数。

その中で BLIP の processor と model を使い、最大50トークンの自然文を出力。

これが「画像から意味のある文章を生成するAI処理」の最初の処理にあたります。

ちなみに、「なんで最初から日本語でキャプション作らないの?」と思った方もいるかもしれません。

これは、日本語でキャプション生成できるモデルがまだ少ないという事情と、英語の方が訓練データが圧倒的に豊富で精度が高いという技術的な背景があります。

BLIP などのモデルは、英語でトレーニングされているため、「画像 → 英語で自然な説明文」を作るのはとても得意なんです。

たとえば、「a woman sitting on a couch and smiling」みたいな、まるで人が書いたようなキャプションが、かなり高精度で出てきます。

これを無理に日本語で出そうとすると、モデルがそもそも対応していなかったり、意味が破綻したり、単語が極端に少なかったりしてしまうことが多い。

だからこそ、まずは英語で高品質なキャプションを生成してから、それを MythoMax で丁寧に日本語に翻訳するという2段階にしています。

このワンクッションが、タグの精度をグッと上げるための小さな工夫なのです。

というわけで、今回は、「BLIPで画像から自然文のキャプションを生成する」処理までをご紹介しました。

このあと、生成された英語キャプションは MythoMax を使って日本語に変換され、  さらに Sudachi によって意味のある検索タグへと落とし込まれていきます。

そのあたりは、次回「MythoMax翻訳編」で詳しく解説します。

それでは皆さま、よき開発ライフを。

※このコードが実際に使われている「追跡されないアダルト動画の検索エンジンSae-Porns」はこちら!よかったら見ていってください。(18歳未満の方はご利用できません。)

sae-porns.org