STEP 17:ViTの実装と応用

🚀 STEP 17: ViTの実装と応用

HuggingFace Transformers、事前学習ViTの利用、
ファインチューニング、DeiT、Attention Mapの可視化を学びます

📋 このステップで学ぶこと

  • HuggingFace Transformersライブラリの基本
  • 事前学習済みViTモデルを使った画像分類
  • カスタムデータセットでのファインチューニング
  • ファインチューニング戦略(全層、分類ヘッドのみ、段階的)
  • DeiT(Data-efficient Image Transformers)と知識蒸留
  • Attention Mapの可視化と解釈
  • 層ごとのAttentionパターンの違い

🤗 1. HuggingFace Transformersライブラリ

HuggingFace Transformersは、Transformerモデルを簡単に使えるようにした統一的なライブラリです。NLP(自然言語処理)だけでなく、コンピュータビジョンや音声処理にも対応しています。

1-1. HuggingFace Transformersとは

【HuggingFace Transformersの概要】 ■ 何ができるか 1. 事前学習済みモデルを簡単に利用 → 数行のコードで最先端モデルを使用可能 2. ファインチューニング → 自分のデータセットに合わせて微調整 3. モデルの共有 → Model Hubで世界中のモデルを共有 ■ 対応しているViT系モデル ・ViT(Vision Transformer) ・DeiT(Data-efficient Image Transformers) ・Swin Transformer ・BEiT ・CLIP(画像とテキストの同時処理) ・DETR(物体検出) ・SegFormer(セグメンテーション) など多数 ■ なぜHuggingFaceを使うのか 1. 統一API → モデルの切り替えが簡単 → ViT → DeiT → Swin がコード数行の変更で可能 2. 事前学習済みモデル → 大規模データで訓練済み → すぐに高性能な結果が得られる 3. ドキュメント充実 → 学習コストが低い → 日本語情報も増えている ■ Model Hub https://huggingface.co/models 世界中の研究者・開発者がモデルを公開 → 最新のモデルをすぐに試せる → 自分のモデルも公開可能

1-2. インストール

Google Colabを使う場合は、以下のコマンドでインストールできます。

# HuggingFace Transformersのインストール # Google Colabでは最初から入っていることが多いが、 # 最新版にするためにインストールを実行 !pip install transformers torch torchvision # バージョン確認 import transformers print(f”transformers version: {transformers.__version__}”)

実行結果:

transformers version: 4.35.0
【インストールオプション】 基本インストール: pip install transformers PyTorch込み: pip install transformers[torch] 画像処理込み: pip install transformers[torch,vision] すべての機能: pip install transformers[all] ※ Google Colabでは pip の代わりに !pip を使用

📦 2. 事前学習済みViTモデルの利用

事前学習済みのViTモデルを使って、画像分類を行う方法を学びます。最も簡単な方法から、詳細な制御ができる方法まで順番に見ていきましょう。

2-1. 最も簡単な方法:pipeline

💡 pipelineとは

HuggingFaceのpipelineは、前処理から推論まですべてを自動で行ってくれる便利な関数です。
たった3行で画像分類ができます。

※ コードが横に長い場合は横スクロールできます

# =================================================== # 最も簡単な方法:pipeline # =================================================== from transformers import pipeline from PIL import Image # 1. 画像分類パイプラインを作成 # model: 使用するモデル名(Model Hubから) # 初回実行時にモデルが自動ダウンロードされる classifier = pipeline( “image-classification”, # タスクの種類 model=”google/vit-base-patch16-224″ # モデル名 ) # 2. サンプル画像をダウンロード(テスト用) import requests from io import BytesIO url = “https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg” response = requests.get(url) image = Image.open(BytesIO(response.content)) # 3. 推論実行 # top_k: 上位何件の予測を返すか results = classifier(image, top_k=5) # 4. 結果を表示 print(“Top 5 Predictions:”) for result in results: print(f” {result[‘label’]}: {result[‘score’]*100:.2f}%”)

実行結果:

Top 5 Predictions: tabby, tabby cat: 45.23% tiger cat: 28.67% Egyptian cat: 15.34% Persian cat: 5.82% Siamese cat, Siamese: 2.43%
【pipelineの仕組み】 classifier = pipeline(“image-classification”, model=”…”) この1行で以下が自動的に行われる: 1. モデルのダウンロード → Model Hubから事前学習済みモデルを取得 → 初回のみダウンロード、2回目以降はキャッシュを使用 2. プロセッサ(前処理)のロード → 画像のリサイズ(224×224) → 正規化(mean、stdで標準化) 3. モデルのロード → PyTorchモデルをメモリに読み込み → 評価モードに設定 results = classifier(image, top_k=5) この1行で以下が自動的に行われる: 1. 前処理 → PILイメージをテンソルに変換 → リサイズ、正規化 2. 推論 → モデルに入力 → ロジットを取得 3. 後処理 → softmaxで確率に変換 → 上位k件を抽出 → クラス名に変換

2-2. 詳細な制御:processor + model

より細かい制御が必要な場合は、processorとmodelを別々にロードします。

# =================================================== # 詳細な制御:processor + model # =================================================== from transformers import ViTImageProcessor, ViTForImageClassification from PIL import Image import torch # =================================================== # 1. モデルとプロセッサのロード # =================================================== # モデル名を指定 # google/vit-base-patch16-224: # – google: 提供元 # – vit-base: モデルサイズ(base = 86M パラメータ) # – patch16: パッチサイズ(16×16) # – 224: 入力画像サイズ(224×224) model_name = “google/vit-base-patch16-224″ # ViTImageProcessor: 画像の前処理を担当 # – リサイズ(224×224) # – 正規化(ImageNetの平均・標準偏差) # – テンソル変換 processor = ViTImageProcessor.from_pretrained(model_name) # ViTForImageClassification: 分類用ViTモデル # – Transformer Encoder + 分類ヘッド # – ImageNetの1000クラス分類用 model = ViTForImageClassification.from_pretrained(model_name) # 評価モードに設定(Dropout無効化、BatchNorm固定) model.eval() # GPUが使える場合はGPUに転送 device = torch.device(‘cuda’ if torch.cuda.is_available() else ‘cpu’) model = model.to(device) print(f”モデル: {model_name}”) print(f”クラス数: {model.config.num_labels}”) print(f”デバイス: {device}”)

実行結果:

モデル: google/vit-base-patch16-224 クラス数: 1000 デバイス: cuda
# =================================================== # 2. 画像の読み込みと前処理 # =================================================== # 画像を読み込み(PILイメージとして) # convert(‘RGB’): 必ずRGB形式に変換(グレースケールやRGBAの場合があるため) image = Image.open(‘cat.jpg’).convert(‘RGB’) # 前処理を実行 # processor(): 画像をモデルの入力形式に変換 # – リサイズ: 224×224 # – 正規化: (pixel – mean) / std # – テンソル化: PILイメージ → PyTorchテンソル # return_tensors=”pt”: PyTorchテンソルで返す(”tf”ならTensorFlow) inputs = processor(images=image, return_tensors=”pt”) # GPUに転送(モデルと同じデバイスに) inputs = {k: v.to(device) for k, v in inputs.items()} print(f”入力テンソルのshape: {inputs[‘pixel_values’].shape}”) print(f”入力テンソルのデバイス: {inputs[‘pixel_values’].device}”)

実行結果:

入力テンソルのshape: torch.Size([1, 3, 224, 224]) 入力テンソルのデバイス: cuda:0
# =================================================== # 3. 推論の実行 # =================================================== # torch.no_grad(): 勾配計算を無効化 # – 推論時は勾配不要(訓練時のみ必要) # – メモリ使用量削減、処理速度向上 with torch.no_grad(): # モデルに入力を渡して出力を取得 # **inputs: 辞書を展開して渡す(pixel_values=…) outputs = model(**inputs) # outputs.logits: 分類のロジット(softmax前の値) # shape: (batch_size, num_classes) = (1, 1000) logits = outputs.logits # softmaxで確率に変換 # dim=-1: 最後の次元(クラス次元)に対してsoftmax probs = torch.softmax(logits, dim=-1) print(f”ロジットのshape: {logits.shape}”) print(f”確率の合計: {probs.sum().item():.4f}”) # 1.0になるはず

実行結果:

ロジットのshape: torch.Size([1, 1000]) 確率の合計: 1.0000
# =================================================== # 4. 結果の取得と表示 # =================================================== # Top-5の確率とインデックスを取得 # torch.topk: 上位k個の値とインデックスを返す top5_prob, top5_idx = torch.topk(probs, 5, dim=-1) # クラスIDからクラス名への変換辞書を取得 # model.config.id2label: {0: “tench”, 1: “goldfish”, …} id2label = model.config.id2label # 結果を表示 print(“\nTop 5 Predictions:”) print(“-” * 40) for i in range(5): # .item(): テンソルから Python の数値を取り出す class_id = top5_idx[0][i].item() class_name = id2label[class_id] prob = top5_prob[0][i].item() print(f”{i+1}. {class_name}”) print(f” 確率: {prob*100:.2f}%”) print(f” クラスID: {class_id}”)

実行結果:

Top 5 Predictions: —————————————- 1. tabby, tabby cat 確率: 45.23% クラスID: 281 2. tiger cat 確率: 28.67% クラスID: 282 3. Egyptian cat 確率: 15.34% クラスID: 285 4. Persian cat 確率: 5.82% クラスID: 283 5. Siamese cat, Siamese 確率: 2.43% クラスID: 284

2-3. 利用可能な事前学習済みモデル

モデル名 事前学習データ パラメータ数 精度(ImageNet)
vit-base-patch16-224 ImageNet-21K → 1K 86M 81.8%
vit-base-patch32-224 ImageNet-21K → 1K 88M 79.5%
vit-large-patch16-224 ImageNet-21K → 1K 307M 84.0%
vit-huge-patch14-224 ImageNet-21K → 1K 632M 85.4%
【モデル選択の指針】 ■ 高精度が必要な場合 model = “google/vit-large-patch16-224” または model = “google/vit-huge-patch14-224” → 精度優先、計算コストは高い ■ バランス重視(推奨) model = “google/vit-base-patch16-224” → 精度と速度のバランスが良い → 多くの実務で十分な性能 ■ 高速推論が必要な場合 model = “google/vit-base-patch32-224” → パッチサイズが大きい = パッチ数が少ない → 計算量が少なく高速 → 精度はやや低下 ■ モデル名の読み方 google/vit-base-patch16-224 │ │ │ │ │ │ │ └─ 入力画像サイズ │ │ └──────── パッチサイズ │ └────────────── モデルサイズ └──────────────────── 提供元

🎓 3. カスタムデータセットでのファインチューニング

事前学習済みモデルを自分のデータセットに合わせて微調整(ファインチューニング)する方法を学びます。

3-1. ファインチューニングとは

💡 ファインチューニングの基本

ファインチューニングとは、大規模データで事前学習したモデルを、
自分の小さなデータセットで追加学習することです。

利点:
・少量データでも高精度(数百〜数千枚で十分)
・学習時間が短い(数十分〜数時間)
・事前学習の知識を活用

【転移学習の流れ】 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. 事前学習(Pre-training) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 大規模データセット(ImageNet-21K: 1400万枚) 学習される知識: ・エッジ、テクスチャ、形状 ・一般的な物体の特徴 ・階層的な視覚表現 → Googleなどが実行済み → 私たちはこの結果を使用 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. ファインチューニング(Fine-tuning) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 自分のデータセット(例: 犬 vs 猫 1000枚) 学習される知識: ・タスク固有の特徴 ・犬と猫を区別する特徴 → 私たちが実行 → 少量データ・短時間で高精度 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 比喩 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 事前学習 = 大学で一般教養を学ぶ ファインチューニング = 専門分野を学ぶ → 一般教養があるから専門が早く習得できる

3-2. ファインチューニングの3つの戦略

【ファインチューニング戦略の比較】 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 戦略1: 全層学習(Full Fine-tuning) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ すべてのパラメータを更新 ViT全体(Transformer Encoder + 分類ヘッド)を学習 推奨データ量: 10,000枚以上 学習率: 2e-5(小さめ) 利点: ・最高精度が期待できる ・タスクに完全に適応 欠点: ・過学習のリスクが高い ・計算コストが高い ・大量データが必要 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 戦略2: 分類ヘッドのみ学習(Linear Probing) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Transformer Encoderを凍結 分類ヘッドのみを学習 推奨データ量: 100〜1,000枚 学習率: 1e-3(大きめ) 利点: ・過学習しにくい ・高速(パラメータ数が少ない) ・少量データで可能 欠点: ・精度に限界がある ・事前学習の特徴をそのまま使用 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 戦略3: 段階的学習(Gradual Unfreezing) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Phase 1: 分類ヘッドのみ(1-2 epochs) Phase 2: 上位層 + 分類ヘッド(1-2 epochs) Phase 3: 全層(1-2 epochs) 推奨データ量: 1,000〜10,000枚 利点: ・バランスが良い ・安定した学習 ・過学習を防ぎつつ高精度 欠点: ・実装がやや複雑 ・学習率の調整が必要 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ データ量と戦略の対応 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 〜500枚: 分類ヘッドのみ 500〜1000枚: 上位層 + 分類ヘッド 1000〜10000枚: 段階的学習 10000枚〜: 全層学習

3-3. 実装:カスタムデータセットでのファインチューニング

犬と猫の分類タスクを例に、ファインチューニングの実装を見ていきましょう。

# =================================================== # ファインチューニングの実装 # =================================================== # 必要なライブラリのインポート from transformers import ViTImageProcessor, ViTForImageClassification from transformers import TrainingArguments, Trainer from torch.utils.data import Dataset import torch from PIL import Image import os from sklearn.metrics import accuracy_score, precision_recall_fscore_support # =================================================== # 1. カスタムデータセットクラスの定義 # =================================================== class CustomImageDataset(Dataset): “”” カスタム画像データセット PyTorchのDatasetクラスを継承 __len__と__getitem__を実装する必要がある “”” def __init__(self, image_paths, labels, processor): “”” Args: image_paths: 画像ファイルパスのリスト labels: 対応するラベルのリスト(0, 1, 2, …) processor: ViTImageProcessor(前処理用) “”” self.image_paths = image_paths self.labels = labels self.processor = processor def __len__(self): “””データセットのサイズを返す””” return len(self.image_paths) def __getitem__(self, idx): “”” idx番目のデータを返す Returns: dict: {‘pixel_values’: テンソル, ‘labels’: ラベル} “”” # 画像を読み込み image = Image.open(self.image_paths[idx]).convert(‘RGB’) # 前処理を適用 inputs = self.processor(images=image, return_tensors=”pt”) # バッチ次元を削除(Trainerが後で追加する) # (1, 3, 224, 224) → (3, 224, 224) pixel_values = inputs[‘pixel_values’].squeeze(0) return { ‘pixel_values’: pixel_values, ‘labels’: torch.tensor(self.labels[idx], dtype=torch.long) }
# =================================================== # 2. データの準備 # =================================================== # 実際のプロジェクトでは、以下のようにファイルパスとラベルを準備 # ここでは例として構造を示す # データディレクトリの構造: # data/ # train/ # dog/ # img1.jpg # img2.jpg # … # cat/ # img1.jpg # img2.jpg # … # val/ # dog/ # … # cat/ # … def load_dataset_paths(data_dir, class_names): “”” ディレクトリ構造からファイルパスとラベルを取得 Args: data_dir: データディレクトリのパス class_names: クラス名のリスト [‘dog’, ‘cat’] Returns: image_paths: 画像パスのリスト labels: ラベルのリスト “”” image_paths = [] labels = [] for label_idx, class_name in enumerate(class_names): class_dir = os.path.join(data_dir, class_name) if os.path.exists(class_dir): for filename in os.listdir(class_dir): if filename.lower().endswith((‘.jpg’, ‘.jpeg’, ‘.png’)): image_paths.append(os.path.join(class_dir, filename)) labels.append(label_idx) return image_paths, labels # クラス設定 class_names = [‘dog’, ‘cat’] # 0: dog, 1: cat num_classes = len(class_names) # ラベルマッピング id2label = {i: name for i, name in enumerate(class_names)} label2id = {name: i for i, name in enumerate(class_names)} print(f”クラス数: {num_classes}”) print(f”id2label: {id2label}”) print(f”label2id: {label2id}”)

実行結果:

クラス数: 2 id2label: {0: ‘dog’, 1: ‘cat’} label2id: {‘dog’: 0, ‘cat’: 1}
# =================================================== # 3. モデルとプロセッサのロード # =================================================== model_name = “google/vit-base-patch16-224″ # プロセッサをロード processor = ViTImageProcessor.from_pretrained(model_name) # モデルをロード(分類ヘッドをカスタムクラス数に変更) # ignore_mismatched_sizes=True: # 事前学習済みモデルは1000クラス、今回は2クラス # サイズが異なるのでこのオプションで許可 model = ViTForImageClassification.from_pretrained( model_name, num_labels=num_classes, # クラス数を指定 id2label=id2label, # ID→ラベル名の辞書 label2id=label2id, # ラベル名→IDの辞書 ignore_mismatched_sizes=True # サイズ不一致を許可 ) print(f”モデルのクラス数: {model.config.num_labels}”) print(f”パラメータ数: {sum(p.numel() for p in model.parameters()):,}”)

実行結果:

モデルのクラス数: 2 パラメータ数: 85,800,194
# =================================================== # 4. 訓練設定 # =================================================== training_args = TrainingArguments( # 出力ディレクトリ(モデル保存先) output_dir=”./vit-finetuned”, # バッチサイズ # GPUメモリに応じて調整(8, 16, 32など) per_device_train_batch_size=16, per_device_eval_batch_size=16, # エポック数 # 過学習を防ぐため少なめに設定 num_train_epochs=5, # 評価と保存のタイミング # “epoch”: 各エポック終了時 # “steps”: 指定ステップごと evaluation_strategy=”epoch”, save_strategy=”epoch”, # 学習率 # ファインチューニングでは小さめに設定 learning_rate=2e-5, # 正則化(過学習防止) weight_decay=0.01, # ロギング設定 logging_dir=”./logs”, logging_steps=10, # ベストモデルの保存 load_best_model_at_end=True, metric_for_best_model=”accuracy”, # 保存するチェックポイント数の制限 save_total_limit=2, # Trainerの内部設定 remove_unused_columns=False, ) print(“訓練設定完了”)
# =================================================== # 5. 評価指標の定義 # =================================================== def compute_metrics(eval_pred): “”” 評価指標を計算する関数 Args: eval_pred: (logits, labels) のタプル logits: モデルの出力 (N, num_classes) labels: 正解ラベル (N,) Returns: dict: 評価指標の辞書 “”” logits, labels = eval_pred # ロジットから予測クラスを取得(argmax) predictions = logits.argmax(axis=-1) # 正解率 accuracy = accuracy_score(labels, predictions) # Precision, Recall, F1 # average=’weighted’: クラスの出現頻度で重み付け precision, recall, f1, _ = precision_recall_fscore_support( labels, predictions, average=’weighted’ ) return { ‘accuracy’: accuracy, ‘precision’: precision, ‘recall’: recall, ‘f1’: f1 } print(“評価指標の関数を定義完了”)
# =================================================== # 6. データセットの作成(実際のデータがある場合) # =================================================== # 実際のプロジェクトでは以下のようにデータセットを作成 # train_paths, train_labels = load_dataset_paths(‘data/train’, class_names) # val_paths, val_labels = load_dataset_paths(‘data/val’, class_names) # # train_dataset = CustomImageDataset(train_paths, train_labels, processor) # val_dataset = CustomImageDataset(val_paths, val_labels, processor) # =================================================== # 7. Trainerの作成と訓練 # =================================================== # trainer = Trainer( # model=model, # args=training_args, # train_dataset=train_dataset, # eval_dataset=val_dataset, # compute_metrics=compute_metrics, # ) # # # 訓練開始 # print(“訓練を開始します…”) # trainer.train() # # # 最終評価 # print(“\n最終評価:”) # results = trainer.evaluate() # for key, value in results.items(): # print(f” {key}: {value:.4f}”) # # # モデルを保存 # trainer.save_model(“./vit-finetuned-best”) # processor.save_pretrained(“./vit-finetuned-best”) # print(“\nモデルを保存しました: ./vit-finetuned-best”)

3-4. 層の凍結による戦略の実装

# =================================================== # 戦略別の実装例 # =================================================== # ————————————————— # 戦略1: 分類ヘッドのみ学習(Linear Probing) # ————————————————— def freeze_encoder(model): “”” Transformer Encoderを凍結し、分類ヘッドのみ学習可能にする 少量データ(100〜1000枚)で有効 “”” for name, param in model.named_parameters(): # “classifier” を含まないパラメータを凍結 if “classifier” not in name: param.requires_grad = False # 学習可能なパラメータ数を確認 trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) total = sum(p.numel() for p in model.parameters()) print(f”学習可能パラメータ: {trainable:,} / {total:,} ({trainable/total*100:.2f}%)”) # 使用例 # freeze_encoder(model)

実行結果(例):

学習可能パラメータ: 1,538 / 85,800,194 (0.00%)
# ————————————————— # 戦略2: 上位層 + 分類ヘッド # ————————————————— def freeze_lower_layers(model, num_layers_to_freeze=8): “”” 下位の層を凍結し、上位の層と分類ヘッドのみ学習可能にする Args: model: ViTモデル num_layers_to_freeze: 凍結する層数(0〜11) 中量データ(1000〜5000枚)で有効 “”” for name, param in model.named_parameters(): # 分類ヘッドは常に学習可能 if “classifier” in name: param.requires_grad = True continue # 凍結する層を判定 # ViTの層名は “encoder.layer.0”, “encoder.layer.1″, … の形式 should_freeze = False for i in range(num_layers_to_freeze): if f”encoder.layer.{i}.” in name: should_freeze = True break param.requires_grad = not should_freeze # 学習可能なパラメータ数を確認 trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) total = sum(p.numel() for p in model.parameters()) print(f”凍結層数: {num_layers_to_freeze}”) print(f”学習可能パラメータ: {trainable:,} / {total:,} ({trainable/total*100:.2f}%)”) # 使用例: 下位8層を凍結、上位4層と分類ヘッドを学習 # freeze_lower_layers(model, num_layers_to_freeze=8)

実行結果(例):

凍結層数: 8 学習可能パラメータ: 28,313,090 / 85,800,194 (33.00%)
# ————————————————— # 戦略3: 段階的学習(Gradual Unfreezing) # ————————————————— def gradual_unfreeze_training(model, train_dataset, val_dataset, processor): “”” 段階的に層を解凍しながら訓練 Phase 1: 分類ヘッドのみ(2 epochs) Phase 2: 上位4層 + 分類ヘッド(2 epochs) Phase 3: 全層(1 epoch) “”” # =================== # Phase 1: 分類ヘッドのみ # =================== print(“=” * 50) print(“Phase 1: 分類ヘッドのみ学習”) print(“=” * 50) # Encoderを凍結 for name, param in model.named_parameters(): if “classifier” not in name: param.requires_grad = False # 訓練(大きめの学習率) args_phase1 = TrainingArguments( output_dir=”./phase1″, num_train_epochs=2, learning_rate=1e-3, # 大きめ per_device_train_batch_size=16, evaluation_strategy=”epoch”, save_strategy=”no”, logging_steps=50, remove_unused_columns=False, ) trainer = Trainer( model=model, args=args_phase1, train_dataset=train_dataset, eval_dataset=val_dataset, compute_metrics=compute_metrics, ) trainer.train() # =================== # Phase 2: 上位4層 + 分類ヘッド # =================== print(“\n” + “=” * 50) print(“Phase 2: 上位4層 + 分類ヘッドを学習”) print(“=” * 50) # 上位4層を解凍 for name, param in model.named_parameters(): if “encoder.layer.8” in name or \ “encoder.layer.9” in name or \ “encoder.layer.10” in name or \ “encoder.layer.11” in name or \ “classifier” in name or \ “layernorm” in name.lower(): param.requires_grad = True # 訓練(中程度の学習率) args_phase2 = TrainingArguments( output_dir=”./phase2″, num_train_epochs=2, learning_rate=5e-5, # 中程度 per_device_train_batch_size=16, evaluation_strategy=”epoch”, save_strategy=”no”, logging_steps=50, remove_unused_columns=False, ) trainer = Trainer( model=model, args=args_phase2, train_dataset=train_dataset, eval_dataset=val_dataset, compute_metrics=compute_metrics, ) trainer.train() # =================== # Phase 3: 全層 # =================== print(“\n” + “=” * 50) print(“Phase 3: 全層を学習”) print(“=” * 50) # 全層を解凍 for param in model.parameters(): param.requires_grad = True # 訓練(小さめの学習率) args_phase3 = TrainingArguments( output_dir=”./phase3″, num_train_epochs=1, learning_rate=2e-5, # 小さめ per_device_train_batch_size=16, evaluation_strategy=”epoch”, save_strategy=”epoch”, load_best_model_at_end=True, metric_for_best_model=”accuracy”, logging_steps=50, remove_unused_columns=False, ) trainer = Trainer( model=model, args=args_phase3, train_dataset=train_dataset, eval_dataset=val_dataset, compute_metrics=compute_metrics, ) trainer.train() return model # 使用例 # model = gradual_unfreeze_training(model, train_dataset, val_dataset, processor)

🎯 4. DeiT(Data-efficient Image Transformers)

DeiTは、少量データでもViTを効果的に学習できるように改良されたモデルです。知識蒸留(Knowledge Distillation)という技術を使います。

4-1. DeiTの概要

💡 DeiTの革新

ViTの問題点:
・大規模データ(数千万〜数億枚)が必要
・ImageNet-1K(130万枚)だけでは性能が低い

DeiTの解決策:
・強力なデータ拡張(RandAugment、MixUp、CutMix)
・知識蒸留(教師モデルから学習)
・蒸留トークン([DISTILL])の導入

【DeiTの成果】 ImageNet-1K(130万枚)のみで訓練した場合: ┌─────────────────────────────────────────────────┐ │ モデル │ Top-1 Accuracy │ ├─────────────────────────────────────────────────┤ │ ViT-Base(蒸留なし) │ 76.3% │ │ DeiT-Base(蒸留なし) │ 81.8% (+5.5%) │ │ DeiT-Base(蒸留あり) │ 83.4% (+7.1%) │ └─────────────────────────────────────────────────┘ DeiT vs 大規模事前学習ViT: ┌─────────────────────────────────────────────────┐ │ モデル │ データ量 │ 精度 │ ├─────────────────────────────────────────────────┤ │ ViT-Base (ImageNet-21K) │ 1400万枚 │ 81.8%│ │ DeiT-Base(蒸留) │ 130万枚 │ 83.4%│ └─────────────────────────────────────────────────┘ → 少量データでも大規模事前学習を超える性能!

4-2. 知識蒸留(Knowledge Distillation)

【知識蒸留の仕組み】 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 通常の学習 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 入力画像 ↓ 学生モデル(ViT) ↓ 予測確率 ↓ 損失 = CrossEntropy(予測, 正解ラベル) 正解ラベル(ハードターゲット): 猫: 1.0 犬: 0.0 馬: 0.0 … → 「猫か否か」の情報のみ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 知識蒸留による学習 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 入力画像 ↓ ┌─────────────────────────────────┐ │ 教師モデル 学生モデル │ │ (CNN) (ViT) │ └─────────────────────────────────┘ ↓ ↓ 教師の出力 学生の出力 └──────┬──────┘ ↓ 損失 = α × L_hard + (1-α) × L_soft L_hard: 正解ラベルとの損失 L_soft: 教師の出力との損失(蒸留損失) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 教師の出力(ソフトターゲット) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 教師モデル(CNN)の出力: 猫: 0.70 犬: 0.15 ← 「犬に似ている」情報 虎: 0.10 ← 「虎にも似ている」情報 馬: 0.03 … → クラス間の関係(暗黙的知識)を含む → この知識を学生に転移 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ なぜ効果があるのか ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. より多くの情報 正解ラベル: 「猫である」 教師の出力: 「猫である、犬に似ている、虎にも似ている」 → 豊富な情報から学習 2. CNNのInductive Biasを活用 教師(CNN): 局所性、階層性を持つ → その知識をViTに転移 → ViTの弱点(大量データ必要)を補う 3. 滑らかな学習 ハードターゲット: 0か1 ソフトターゲット: 確率分布 → 勾配が滑らか、学習が安定

4-3. 蒸留トークン

【DeiTの蒸留トークン】 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ViTの構造(復習) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 入力: [CLS] + パッチ1 + パッチ2 + … + パッチ196 197トークン 出力: [CLS]’ → 分類ヘッドに入力 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DeiTの構造 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 入力: [CLS] + [DISTILL] + パッチ1 + パッチ2 + … + パッチ196 198トークン(1つ増えた) 出力: [CLS]’ → 正解ラベルとの損失(L_hard) [DISTILL]’ → 教師モデルとの損失(L_soft) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2つのトークンの役割 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [CLS]トークン: 目的: 正解ラベルを学習 損失: CrossEntropy(予測, 正解ラベル) → ハードターゲットからの学習 [DISTILL]トークン: 目的: 教師モデルの出力を学習 損失: KL_Divergence(予測, 教師の出力) → ソフトターゲットからの学習 利点: ・2つの異なる目的を分離 ・各トークンが専門的に学習 ・干渉が少ない ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 推論時の使い方 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 方法1: [CLS]のみ使用 方法2: [DISTILL]のみ使用 方法3: 平均 ([CLS]’ + [DISTILL]’) / 2 ← 最高精度 DeiTでは方法3が推奨される

4-4. DeiTの使用方法

# =================================================== # DeiTの使用(HuggingFace Transformers) # =================================================== from transformers import DeiTImageProcessor, DeiTForImageClassification from PIL import Image import torch # =================================================== # 1. モデルとプロセッサのロード # =================================================== # DeiT-Base(蒸留あり)モデル # “distilled” が名前に含まれる = 蒸留トークンを持つ model_name = “facebook/deit-base-distilled-patch16-224″ # プロセッサ(前処理) processor = DeiTImageProcessor.from_pretrained(model_name) # モデル model = DeiTForImageClassification.from_pretrained(model_name) model.eval() print(f”モデル: {model_name}”) print(f”クラス数: {model.config.num_labels}”)

実行結果:

モデル: facebook/deit-base-distilled-patch16-224 クラス数: 1000
# =================================================== # 2. 推論 # =================================================== # 画像を読み込み image = Image.open(‘cat.jpg’).convert(‘RGB’) # 前処理 inputs = processor(images=image, return_tensors=”pt”) # 推論 with torch.no_grad(): outputs = model(**inputs) logits = outputs.logits probs = torch.softmax(logits, dim=-1) # Top-5予測 top5_prob, top5_idx = torch.topk(probs, 5) print(“\nTop 5 Predictions (DeiT):”) print(“-” * 40) for i in range(5): class_id = top5_idx[0][i].item() class_name = model.config.id2label[class_id] prob = top5_prob[0][i].item() print(f”{i+1}. {class_name}: {prob*100:.2f}%”)

実行結果:

Top 5 Predictions (DeiT): —————————————- 1. tabby, tabby cat: 52.34% 2. tiger cat: 25.12% 3. Egyptian cat: 12.78% 4. Persian cat: 4.56% 5. Siamese cat, Siamese: 2.89%
🎯 DeiTの意義

実務での利点:
・大規模データセット不要(ImageNet-1Kで十分)
・ViTと同じ推論速度(追加コストなし)
・CNNの知識を活用しつつ、ViTの柔軟性を得る

使い分け:
・データが少ない場合 → DeiT(蒸留あり)推奨
・データが十分ある場合 → ViTでも可
・最高精度を目指す場合 → DeiT(蒸留あり)

🔍 5. Attention Mapの可視化

ViTのAttention Mapを可視化することで、モデルが画像のどこに注目しているかを理解できます。

5-1. Attention Mapの抽出

# =================================================== # Attention Mapの可視化 # =================================================== import torch import numpy as np import matplotlib.pyplot as plt from transformers import ViTModel, ViTImageProcessor from PIL import Image # =================================================== # 1. モデルの準備(Attention出力を有効化) # =================================================== model_name = “google/vit-base-patch16-224” # プロセッサ processor = ViTImageProcessor.from_pretrained(model_name) # ViTModel: 分類ヘッドなしのベースモデル # output_attentions=True: Attention行列を出力に含める model = ViTModel.from_pretrained( model_name, output_attentions=True # これが重要! ) model.eval() print(“Attention出力を有効化したモデルをロードしました”)
# =================================================== # 2. 画像の前処理と推論 # =================================================== # 画像を読み込み image = Image.open(‘cat.jpg’).convert(‘RGB’) # 前処理 inputs = processor(images=image, return_tensors=”pt”) # 推論(Attentionも取得) with torch.no_grad(): outputs = model(**inputs) # Attentionを取得 # outputs.attentions: タプル(層数分) # 各要素: (batch_size, num_heads, num_tokens, num_tokens) # = (1, 12, 197, 197) attentions = outputs.attentions print(f”層数: {len(attentions)}”) print(f”各層のAttention shape: {attentions[0].shape}”)

実行結果:

層数: 12 各層のAttention shape: torch.Size([1, 12, 197, 197])
【Attentionテンソルの構造】 attentions[layer_idx] の shape: (1, 12, 197, 197) │ │ │ │ │ │ │ └─ どのトークンに注目しているか │ │ └────── どのトークンが │ └────────── ヘッド数 └───────────── バッチサイズ 例: attentions[11][0][5][0][10] = 第12層、ヘッド5、トークン0([CLS])が トークン10に向けるAttention重み 197トークン: – トークン0: [CLS]トークン – トークン1〜196: 14×14 = 196パッチ

5-2. Attention Mapの可視化関数

# =================================================== # 3. Attention Map可視化関数 # =================================================== def visualize_attention_map(attentions, layer_idx=-1, head_idx=None): “”” Attention Mapを可視化 Args: attentions: モデルのAttention出力 layer_idx: 可視化する層(-1で最終層) head_idx: 可視化するヘッド(Noneで全ヘッド平均) Returns: attn_map: 14×14のAttention Map “”” # 指定層のAttentionを取得 # shape: (1, num_heads, 197, 197) attn = attentions[layer_idx][0] # バッチ次元を削除 if head_idx is not None: # 特定のヘッドのみ attn = attn[head_idx] # (197, 197) else: # 全ヘッドの平均 attn = attn.mean(dim=0) # (197, 197) # [CLS]トークンが各パッチに向けるAttentionを取得 # attn[0, 1:]: [CLS](インデックス0)から # パッチ(インデックス1〜196)へのAttention attn_cls = attn[0, 1:] # (196,) # 14×14のグリッドに再構成 num_patches = int(np.sqrt(attn_cls.shape[0])) # 14 attn_map = attn_cls.reshape(num_patches, num_patches) # NumPyに変換 attn_map = attn_map.cpu().numpy() # 0-1に正規化 attn_map = (attn_map – attn_map.min()) / (attn_map.max() – attn_map.min()) return attn_map # Attention Mapを取得 attn_map = visualize_attention_map(attentions, layer_idx=-1) print(f”Attention Map shape: {attn_map.shape}”)

実行結果:

Attention Map shape: (14, 14)
# =================================================== # 4. 可視化の実行 # =================================================== # 3つの画像を並べて表示 fig, axes = plt.subplots(1, 3, figsize=(15, 5)) # 元画像 axes[0].imshow(image) axes[0].set_title(“Original Image”, fontsize=14) axes[0].axis(‘off’) # Attention Map im = axes[1].imshow(attn_map, cmap=’viridis’) axes[1].set_title(“Attention Map (Last Layer)”, fontsize=14) axes[1].axis(‘off’) plt.colorbar(im, ax=axes[1], fraction=0.046) # 重ね合わせ # 元画像にAttention Mapをオーバーレイ axes[2].imshow(image) # リサイズしてオーバーレイ attn_resized = np.array(Image.fromarray((attn_map * 255).astype(np.uint8)).resize(image.size, Image.BILINEAR)) / 255 axes[2].imshow(attn_resized, cmap=’jet’, alpha=0.5) axes[2].set_title(“Overlay”, fontsize=14) axes[2].axis(‘off’) plt.tight_layout() plt.savefig(‘attention_visualization.png’, dpi=150, bbox_inches=’tight’) plt.show() print(“attention_visualization.png を保存しました”)

5-3. 層ごとのAttention比較

# =================================================== # 5. 層ごとのAttention比較 # =================================================== def visualize_attention_across_layers(attentions, image): “””複数の層のAttentionを比較””” # 可視化する層(第1, 4, 7, 10, 12層) layer_indices = [0, 3, 6, 9, 11] fig, axes = plt.subplots(1, len(layer_indices) + 1, figsize=(20, 4)) # 元画像 axes[0].imshow(image) axes[0].set_title(“Original”, fontsize=12) axes[0].axis(‘off’) # 各層のAttention for i, layer_idx in enumerate(layer_indices): attn_map = visualize_attention_map(attentions, layer_idx=layer_idx) im = axes[i + 1].imshow(attn_map, cmap=’viridis’) axes[i + 1].set_title(f”Layer {layer_idx + 1}”, fontsize=12) axes[i + 1].axis(‘off’) plt.tight_layout() plt.savefig(‘attention_layers.png’, dpi=150, bbox_inches=’tight’) plt.show() print(“attention_layers.png を保存しました”) # 実行 visualize_attention_across_layers(attentions, image)

5-4. Attention Mapの解釈

【Attention Mapから分かること】 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. モデルの注目領域 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 明るい領域 = モデルが強く注目 暗い領域 = モデルがあまり注目していない 例: 猫の画像 明るい: 猫の顔、体 暗い: 背景(木、空) → モデルは猫に注目して分類している ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. 層による違い ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 浅い層(第1-4層): ・Attentionが分散 ・画像全体を均等に見る ・低レベル特徴(エッジ、テクスチャ) 視覚的イメージ: ┌──────────┐ │▓▓░░▓▓░░▓▓│ ← 分散したパターン │░░▓▓░░▓▓░░│ │▓▓░░▓▓░░▓▓│ └──────────┘ 中間層(第5-8層): ・物体の形が見え始める ・パーツ(耳、鼻など)に集中 ・中レベル特徴 視覚的イメージ: ┌──────────┐ │░░▓▓▓▓░░░░│ ← 物体の形状 │░░▓▓▓▓░░░░│ │░░░░░░░░░░│ └──────────┘ 深い層(第9-12層): ・Attentionが集中 ・識別に重要な領域のみ ・高レベル特徴(物体全体) 視覚的イメージ: ┌──────────┐ │░░░███░░░░│ ← 猫の顔に集中 │░░░░█░░░░░│ │░░░░░░░░░░│ └──────────┘ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3. CNNとの比較 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CNN(CAM/Grad-CAM): ・クラス活性化マップ ・「どこが分類に重要か」 ・後処理で生成 ViT(Attention Map): ・トークン間の関係 ・「どことどこが関連しているか」 ・モデル内部で直接計算 ViTの利点: ・明示的な関係を可視化 ・解釈がより直接的 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4. 実務での活用 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. デバッグ 誤分類の原因を調査 → Attentionが不適切な領域に向いている? 2. モデルの検証 モデルが適切な特徴を学習しているか確認 → 医療画像で病変部位に注目している? 3. 説明可能性 ユーザーに予測の根拠を説明 → 「この領域を見て判断しました」

📝 練習問題

問題1:HuggingFace Transformersの基本(基礎)

HuggingFace Transformersを使って、事前学習済みViTで画像分類を行う最小限のコードを書いてください。

解答:

最も簡単な方法(pipeline):

from transformers import pipeline from PIL import Image # 画像分類パイプラインを作成 classifier = pipeline( “image-classification”, model=”google/vit-base-patch16-224″ ) # 画像を読み込み image = Image.open(“cat.jpg”) # 推論 results = classifier(image, top_k=5) # 結果を表示 for result in results: print(f”{result[‘label’]}: {result[‘score’]*100:.2f}%”)

より詳細な制御が必要な場合:

from transformers import ViTImageProcessor, ViTForImageClassification from PIL import Image import torch # プロセッサとモデルをロード processor = ViTImageProcessor.from_pretrained(“google/vit-base-patch16-224”) model = ViTForImageClassification.from_pretrained(“google/vit-base-patch16-224”) model.eval() # 画像を読み込んで前処理 image = Image.open(“cat.jpg”).convert(‘RGB’) inputs = processor(images=image, return_tensors=”pt”) # 推論 with torch.no_grad(): outputs = model(**inputs) probs = torch.softmax(outputs.logits, dim=-1) # Top-5予測 top5_prob, top5_idx = torch.topk(probs, 5) for i in range(5): class_name = model.config.id2label[top5_idx[0][i].item()] prob = top5_prob[0][i].item() print(f”{class_name}: {prob*100:.2f}%”)

問題2:ファインチューニング戦略(中級)

1000枚の犬と猫の画像データセットでViTをファインチューニングする場合、どの戦略が最適か説明してください。

解答:

推奨戦略:段階的学習(Gradual Unfreezing)

理由:

1. データ量(1000枚)との相性 ・全層学習: 過学習リスク高い(データ不足) ・分類ヘッドのみ: 精度に限界 ・段階的学習: バランスが良い ← 最適 2. 段階的学習の流れ Phase 1(2 epochs): 分類ヘッドのみ ・学習率: 1e-3(大きめ) ・目的: 新タスク(犬vs猫)に適応 Phase 2(2 epochs): 上位4層 + 分類ヘッド ・学習率: 5e-5(中程度) ・目的: タスク固有の特徴を微調整 Phase 3(1 epoch): 全層 ・学習率: 2e-5(小さめ) ・目的: 全体を微調整 3. 期待される精度 ・Phase 1後: 85-90% ・Phase 2後: 90-95% ・Phase 3後: 95-98%

データ拡張も重要:

・RandomResizedCrop ・RandomHorizontalFlip ・ColorJitter ・RandomRotation → 実質的なデータ量を増やし、過学習を防ぐ

問題3:DeiTの知識蒸留(中級)

DeiTにおける知識蒸留の仕組みと、なぜ教師モデル(CNN)の知識がViT学生モデルの性能向上に寄与するのか説明してください。

解答:

1. 知識蒸留の仕組み

通常の学習: 損失 = CrossEntropy(予測, 正解ラベル) 正解ラベル(ハードターゲット): 猫: 1.0, 犬: 0.0, 馬: 0.0, … → 「猫か否か」の情報のみ 知識蒸留: 損失 = α × L_hard + (1-α) × L_soft L_hard: 正解ラベルとの損失 L_soft: 教師モデルの出力との損失 教師の出力(ソフトターゲット): 猫: 0.70, 犬: 0.15, 虎: 0.10, 馬: 0.03, … → 「猫である、犬や虎に似ている」情報を含む

2. CNNの知識がViTに有効な理由

理由1: Inductive Biasの補完 ・CNN: 局所性、階層性という強いInductive Bias ・ViT: Inductive Biasが弱い → 大量データ必要 知識蒸留により: CNNの「画像に特化した知識」をViTに転移 → ViTがCNNのInductive Biasを間接的に学習 → 少量データでも高性能 理由2: クラス間関係の学習 教師の出力: 猫: 0.70, 犬: 0.15, 虎: 0.10 → 「猫は犬や虎に似ている」 学生(ViT)も同様の関係を学習 → テスト時の誤分類パターンが改善 理由3: より多くの情報 ハードターゲット: 「猫である」 ソフトターゲット: 「猫である、犬に似ている、虎にも似ている」 → 豊富な情報から学習

3. 蒸留トークンの役割

DeiTの構造: [CLS] + [DISTILL] + パッチ1 + … + パッチ196 役割分担: [CLS]: 正解ラベルを学習(ハードターゲット) [DISTILL]: 教師の出力を学習(ソフトターゲット) 利点: ・2つの目的を独立に最適化 ・干渉が少なく、効果的な学習

問題4:Attention Mapの解釈(上級)

ViTのAttention Mapを可視化した際、浅い層と深い層でAttentionパターンがどのように異なるか、具体例を挙げて説明してください。

解答:

例:猫の画像でのAttentionパターン

1. 浅い層(第1-4層)

特徴: ・Attentionが分散 ・画像全体を均等に見る ・低レベル特徴(エッジ、テクスチャ、色) 視覚的イメージ: ┌──────────────┐ │ ▓▓░░▓▓░░▓▓░░ │ ← チェッカーボード状 │ ░░▓▓░░▓▓░░▓▓ │ に分散 │ ▓▓░░▓▓░░▓▓░░ │ │ ░░▓▓░░▓▓░░▓▓ │ └──────────────┘ 解釈: ・まだ「猫」を認識していない ・局所的なパターンを処理中 ・CNNの初期層と類似

2. 中間層(第5-8層)

特徴: ・物体の形状が見え始める ・パーツ(耳、鼻、体)に集中 ・中レベル特徴 視覚的イメージ: ┌──────────────┐ │ ░░░░░░░░░░░░ │ │ ░░▓▓▓▓▓▓░░░░ │ ← 猫の輪郭が │ ░░▓▓▓▓▓▓░░░░ │ 見え始める │ ░░░░░░░░░░░░ │ └──────────────┘ 解釈: ・物体として認識し始める ・背景との分離が進む ・パーツ間の関係を学習中

3. 深い層(第9-12層)

特徴: ・Attentionが強く集中 ・識別に重要な領域のみ ・高レベル特徴(物体全体、クラス識別) 視覚的イメージ: ┌──────────────┐ │ ░░░░░░░░░░░░ │ │ ░░░░███░░░░░ │ ← 猫の顔に │ ░░░░░█░░░░░░ │ 強く集中 │ ░░░░░░░░░░░░ │ └──────────────┘ 解釈: ・「猫らしさ」を決定づける領域に注目 ・背景は完全に無視 ・最終的な分類判断に直結

4. この違いが意味すること

階層的な特徴学習: 浅い層: 低レベル特徴(エッジ、テクスチャ) 中間層: 中レベル特徴(パーツ、形状) 深い層: 高レベル特徴(物体、意味) CNNとの類似点: 層が深くなるほど抽象的な特徴を学習 → CNNと同様の階層性 ViTの特徴: すべての層でグローバルな受容野を持つ → 層が深くなるほど「選択的」に注目

📝 STEP 17 のまとめ

✅ このステップで学んだこと

1. HuggingFace Transformers
・pipelineで簡単に推論
・processor + modelで詳細な制御

2. ファインチューニング
・全層学習、分類ヘッドのみ、段階的学習の3戦略
・データ量に応じて戦略を選択

3. DeiT
・知識蒸留で少量データでも高性能
・蒸留トークンでCNNの知識を活用

4. Attention Map
・可視化でモデルの注目領域を理解
・浅い層は分散、深い層は集中

💡 重要ポイント

実務でのViT活用:
・HuggingFace Transformersで簡単に利用可能
・事前学習モデル + 転移学習が基本
・少量データではDeiT(知識蒸留)が有効

次のSTEP 18では、「Swin TransformerとDETR」を学びます。
階層的なViTと、Transformerベースの物体検出を習得します!

📝

学習メモ

コンピュータビジョン(CV) - Step 17

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE