TL;DR:
自前でCNNを一から学習しなくても、ImageNetで学習済みのResNetやEfficientNetの途中層から、優秀な特徴量ベクトルを取得できる!分類やクラスタリング、検索にも使える。


使い方(PyTorch例)

pythonコピーする編集するfrom torchvision import models
import torch.nn as nn

model = models.resnet50(pretrained=True)
model = nn.Sequential(*list(model.children())[:-1])  # 最終FC層の手前まで

features = model(image_tensor)  # 出力 shape: [1, 2048, 1, 1]

👉 features.squeeze()[2048] のベクトル完成!


これが便利な理由

メリット内容
💡 再学習不要既にImageNetで訓練済み=高精度な抽象表現が得られる
🔍 類似画像検索やクラスタリングにも流用可cosine類似度で近い画像を見つけられる
🧠 転移学習の事前確認にも最適学習前に「うまく分離できそうか」検証できる

覚えておこう!
学習済みCNNは「特徴量抽出器」としても超優秀。
「最終層の1つ手前」こそ、AIの“見ている世界”を取り出す入り口です!

「どの層を“特徴ベクトル”に使う?」を決める 3 ステップ

ステップ何をする?ざっくり理由
1. 目的別の“経験則”を当てはめる画像検索・分類最終 GAP の後(=FC 手前)
セグメンテーション・姿勢推定中〜深層の 2D フィーチャマップ(解像度が残る)
テクスチャ/スタイル解析浅〜中層
畳み込み層の深さで「低レベル→高レベル」情報に変わるため
2. “線形プローブ”で試す各層の出力を凍結し、上に1 枚の線形分類器だけ乗せて小データで評価。→ 最も精度が高い層を採用早い+コード数十行で客観比較できる
3. t-SNE / UMAP で可視化候補層ごとにベクトルを 2 次元に圧縮→クラスタの分離を目視。「似た画像が近いか」を直感確認できる

実践コード例(PyTorch)

pythonコピーする編集するimport torch, torchvision.models as models
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

model = models.resnet50(weights="DEFAULT").eval()
layers = list(model.children())[:-1]  # FC を除外

def extract(layer_idx, x):
    with torch.no_grad():
        feat = torch.nn.Sequential(*layers[:layer_idx+1])(x)
        return feat.flatten(1).cpu().numpy()

best_acc, best_idx = 0, 0
for i in [3, 4, 5, 6]:                  # conv3_x〜conv5_x + GAP
    X_train = extract(i, images_train)
    X_test  = extract(i, images_test)
    clf = LogisticRegression(max_iter=200).fit(X_train, y_train)
    acc = accuracy_score(y_test, clf.predict(X_test))
    print(f"Layer {i}: {acc:.3f}")
    if acc > best_acc:
        best_acc, best_idx = acc, i
print("✅ 最適層 =", best_idx)

迷ったらココ!

タイプ推奨層備考
汎用特徴(検索・分類)GAP 後 (2048d)ResNet系なら layer4 → avgpool
中解像度マップが欲しいlayer3 出力 (1024ch, 28×28)深さと空間情報のバランス◎
浅いテクスチャlayer1 or layer2形より質感を重視

まとめ

  1. 目的ファーストの経験則で候補を絞る
  2. 線形プローブで簡易ベンチ → 数分で客観比較
  3. 可視化で直感チェック

この 3 点で「どの層を使うべきか」がデータに基づいて判断できます。

「最終 GAP の後(=FC 手前)」って何? ざっくり図解


┌─ 畳み込み層① ─┐  ← エッジや色 (低レベル特徴)
│                 │
├─ 畳み込み層② ─┤  ← 形・パーツ (中レベル)
│                 │
├─ 畳み込み層③ ─┤  ← 全体の構造・意味 (高レベル)
│                 │
└─ Global Average Pooling (GAP) ─→ ★ココ!
                     │            (2048 など固定長ベクトル)
                     ▼
            Fully Connected (FC) 層
                     │            ← 「犬」「猫」…各クラスのスコア
                    Softmax
                     ▼
                  予測クラス
用語役割例(ResNet-50)
GAP (Global Average Pooling)画像の**縦×横を全部“平均”**して、各チャンネル(特徴マップ)を 1 個の数値にまとめる処理。
空間情報を潰して“意味だけ”を残す
avgpool 出力 → 形状 [batch, 2048, 1, 1]
FC (Fully Connected) 層さきほどの 2048 次元ベクトルを受け取り、クラス数(例:1000)だけスコアを出す線形層。fc 重み形状 [1000, 2048]

「最終 GAP の後=FC 手前」
GAP でできた 2048 次元ベクトル(ResNet-50/101 系の例)のこと。

  • ここには「この画像は何か」を示す濃縮された情報が詰まっている。
  • まだクラスに振り分けていないので汎用的(犬・猫・車など共通)。
  • ベクトルとして取り出しやすく、検索やクラスタリングに転用しやすい。

つまり “FC に渡す直前のベクトル”「GAP 後」=「最後から 1 個手前の層」
これを 特徴量 として使うのが鉄板というわけ

アーキテクチャー別の次元数の例

アーキテクチャ“GAP 後=FC 手前” の次元数備考
ResNet-18 / 34512軽量版のためチャンネルが少ない
ResNet-50 / 101 / 1522048Bottleneck ブロックで幅倍増
EfficientNet-B01280Compound scaling によって決定
EfficientNet-V2-S1536V2 系はやや増量
MobileNetV3-Large960モバイル向けで小さめ
Vision Transformer (ViT-Base, CLS トークン)768CNN ではないが「CLS 埋め込み」を同様に利用
YOLOv8-n Pose (backbone)512軽量 YOLO 系バックボーン

どうやって確認する?

pythonコピーする編集するimport torchvision.models as models
model = models.resnet18(weights="DEFAULT")
print(list(model.children())[-2].out_channels)  # → 512
  • [-2]avgpool 直前層(最後の conv 出力)のチャンネル数=ベクトル長。
  • ViT 系は model.config.hidden_size がそのまま次元数です。

実践ポイント

  1. モデルが軽いほど次元も小さい → メモリ節約になるが情報量も減る。
  2. 用途に合わせて選択
    • 高精度検索やクラスタリング:ResNet50 以上(2048d など)が安定
    • モバイル・エッジ:MobileNet, EfficientNet-B0(〜1000d)
  3. 次元数が足りないと感じたら、中間層を追加で平均したり、PCA/UMAP で圧縮して扱う方法もあります。

まとめ

  • ベクトル長は “最後の畳み込みチャンネル数” で決まる(アーキ設計次第)。
  • 2048 は一例にすぎないので、使うモデルの仕様を確認して取り出しましょう!

投稿者 kojiro777

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です