はじめに
「この画像、まとめて整理できたらなぁ…」
イラストや写真をフォルダに詰め込んでいくと、検索不能なカオス地獄になりますよね。そんなときに出会ったのが SmilingWolf さんのWD EVA02-Large Tagger v3。
聞くところによると「画像を食わせると、勝手にタグを山盛り付けてくれる」らしい。これは試さない手はない!
モデルって何者?
・Hugging Face 公開の 自動タグ付けAI
・出力カテゴリは3つ:
・rating → safe / questionable / explicit
・character → キャラ名
・general → 髪色・服・背景など
・学習元はおなじみDanbooru データセット
要するに、「人間がつけるタグをほぼ自動でやってくれるスゴいやつ」です。
使ってみた
Hugging Face からモデルを取ってきて、画像をアップロード。
(フォルダに16枚放り込みました📂)














前処理して → ONNX で推論 → CSV に保存。この流れを作ってスイッチオン!
処理完了のメッセージ:
results len: 16
保存完了: 400 行
おぉ……! 16枚の画像から一気に400タグ が抽出されました。
サンプルを覗くと:
image category tag score
0 B2.png general monochrome 0.7211
1 B2.png general black_background 0.6906
2 B2.png general greyscale 0.6878
3 B2.png general no_humans 0.6707
4 B2.png general simple_background 0.6636
5 B2.png general solo 0.6372
6 B2.png general general 0.6319
7 B2.png general text_focus 0.6255
8 B2.png general 1girl 0.6187
9 B2.png general dark 0.6041
「モノクロ」「背景黒」「1girl」…人が説明してるみたいにタグが並んでる!
気づいたこと
・rating タグが便利
→ Safe / Questionable が自動判定。フィルタリングに使える。
・general タグは超細かい
→ 髪色・構図・背景まで出る。検索用データベースにピッタリ。
・character タグはデータセット依存
→ 知ってるキャラは出るけど、新キャラはもちろん出ない。
使い道いろいろ
🔍 画像整理:何千枚あっても一瞬でタグ検索可能に
🚫 コンテンツフィルタ:safe / explicit の自動仕分け
🎨 生成AIのプロンプト支援:出力されたタグをそのまま Stable Diffusion に投げると「元画像っぽい雰囲気」で再生成できる
📊 傾向分析:頻出タグを数えると「自分の画像フォルダの趣味傾向」が丸見えになる(笑)
手順
1. モデルとタグ辞書をダウンロード
from huggingface_hub import hf_hub_download
REPO_ID = "SmilingWolf/wd-eva02-large-tagger-v3"
onnx_path = hf_hub_download(REPO_ID, "model.onnx")
tags_path = hf_hub_download(REPO_ID, "selected_tags.csv")
2. 画像をアップロード
import os, shutil
from google.colab import files
os.makedirs("images", exist_ok=True)
uploaded = files.upload()
for name in uploaded.keys():
shutil.move(name, f"images/{name}")
3. 前処理関数
import numpy as np
from PIL import Image
IM_SIZE = 448
MEAN = np.array([0.485,0.456,0.406], dtype=np.float32)
STD = np.array([0.229,0.224,0.225], dtype=np.float32)
def preprocess(img: Image.Image):
img = img.convert("RGB").resize((IM_SIZE, IM_SIZE), Image.BICUBIC)
x = np.array(img).astype(np.float32) / 255.0
x = (x - MEAN) / STD
return x # (448,448,3)
4. タグ一覧の読み込み
import pandas as pd
tags_df = pd.read_csv(tags_path)
# category が数値のこともあるので変換
cat_map = {0:"general",1:"character",2:"rating"}
tag_names = tags_df["name"].tolist()
tag_cats = [cat_map.get(int(c), str(c)) for c in tags_df["category"].tolist()]
5. 推論準備(ONNX Runtime)
import onnxruntime as ort
providers = ["CUDAExecutionProvider","CPUExecutionProvider"]
sess = ort.InferenceSession(onnx_path, providers=[p for p in providers if p in ort.get_available_providers()])
input_name = sess.get_inputs()[0].name
output_name = sess.get_outputs()[0].name
6. タグ抽出関数
THRESH = {"rating":0.35, "character":0.50, "general":0.35}
TOPK = 25
def pick_tags(probs_vec, want_cat):
idxs = [j for j,c in enumerate(tag_cats) if c==want_cat]
sub = [(tag_names[j], float(probs_vec[j])) for j in idxs]
picked = [t for t in sub if t[1] >= THRESH[want_cat]]
if not picked:
sub.sort(key=lambda x:x[1], reverse=True)
picked = sub[:TOPK]
else:
picked.sort(key=lambda x:x[1], reverse=True)
picked = picked[:TOPK]
return picked
7. 推論ループ
import glob
from tqdm import tqdm
results = []
batch, names = [], []
BATCH = 8
image_paths = sorted(glob.glob("images/*"))
def emit_batch(batch, names):
if not batch: return
x = np.stack(batch, axis=0)
logits = sess.run([output_name], {input_name: x})[0]
probs = 1/(1+np.exp(-logits))
for i, fname in enumerate(names):
p = probs[i]
results.append({
"image": fname,
"rating": pick_tags(p,"rating"),
"character": pick_tags(p,"character"),
"general": pick_tags(p,"general"),
})
for fp in tqdm(image_paths):
img = Image.open(fp)
batch.append(preprocess(img))
names.append(os.path.basename(fp))
if len(batch) >= BATCH:
emit_batch(batch, names)
batch, names = [], []
emit_batch(batch, names)
print("results:", len(results), "images processed")
8. 保存
rows = []
for r in results:
for cat in ("rating","character","general"):
for tag,score in r[cat]:
rows.append({"image":r["image"],"category":cat,"tag":tag,"score":round(score,4)})
df = pd.DataFrame(rows)
df.to_csv("wd_eva02_results.csv", index=False)
import json
with open("wd_eva02_results.json","w",encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print("保存完了:", len(df), "行")
print(df.head(10))
実験してみた感想
正直、「16枚で400タグ」 って数字に驚きました。
タグの粒度が細かいので、ただ整理するだけじゃなく「AIに自分の絵柄を言語化させる」感覚もあります。
やっていて面白いのは、自分では気にしてなかった特徴をタグ化してくれるところ。「あ、この絵は背景黒で見栄えしてたんだ!」みたいな再発見がありました。
まとめ
・WD EVA02-Large Tagger v3は「自動タグ職人」
・Colabで動かすのは簡単
・小規模実験でも「大量のタグ」が出てきてワクワクする
・整理・検索・生成AI連携まで用途は広い
フリーランスエンジニアです。
AIや画像生成の記事色々書いているのでプロフィール見てみてください。
もし以下のようなご要望をお持ちでしたらお気軽にご相談ください。
AIサービスを開発したい、ビジネスにAIを組み込んで効率化したい、AIを使ったスマホアプリを開発したい、
ARを使ったアプリケーションを作りたい、スマホアプリを作りたいけどどこに相談したらいいかわからない…
いずれも中間コストを省いたリーズナブルな価格でお請けできます。
お仕事のご相談はこちらまで
rockyshikoku@gmail.com
機械学習やAR技術を使ったアプリケーションを作っています。
機械学習/AR関連の情報を発信しています。