ビジョントランスフォーマー(VITネットワークアーキテクチャ)

論文のダウンロードリンク: https://arxiv.org/abs/2010.11929

導入

1. VIT と従来の CNN の比較

画像処理における ViT (Vision Transformer) と従来の畳み込みニューラル ネットワーク (CNN) の間には、いくつかの重要な違いがあります。

1.モデル構造:

  • ViT: 主に Transformer 構造に基づいており、畳み込み層は使用されません。
  • CNN: 畳み込み層、プーリング層、完全接続層を使用します。

2.入力処理:

  • ViT: 画像を複数の固定サイズのチャンクに分割し、それらをすべて一度に処理します。
  • CNN: 畳み込みウィンドウを通じて画像全体を徐々にスキャンします。

3.計算の複雑さ:

  • ViT: 自己注意メカニズムにより、計算の複雑さが高くなる可能性があります。
  • CNN: 通常、最適化が容易で、計算の複雑さが比較的低いです。

4. データの依存関係:

  • ViT: 通常、効果的なトレーニングにはより多くのデータとコンピューティング リソースが必要です。
  • CNN: 小規模なデータセットでのトレーニングは比較的簡単です。

2. 画像タスクに Transformer が必要なのはなぜですか?

深層学習の歴史において、畳み込みニューラル ネットワーク (CNN) は長い間、画像タスクを処理するための主流のアーキテクチャでした。しかし、自然言語処理 (NLP) タスクへの Transformer の適用が成功したことで、研究者はコンピューター ビジョンにおける Transformer の可能性を検討し始めました。

柔軟なグローバル アテンション メカニズム

  • グローバル コンテキスト: ローカル受容野を持つ CNN とは異なり、Transformer にはグローバル受容野があり、画像全体の情報を融合できます。このグローバル コンテキストは、画像セグメンテーション、オブジェクト検出、マルチオブジェクト インタラクションなどの特定のタスクで非常に役立ちます。

解釈可能性と視覚化への配慮

  • 解釈可能性の向上: セルフ アテンション メカニズムのおかげで、モデルが意思決定を行う際に焦点を当てている領域を簡単に視覚化できるため、モデルの解釈可能性が向上します。

シーケンス間タスク

  • シーケンス出力の処理が容易になります。画像キャプションなどのタスクでは、画像情報とテキスト情報の両方を同様の Transformer アーキテクチャで処理できるため、両方を考慮することがより簡単になります。

適応力

  • さまざまなスケールや形状への適応が容易になる: Transformer は固定サイズのフィルターに依存しないため、理論的にはさまざまな入力への適応が容易になります。

1. 詳細なトランスフォーマー

1.1 Transformer の起源: NLP 分野における画期的な進歩

Transformer モデルは、もともと Google 研究者によって 2017 年の論文「Attending Is All You Need」で提案されました。このモデルは、主に Self-Attention メカニズムに基づいた新しいアーキテクチャを導入しており、当時の自然言語処理 (NLP) における一連のタスクを正常に解決します。NLP の分野における Transformer の重要な進歩と影響をいくつか紹介します。

1. シーケンス モデリングの問題に対する新しい視点
従来の RNN (リカレント ニューラル ネットワーク) および LSTM (長期短期記憶) ネットワークは、再帰的な性質のため、長いシーケンスを処理するときに勾配の消失または勾配の爆発の問題に遭遇します。変圧器合格自己注意のメカニズムシーケンス内の依存関係をうまくキャプチャし、シーケンス全体を並列処理できるため、多くの点で RNN や LSTM を上回ります。

2. セルフ アテンション メカニズム
Transformer モデルのセルフ アテンション メカニズムにより、モデルは異なる場所の入力間に直接の依存関係を確立できるため、モデルが文またはドキュメント内の文脈上の関係を理解し​​やすくなります。このメカニズムは、機械翻訳、テキスト要約、質問応答システムなど、長距離の依存関係をキャプチャする必要があるタスクに特に適しています。

3. 拡張性
による拡張性並列処理Transformer アーキテクチャは時間の複雑さが比較的少なく、最新のハードウェアをより効率的に利用できます。これにより、研究者は、より優れたパフォーマンスを達成する、より大規模で強力なモデルをトレーニングできるようになります。

4. マルチモーダルおよびマルチタスク学習のための Transformer のアーキテクチャ
は柔軟性が高く、次のような他の種類のデータやタスクに簡単に拡張できます。画像、音声、マルチモーダル入力この点は、その後の研究と応用において広く確認されています。

5. 事前トレーニングと微調整
Transformer アーキテクチャは、事前トレーニングと微調整のワークフローに適しています。BERT、GPT、T5 などの大規模な事前トレーニング済みモデルは Transformer 上に構築されており、さまざまな NLP タスクで新しいパフォーマンス ベンチマークを設定します。

1.2 トランスの基本構成

1.2.1 自己注意メカニズム

心理学的に言えば

  • 動物は複雑な環境で注目すべき点に効果的に焦点を合わせる必要がある
  • 心理的枠組み: 人間は自発的および非自発的な手がかりに基づいて注意点を選択します(注: ここでのカジュアルは、カジュアルという意味ではありません。翻訳されているため、ここでのカジュアルとは、積極的な観察と非活動的な観察を意味する必要があり、また、意図的および意図的ではないと理解することもできます。

私たちの前に 5 つの物体があると想像してください。新聞、研究論文、一杯のコーヒー、ノート、そして本です。赤いコーヒーカップを除いて、すべての紙製品は白黒で印刷されています。つまり、このコーヒーマグはこの視覚環境の中で際立って目立ち、思わず人々の注目を集めてしまうのです。そこで私たちはコーヒーに最も鋭い目を向けました
ここに画像の説明を挿入

そして読みたいという欲求はランダムな手がかりになった
ここに画像の説明を挿入

注意メカニズム

  • 存在する従来の CNN アーキテクチャ真ん中。畳み込み、プーリング、および完全に接続された層は、非自発的な手がかりのみを考慮します
  • 次に、注意メカニズムがランダムな手がかりを考慮することが示されます。
    • ランダムな手がかりはクエリと呼ばれます
    • 各入力は、値 (value) と非ランダムな手がかり (キー) のペアです(ここで、入力は環境として理解できます
    • いくつかの入力は、アテンションプーリング層を通じてバイアスされます。これは、いくつかのランダムな手がかりを追加しており、その中のいくつかの入力にバイアスをかけることができるためです。

計算プロセス

  1. ドット積の計算: 特定のクエリに対して、各キーでドット積を実行し、クエリと各キーの間の類似性を測定します。
  2. スケール: ドット積の結果をスケールします (通常はキー ベクトル次元の平方根で除算します)。
  3. 活性化関数: 重みの合計が 1 かつ 0 ~ 1 の間にあるように Softmax 活性化関数を適用します。
  4. 重み付き合計: 結果の重みを使用して、値のベクトルの重み付き合計を実行します。
  5. 出力: オプションの全結合 (線形) レイヤーを介して加重合計を変換し、その位置で出力を生成します。

マルチヘッド アテンション (Multi-Head Attendance)
さまざまな依存関係をより豊富に捉えるために、通常、マルチヘッド アテンションが使用されます。マルチヘッド アテンションでは、モデルは独立したクエリの複数のセット、キーと値の重み行列を維持し、それらを並行して計算します。各ヘッドの出力は完全に接続されたレイヤーを介して連結され、結合されます。

1.2.2 フィードフォワード ニューラル ネットワーク

フィードフォワード ニューラル ネットワーク (FFNN) は、最も初期の最も単純なニューラル ネットワーク アーキテクチャです。この種のネットワークの特徴は、データがネットワーク内で一方向にのみ、つまり入力層から隠れ層を通って、最後に出力層に伝播することです。この一方向のデータの流れが「フィードフォワード」という名前の由来です。

構造とコンポーネント

  1. 入力層:この層は生の入力データを受け取り、それを次の層に渡します。
  2. 隠れ層:ネットワークには、それぞれが複数のニューロンで構成される 1 つ以上の隠れ層を含めることができます。これらのレイヤーは、入力データの複雑なパターンをキャプチャします。
  3. 出力層:タスクの要件 (分類、回帰など) に従って、出力層はネットワークの最終出力を生成します。

活性化関数
非線形性を導入するために、通常、各ニューロンには活性化関数があります。一般的に使用されるアクティベーション関数は次のとおりです。

  • ReLU (整流線形ユニット)
  • シグモイド
  • Tanh (双曲線正接)
  • Leaky ReLU、Parametric ReLUなど

トレーニング
フィードフォワード ニューラル ネットワークは通常、バックプロパゲーション アルゴリズムを使用してトレーニングされます。これには以下が含まれます。

  1. 順伝播:入力層から開始して、データがネットワークを介して流れ、予測された出力が生成されます。
  2. 損失計算:予測出力と実際の目標に基づいて損失を計算します。
  3. 逆方向伝播:各重みに対する損失の勾配を計算し、ネットワーク内の重みを更新します。

Transformer でのアプリケーション
Transformer アーキテクチャは主にセルフ アテンション メカニズムに焦点を当てていますが、各アテンション モジュールの後にフィードフォワード ニューラル ネットワーク (通常は 2 層ネットワーク) があります。これにより、モデルに追加の計算能力が導入され、データのさまざまな特徴を捕捉するのに役立ちます。

1.2.3 残留接続

Transformer アーキテクチャでは、残りの接続が非常に重要な役割を果たします。これらはセルフ アテンション レイヤーとフィードフォワード ニューラル ネットワーク レイヤーの後に表示され、レイヤーの正規化と併用されることがよくあります。

構造と機能
Transformer では、各サブレイヤー (マルチヘッド セルフ アテンションやフィードフォワード ニューラル ネットワークなど) の出力がこのサブレイヤーの入力に追加されて、残りの接続が形成されます。この接続構造は次のように表現できます。

Output=Sublayer(x)+x
、またはより一般的には:
Output=LayerNorm(Sublayer(x)+x)

ここで、Sublayer(x) はサブレイヤー (マルチヘッド セルフ アテンションやフィードフォワード ニューラル ネットワークなど) の出力であり、 LayerNormはレイヤーの正規化です。

1.2.4 層の正規化

理論的根拠
レイヤー正規化の中心的な考え方は、各レイヤーの出力がほぼ同じスケールになるように、各レイヤーの各サンプルを個別に正規化することです。層の正規化は、完全に接続された層または畳み込み層の後で適用されますが、通常は活性化関数の前に適用されます。
数学的には次のように表されます。
ここに画像の説明を挿入

Transformer でのアプリケーション
Transformer アーキテクチャでは、層の正規化は通常、残留接続 (残留接続) と組み合わせて使用​​されます。各残りの接続の後に、モデルのトレーニングを安定させるための層正規化ステップが続きます。この組み合わせは、特に非常に深いモデルの場合、トレーニング中にモデルの数値安定性を維持するのに役立ちます。

class AddNorm(nn.Module):
    """残差连接后进行层规范化"""
    def __init__(self, normalized_shape, dropout, **kwargs):
        super(AddNorm, self).__init__(**kwargs)
        self.dropout = nn.Dropout(dropout)
        self.ln = nn.LayerNorm(normalized_shape)

    def forward(self, X, Y):
        return self.ln(self.dropout(Y) + X)

アドバンテージ

  1. 数値の安定性:レイヤーの正規化により、勾配の消失または爆発の問題が防止され、モデルのトレーニングが容易になります。
  2. 収束の加速:各レイヤーのスケールを調整することで、レイヤーの正規化によりモデルの収束を高速化できます。
  3. 適応性:レイヤーの正規化は、リカレント ニューラル ネットワーク (RNN) を含む、さまざまなタイプと深さのネットワーク アーキテクチャに適用できます。

欠点がある

  1. シーケンスの長さの依存性:可変長のシーケンスを扱う場合、レイヤー正規化はバッチ正規化ほど効果的ではない可能性があります。
  2. モデルの複雑さ:追加の学習可能なパラメーターが導入され、モデルの複雑さが増す可能性があります。

2. CNN から Vision Transformer へ

畳み込みニューラル ネットワーク (CNN) とビジョン トランスフォーマー (ViT) はどちらも画像処理タスクの一般的なモデルですが、設計哲学と適用範囲が異なります。両者の間の進化を以下に簡単に説明します。

2.1 CNN の限界

1. 局所受容野
CNN は局所受容野を通じて画像を処理しますが、これは一部のタスクでは制限となります。この設計は画像内の局所構造を識別するのには役立ちますが、キャプチャには適していない可能性があります。長距離依存関係。


2.加工時のコストを計算する高解像度の画像、畳み込み演算の計算コストが非常に高くなる可能性があります。

3. 空間構造の仮定
CNN は、入力データが何らかの空間構造を持っていることを前提としています。固有の空間的または時間的構造このため、明確な空間構造がなければ CNN をデータに適用するのは簡単ではありません。

4. パラメータ効率 パラメータ
効率の点では、さまざまな手法 (バッチ正規化、残差接続など) を使用したとしても、CNN は依然として Transformer モデルより劣る可能性があります。

2.2 ビジョントランスフォーマーの出現と動機

Vision Transformer は 2020 年に Google Research によって初めて提案され、その設計は自然言語処理の Transformer モデルからインスピレーションを受けました。

1. グローバル アテンション
CNN とは異なり、ViT はグローバル セルフ アテンション メカニズムを使用しています。遠距離依存関係

2. 計算効率
ViT パス自意識そしてフィードフォワード ニューラル ネットワーク特に高解像度の画像を扱う場合に、計算効率を達成します。

3. モジュール性とスケーラビリティ
ViT は優れたモジュール性とスケーラビリティを備えており、モデルのサイズと複雑さを簡単に調整できます。

4. パラメータの効率化
は多数のデータセットに対して実行されます事前トレーニング最後に、ViT は通常、高度なパラメーター効率を示します。つまり、同じ数のパラメーターを持つ CNN よりも優れたパフォーマンスを示します。

5. クロスモーダルアプリケーション
ViT はサポートしていないため、ハードコーディングされた空間仮定他の種類のデータやタスクにも簡単に適用できます。

3. ビジョントランスフォーマーの仕組み

3.1 入力: 画像をパッチに分割する

入力: 画像をパッチに分割します

  1. 画像セグメンテーション: Vision Transformer (ViT) はまず入力画像を複数に分割します。固定サイズのチャンク(パッチ)。これらの小さな断片は通常、四角、たとえば 16x16 ピクセル。
  2. 1 次元化:それぞれの小さなブロックが平坦化され、1D ベクトル
  3. マージ:これらすべての 1D ベクトルが結合されます。シーケンスに連結される、Transformer エンコーダーの入力として。

3.2 埋め込み: 線形埋め込みと位置埋め込み

  1. 線形埋め込み:小さなブロックは線形層 (通常は完全に接続された層) を介して埋め込まれ、適切な次元のベクトルに変換されます。これは非常に浅い水域を通過するのと同等です。CNNレイヤー特徴抽出を実行します。
  2. 位置埋め込み:小さいため1D中は元の位置情報が失われるしたがって、モデルがこれらのパッチの相対的または絶対的な位置を識別できるようにするために、位置埋め込みを追加する必要があります。
  3. マージ: 線形埋め込みと位置埋め込み通常、これらを加算して、位置情報を含む埋め込みシーケンスを生成します。

3.3 トランスエンコーダ

  1. セルフ アテンション レイヤー:このレイヤーは、さまざまなパッチ間の関係をより適切に表現するために、セルフ アテンション メカニズムを使用して入力シーケンス内の各要素 (つまり、各パッチとその対応する位置の埋め込み) を分析します。
  2. フィードフォワード ニューラル ネットワーク:自己注意層の出力はフィードフォワード ニューラル ネットワークに供給されます。
  3. 残留接続と層の正規化:セルフ アテンション層とフィードフォワード ニューラル ネットワークの後に、モデル トレーニングの安定性と効率を促進するために残留接続と層の正規化操作が行われます。
  4. スタックされたエンコーダ:上記のコンポーネントはすべて複数回 (たとえば、12 回または 24 回など) スタックされて、完全な Transformer エンコーダを形成します。
  5. 分類ヘッド:分類タスクの場合、エンコーダー出力シーケンスの最初の要素 (通常は特別な「[CLS]」トークンに対応) を取得し、それを分類のために完全に接続されたレイヤーに渡すのが一般的です。
class EncoderBlock(nn.Module):
    """Transformer编码器块"""
    def __init__(self, key_size, query_size, value_size, num_hiddens,
                 norm_shape, ffn_num_input, ffn_num_hiddens, num_heads,
                 dropout, use_bias=False, **kwargs):
        super(EncoderBlock, self).__init__(**kwargs)
        self.attention = d2l.MultiHeadAttention(
            key_size, query_size, value_size, num_hiddens, num_heads, dropout,
            use_bias)
        self.addnorm1 = AddNorm(norm_shape, dropout)
        self.ffn = PositionWiseFFN(
            ffn_num_input, ffn_num_hiddens, num_hiddens)
        self.addnorm2 = AddNorm(norm_shape, dropout)

    def forward(self, X, valid_lens):
        Y = self.addnorm1(X, self.attention(X, X, X, valid_lens))
        return self.addnorm2(Y, self.ffn(Y))

Transformer エンコーダーのレイヤーは入力の形状を変更しません。

3.4 出力ヘッド: 分類タスク

Vision Transformer (ViT) モデルでは、分類タスクの出力ヘッドは通常、全結合(線形)層、Transformer エンコーダーの出力をクラス ラベルの数にマップするレイヤー。ほとんどの実装では、通常は Transformer が使用されますエンコーダ出力最初の位置の機能 (通常、追加された特別な [CLS] タグに対応します)

4. ViT のバリアントと関連作品

画像分類タスクにおける Vision Transformer (ViT) の成功により、多くの研究者がそのバリ​​エーションと改良点を探求し始めました。ここでは、概要分析のためのいくつかの注目すべきバリアントと関連作業を示します。

4.1 DeiT (データ効率の高い画像変換器)

4.1.1 概要

  • コンセプト: DeiT はデータをより効果的に使用する方法に焦点を当てています。標準の ViT は事前トレーニングに多くのデータとコンピューティング リソースを必要としますが、DeiT はより効率的なトレーニング戦略を採用しています。データ拡張そして知識の蒸留, これを改善するために。
  • 主な機能:使用知識の蒸留などのさまざまなトレーニングテクニック学習率のスケジューリングとデータ拡張、大量のラベル付きデータへの依存を軽減します。
import torch
import torch.nn as nn
import torch.nn.functional as F

# 分割图像到patch
class PatchEmbedding(nn.Module):
    def __init__(self, patch_size, in_channels, embed_dim):
        super().__init__()
        self.proj = nn.Conv2d(in_channels, embed_dim, kernel_size=patch_size, stride=patch_size)

    def forward(self, x):
        x = self.proj(x)  # [B, C, H, W]
        x = x.flatten(2).transpose(1, 2)  # [B, num_patches, embed_dim]
        return x

# DeiT 模型主体
class DeiT(nn.Module):
    def __init__(self, patch_size, in_channels, embed_dim, num_heads, num_layers, num_classes):
        super().__init__()

        # 分割图像到patch并嵌入
        self.patch_embed = PatchEmbedding(patch_size, in_channels, embed_dim)

        # 特殊的 [CLS] token
        self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))

        # 位置嵌入
        num_patches = (224 // patch_size) ** 2
        self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))

        # Transformer 编码器
        encoder_layer = nn.TransformerEncoderLayer(embed_dim, num_heads)
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)

        # 分类器头
        self.fc = nn.Linear(embed_dim, num_classes)

    def forward(self, x):
        B = x.size(0)

        # 分割图像到patch并嵌入
        x = self.patch_embed(x)

        # 添加 [CLS] token
        cls_token = self.cls_token.repeat(B, 1, 1)
        x = torch.cat([cls_token, x], dim=1)

        # 添加位置嵌入
        x += self.pos_embed

        # 通过 Transformer
        x = self.transformer(x)

        # 只取 [CLS] 对应的输出用于分类任务
        x = x[:, 0]

        # 分类器
        x = self.fc(x)

        return x

# 参数
patch_size = 16
in_channels = 3
embed_dim = 768
num_heads = 12
num_layers = 12
num_classes = 1000  # 假设是一个1000分类问题

# 初始化模型
model = DeiT(patch_size, in_channels, embed_dim, num_heads, num_layers, num_classes)

# 假数据
x = torch.randn(32, 3, 224, 224)  # 32张3通道224x224大小的图片

# 模型前向推断
logits = model(x)

4.1.2 知識の蒸留

知識蒸留 (KD) は、大規模で複雑なモデル (「教師モデル」と呼ばれることが多い) から、より小規模で単純なモデル (「学生モデル」と呼ばれることが多い) に知識を転送するためのモデル圧縮手法です。 )。目標は、より大きなモデルと同様のパフォーマンスを維持しながら、モデルのサイズと推論時間を削減することです。

動作原理

  • 教師モデル:通常は事前トレーニング済み大型モデル、生成するために使用されますソフトラベル(ソフトラベル)、つまりカテゴリの確率分布です。
  • Student モデル:通常は、トレーニングする必要がある比較的小さなモデルです。教師のモデルを真似る
  • 蒸留損失:最も基本的な知識の蒸留では、スチューデント モデルのトレーニングに必要なだけでなく、真のラベルに対する損失 (クロスエントロピー損失など) を最小限に抑えますが、教師モデルによって予測されたソフトラベルに対する損失も最小限に抑えます。

簡単な知識蒸留コード例
教師モデル (Teacher_model) と生徒モデル (student_model) があると仮定します。以下は、PyTorch を使用した知識蒸留の簡単な例です。

import torch
import torch.nn.functional as F

# 假定 teacher_model 和 student_model 已经定义并初始化
# teacher_model = ...
# student_model = ...

# 数据加载器
# data_loader = ...

# 优化器
optimizer = torch.optim.Adam(student_model.parameters(), lr=0.001)

# 温度参数和软标签权重
temperature = 2.0
alpha = 0.9

# 训练循环
for data, labels in data_loader:
    optimizer.zero_grad()

    # 正向传播:教师和学生模型
    teacher_output = teacher_model(data).detach()  # 注意:通常不会计算教师模型的梯度
    student_output = student_model(data)

    # 计算损失
    hard_loss = F.cross_entropy(student_output, labels)  # 与真实标签的损失
    soft_loss = F.kl_div(F.log_softmax(student_output/temperature, dim=1),
                         F.softmax(teacher_output/temperature, dim=1))  # 与软标签的损失

    loss = alpha * soft_loss + (1 - alpha) * hard_loss

    # 反向传播和优化
    loss.backward()
    optimizer.step()

アプリケーション
シナリオ ナレッジ蒸留は、モデルの圧縮に適しているだけでなく、データ効率を向上させるための DeiT (Data-efficient Image Transformer) など、一部の特定のアプリケーションで小さなモデルのパフォーマンスを向上させるために使用することもできます。

4.1.3 知識蒸留により最適化された変圧器モデル

以下では、トレーニング済みの大きな Transformer モデル (教師モデル) と、より小さな Transformer モデル (学生モデル) があると仮定します。

注: ここでは簡単にするために、Transformer の単純な実装として nn.Transformer モジュールを使用します。必要に応じて、より複雑なモデルに置き換えることもできます。

損失関数は 2 つの部分で構成されます。1 つは学生モデルと実際のラベル間の損失で、もう 1 つは学生モデルと教師モデルの出力間のカルバック・ライブラー発散です。

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

# 定义简单的 Transformer 模型
class SimpleTransformer(nn.Module):
    def __init__(self, d_model, nhead, num_layers, num_classes):
        super(SimpleTransformer, self).__init__()
        self.encoder = nn.Transformer(d_model, nhead, num_layers)
        self.classifier = nn.Linear(d_model, num_classes)
    
    def forward(self, x):
        x = self.encoder(x)
        x = x.mean(dim=1)
        x = self.classifier(x)
        return x

# 定义损失函数
def distillation_loss(y, labels, teacher_output, T=2.0, alpha=0.5):
    return nn.CrossEntropyLoss()(y, labels) * (1. - alpha) + (alpha * T * T) * nn.KLDivLoss()(F.log_softmax(y/T, dim=1),
                                                     F.softmax(teacher_output/T, dim=1))

# 假设我们有一些数据
# 注意:这里使用随机数据仅作为示例
N = 100  # 数据点数量
d_model = 32  # 嵌入维度
nhead = 2  # 多头注意力的头数
num_layers = 2  # Transformer 层的数量
num_classes = 10  # 分类数
T = 2.0  # 温度参数
alpha = 0.5  # 蒸馏损失的权重因子

x = torch.randn(N, 10, d_model)
labels = torch.randint(0, num_classes, (N,))

# 初始化教师和学生模型
teacher_model = SimpleTransformer(d_model, nhead, num_layers, num_classes)
student_model = SimpleTransformer(d_model, nhead, num_layers, num_classes)

# 设置优化器
optimizer = optim.Adam(student_model.parameters(), lr=0.001)

# 模拟训练过程
for epoch in range(10):
    # 前向传播
    teacher_output = teacher_model(x).detach()  # 通常来说,教师模型是预先训练好的,因此不需要计算梯度
    student_output = student_model(x)
    
    # 计算损失
    loss = distillation_loss(student_output, labels, teacher_output, T, alpha)
    
    # 反向传播和优化
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    
    print(f"Epoch {
      
      epoch+1}, Loss: {
      
      loss.item()}")

4.2 ハイブリッド モデル (ViT + CNN)

ハイブリッド モデルは、ビジョン トランスフォーマー (ViT) と畳み込みニューラル ネットワーク (CNN) の利点を組み合わせて、より強力な画像認識機能を実現します。このようなモデルは通常、CNN を特徴抽出器として使用し、その出力が ViT への入力として使用されます。

4.2.1 なぜ混合モデルなのか?

  1. ローカルおよびグローバルの特徴: CNN はキャプチャーに非常に優れています。地域性、Transformer は処理できますグローバルな依存関係2 つを組み合わせることで、画像をより完全に理解できるようになります。
  2. 計算効率: CNN は一般に、画像データの処理効率が高くなります。を通ってモデルのフロントエンドは CNN を使用します、Transformer の計算の複雑さを軽減できます。
  3. データ効率: CNN の使用事前トレーニングされた特徴によりモデルのデータ効率を向上させることができますこれは、トレーニング データが少ないタスクに特に役立ちます。

4.2.2 インフラストラクチャ

典型的なハイブリッド モデルでは、通常、CNN が特徴抽出器として使用され、ViT が特徴のエンコードと分類として使用されます。

  1. 特徴抽出: CNN レイヤー (おそらく ResNet や VGG などの事前学習済みネットワーク) を使用して、入力画像から特徴を抽出します。
  2. 画像ブロックと埋め込み: CNN の出力をブロックし、線形埋め込み層 (または他の方法) を通じて Transformer に適したシーケンスに変換します。
  3. Transformer エンコーディング: ViT を使用した特徴のさらなるエンコーディング。
  4. 分類ヘッド:最後に、完全に接続された層が分類に使用されます。

4.2.3 例

import torch
import torch.nn as nn

# 假设使用 ResNet 的某个版本作为特征提取器
class FeatureExtractor(nn.Module):
    def __init__(self, ...):
        super().__init__()
        # 定义 CNN 结构,例如一个简化的 ResNet
        ...

    def forward(self, x):
        # 通过 CNN 提取特征
        return x

# ViT 作为编码器
class ViTEncoder(nn.Module):
    def __init__(self, ...):
        super().__init__()
        # 定义 Transformer 结构
        ...

    def forward(self, x):
        # 通过 Transformer 编码特征
        return x

# 混合模型
class HybridModel(nn.Module):
    def __init__(self, ...):
        super().__init__()
        self.feature_extractor = FeatureExtractor(...)
        self.vit_encoder = ViTEncoder(...)
        self.classifier = nn.Linear(...)

    def forward(self, x):
        x = self.feature_extractor(x)  # CNN 特征提取
        x = self.vit_encoder(x)  # Transformer 编码
        x = self.classifier(x)  # 分类头
        return x

4.3 スイングトランス

Swin Transformer は、コンピュータ ビジョン タスク用の Transformer アーキテクチャであり、スライディング ウィンドウに基づくセルフ アテンション メカニズムを提案します。このアプローチは、畳み込みニューラル ネットワーク (CNN) とトランスフォーマーの利点を組み合わせて、より高いモデルの効率とパフォーマンスを達成することを目指しています。

4.3.1 主な機能

  1. 階層的特徴抽出: CNN と同様に、Swin Transformer は次のことを実行します。多層特徴抽出, 各レイヤーはダウンサンプリングしますが、ここでは Transformer を通じて実装されます。
  2. スライディング ウィンドウ セルフ アテンション: Swin Transformer を使用スライディングウィンドウセルフアテンション機構、メカニズムはのみを考慮しますローカルコンテキスト情報、従来のトランスフォーマーの代わりにグローバルコンテキスト情報これ計算の複雑さの軽減
  3. チャンク化とマージ:複数のレベルで、Swin Transformer がパスします。チャンク化とマージ方法、段階的にシーケンスの長さを短くする、そして機能の寸法を増やす、より高いレベルの特徴抽出を実現します。
  4. 柔軟性: Swin Transformer は、画像分類、オブジェクト検出、セマンティック セグメンテーションなど、さまざまなコンピューター ビジョン タスクに使用できます。

4.3.2 インフラストラクチャ

  1. パッチ埋め込み:画像を複数の小さなパッチ(パッチ)に分割して使用します。線形埋め込み層埋め込むために。
  2. Swin Transformer ブロック:複数の Swin Transformer レイヤーで構成され、それぞれが 1 つ以上のスライディング ウィンドウ セルフ アテンション メカニズムとフィードフォワード ニューラル ネットワークを備えています。
  3. 責任者:特定のタスク (分類、検出など) に従って、Swin Transformer で最後の層さまざまな頭部構造を追加します。

4.3.3 コード例

  • PatchEmbedding:この部分は、入力画像を小さな断片に切り取って埋め込む役割を果たします。
  • WindowAttention:これは Swin Transformer に固有であり、ローカル ウィンドウ内のセルフ アテンションの計算に使用されます。
  • SwinBlock:ウィンドウ アテンション レイヤーと多層パーセプトロン (MLP) で構成されます。
  • SwinTransformer:最終的なモデル アーキテクチャ。
import torch
import torch.nn as nn
import torch.nn.functional as F

# 切分图像为patches
class PatchEmbedding(nn.Module):
    def __init__(self, in_channels, out_dim, patch_size):
        super().__init__()
        self.conv = nn.Conv2d(in_channels, out_dim, kernel_size=patch_size, stride=patch_size)

    def forward(self, x):
        x = self.conv(x)
        x = x.flatten(2).transpose(1, 2)
        return x

# 滑窗注意力
class WindowAttention(nn.Module):
    def __init__(self, dim, heads, window_size):
        super().__init__()
        self.dim = dim
        self.heads = heads
        self.window_size = window_size

        self.query = nn.Linear(dim, dim)
        self.key = nn.Linear(dim, dim)
        self.value = nn.Linear(dim, dim)

    def forward(self, x):
        # 假设 x 的形状为 [batch_size, num_patches, dim]
        # 分割为多个窗口
        windows = x.view(x.size(0), self.window_size, self.window_size, self.dim)

        # 计算 q, k, v
        q = self.query(windows)
        k = self.key(windows)
        v = self.value(windows)

        # 注意力计算
        attn = torch.einsum('bqhd,bkhd->bhqk', q, k)
        attn = F.softmax(attn, dim=-1)

        # 输出
        out = torch.einsum('bhqk,bkhd->bqhd', attn, v)
        out = out.contiguous().view(x.size(0), self.window_size * self.window_size, self.dim)

        return out

# Swin Transformer Block
class SwinBlock(nn.Module):
    def __init__(self, dim, heads, window_size):
        super().__init__()
        self.norm1 = nn.LayerNorm(dim)
        self.attn = WindowAttention(dim, heads, window_size)
        self.norm2 = nn.LayerNorm(dim)
        self.mlp = nn.Sequential(
            nn.Linear(dim, dim),
            nn.GELU(),
            nn.Linear(dim, dim)
        )

    def forward(self, x):
        x = x + self.attn(self.norm1(x))
        x = x + self.mlp(self.norm2(x))
        return x

# Swin Transformer 模型
class SwinTransformer(nn.Module):
    def __init__(self, in_channels, out_dim, patch_size, num_classes):
        super().__init__()
        self.patch_embedding = PatchEmbedding(in_channels, out_dim, patch_size)

        # 假设我们有 4 个 Swin Blocks 和窗口大小为 8
        self.blocks = nn.ModuleList([
            SwinBlock(out_dim, 8, 8) for _ in range(4)
        ])

        self.global_avg_pool = nn.AdaptiveAvgPool1d(1)
        self.fc = nn.Linear(out_dim, num_classes)

    def forward(self, x):
        x = self.patch_embedding(x)
        for block in self.blocks:
            x = block(x)
        x = self.global_avg_pool(x.mean(dim=1))
        x = self.fc(x.squeeze(-1))
        return x

# 测试模型
if __name__ == '__main__':
    model = SwinTransformer(3, 128, 4, 10)
    x = torch.randn(16, 3, 32, 32)  # 假设有 16 张 32x32 的图像
    y = model(x)
    print(y.shape)  # 应该输出 torch.Size([16, 10])

5. ViTのメリットとデメリット

5.1 CNNと比較した利点

  1. 長距離依存関係の処理の向上: Transformer アーキテクチャはもともと、遠距離依存これは、いくつかの複雑な画像認識タスクで非常に役立ちます。
  2. パラメータ効率: ViTには可能性があるより少ないパラメータで CNN と同じパフォーマンスを実現
  3. 解釈可能性: 自己注意メカニズムの出力画像の各部分のモデルを分析するために使用できます懸念、これはモデルの解釈に役立ちます。
  4. 柔軟性と一般化: Transformer は依存しません。固定サイズのフィルターまたはローカル領域したがって、視覚データのさまざまなタイプや構造に対してより適切に一般化できる可能性があります。
  5. エンドツーエンドのトレーニング:特別に設計された一部の CNN アーキテクチャと比較して、ViT は統合されたアーキテクチャで最初から最後までトレーニングできます。

5.2 ViT の課題と限界

  1. 計算の複雑さ:大きな画像、グローバルな自己注意メカニズムの計算の複雑さは非常に高くなる可能性があります。これが、当初 ViT が NLP の分野で主に使用されていた理由の 1 つです。
  2. データ依存: ViT は通常、効果的なトレーニングのための大量のラベル付きデータこれは、ラベル付きデータがあまりないシナリオでは問題になる可能性があります。
  3. 不安定なトレーニング: Transformer アーキテクチャは通常 CNN よりも高速です訓練するのが難しい特に十分なコンピューティング リソースとデータが存在しない場合に発生します。
  4. 局所特徴処理は CNN ほど優れていません:組み込みの畳み込み演算がないため、ViT は一部のローカル機能に依存するタスク(テクスチャ認識など) は、特別に設計された CNN ほど優れていません。
  5. メモリ消費量:特に大きな画像や長いシーケンスでは、Transformer モデル (ViT を含む) が頻繁に発生します。もっとメモリが必要です
  6. 過学習のリスク:通常、モデルの複雑さとパラメーターの数が大きいため、ViT過学習になりやすい特にデータ量が少ない場合。

おすすめ

転載: blog.csdn.net/m0_63260018/article/details/130999047