拡張(ホール)コンボリューションを理解するための記事(コード含む)

はじめに: この記事の個々の内容と写真はさまざまなブログから引用しましたが、長い間のため、元の著者のリンクが見つかりません。必要な場合は、私に連絡してください。

目次

1. 拡張畳み込みとは何ですか? 拡張畳み込みを使用する理由

2. 拡張コンボリューションの特徴(メリット)

3. 拡張畳み込みの特性の理解

1. まずは特性を見てみる②:出力される特徴マップ(特徴マップ)のサイズが変わらないことを保証できる

2. 拡張コンボリューション機能1:コンボリューションカーネルの受容野を拡大

 4. 拡張畳み込みの問題

4.1 グリッド効果

4.2 長距離の情報は意味を持たない場合がある

5、多層拡張畳み込みデザインルール HDC (4 番目の問題を解決するため)

 5.1 最初のルールを理解する

 5.2 2 番目のルールを理解する

 5.3 3 番目のルールを理解する

5.4 HDC原理とアプリケーションでの画像分割効果を満たす伸長率設定

付録 1: 拡張畳み込みコード

付録 2: HDC は拡張畳み込みコードを描画します


1. 拡張畳み込みとは何ですか? 拡張畳み込みを使用する理由

拡張畳み込み (最初のものはMULTI-SCALE CONTEXT AGGREGATION BY DILATED CONVOLUTIONS (拡張畳み込みに基づくマルチスケール コンテキストの融合。2015)

元の提案は、画像セグメンテーションの問題を解決するために提案されました一般的な画像セグメンテーション アルゴリズムは、通常、プーリング層と畳み込み層を使用して、受容野(Receptive Filed) を増加させ、また、特徴マップのサイズ(解像度)を削減します。画像のサイズを復元するためのアップサンプリングでは特徴マップの縮小と拡大のプロセスにより精度が失われます。そのため、特徴マップのサイズを変更せずに受容野を拡大できる操作が必要となりそれによってダウンサンプリングに代わる操作が必要になります。およびアップサンプリング操作。

2. 拡張コンボリューションの特徴(メリット)

パラメータの数を変えずに、コンボリューションカーネルの受容野が増加するため、各コンボリューション出力にはより広範囲の情報が含まれます。

同時に、出力される特徴マップ( feature map )のサイズが変わらないことを保証できます。

3. 拡張畳み込みの特性の理解

1. まずは特性を見てみましょう②:出力される特徴マップ ( feature map )のサイズが変わらないことを保証できます

1 次元信号の場合:

 1 次元信号を取得します。黒はパディングを表します

(a) は通常の畳み込み、ステップ サイズ 2、畳み込みカーネル 3

(b) は、ステップ サイズ 1、畳み込みカーネル 3 の通常の畳み込みです。7 つの入力特徴があり、線形加重加算後の出力特徴は 7 であることがわかります。

(c) は拡張コンボリューションであり、ステップ サイズは 1、コンボリューション カーネルは 3、拡張率は 2 です。入力特徴は 7 であり、線形加重加算後の出力特徴は 7 であることがわかります。

拡張畳み込みによって出力される特徴マップ(feature map)のサイズは、通常の畳み込みと同じで変化しないことがわかります。ホール畳み込みの有無は出力特徴のサイズに影響を与えません。マップ、つまり、 void の数に依存しない出力特徴マップのサイズ

2 次元信号の場合:

出力特徴マップのサイズに影響する要因には、入力特徴マップのサイズ (H、W)、コンボリューション カーネルのサイズ (FH、FW)、フィリング P、およびステップ サイズ Sが含まれます。

出力特徴マップ サイズ ( OH,OW )を設定します。

 ホール畳み込みの有無は出力特徴マップのサイズに影響を与えません。つまり、出力特徴マップのサイズはホールの数とは関係ありません

2. 拡張コンボリューション機能1:コンボリューションカーネルの受容野を拡大

通常の畳み込み 3×3

 拡張コンボリューション 3×3

上の 2 つの図からわかるように、コンボリューション カーネルは変化しませんが、その受容野は大幅に変化します。

2.1 展開処理後の等価コンボリューションカーネル

カーネル サイズ = 3、ストライド = 1 拡張率はそれぞれ1、2

展開のコンボリューション カーネル サイズ =  k 展開率/穴の数の拡張率 =  d  およびその 等価カーネル サイズ =  k'とします。 

k' = k + (k - 1) * (d - 1) ---------------------------- (計算式)

K' = 3 + (3 - 1) * (2 - 1) = 5-----------------------------(図b)の計算

ここで説明しておく必要があるのは、畳み込みカーネルの数は拡張処理後も変化しないこと、つまり元は 3×3 であり、拡張後も 3×3 のままであるということです。なぜ等価物があるのか​​というと、拡張はまだ 3×3 ですが、拡張により、受容野を計算する際に受容野は 5×5 のコンボリューション カーネルと等価になります。後の受容野の計算を容易にするために、ここでは等価畳み込みカーネルを提案します。

2.2 受容野の計算

             カーネル サイズ = 3、ストライド = 1 拡張率1、2、および 4の 3 つの異なる拡張畳み込み

 注: RF2 は図 (a) に対応し、RF3 は図 (b) に対応し、RF4 は図 (c) に対応します。

        RF2 を計算するとき、数値 1 はデフォルトの元の画像の受容野が 1 です。

グラフ abc の全体的な計算プロセスは次のとおりです。

 4. 拡張畳み込みの問題

4.1 グリッド効果

以下の図に示すように、多層拡張コンボリューションを設定します。

各層の処理は以下の通りです。 (下から上へ(図4.4から図4.2へ))

 図4.2 レイヤ4

 図 4.3 レイヤ 3

  図4.4 レイヤ2

 #数字の付いたブロック (ゼロ以外のブロック) は、このピクセル ブロックが拡張畳み込み後に使用されることを示します

#ブロック内の数字は、一連の拡張畳み込み後のブロックの使用の累積数を示します。(計算は簡単です、自分で描いてみればわかります)

3 回の拡張畳み込みを行うと図 4.2 の右側が得られ、多層拡張畳み込みの拡大率が同じ (この例ではどちらも 2) の場合、次のような画素ブロックが存在することがわかります。受容野での使用回数が0回、​​つまり使用される元のデータが不連続であるため、情報が失われます。

4.2 長距離の情報は意味を持たない場合がある

拡張畳み込みは受容野を拡張するため、遠距離情報を取得できます (これは画像内の大きなターゲットの分析に有益です)。ただし、一部の遠距離情報は現在の点とはまったく無関係であり、一貫性に影響します。データの量(小さなターゲットはあまり友好的ではないため)。

5、多層拡張畳み込みデザインルール HDC (4 番目の問題を解決するため)

参考文章:Understanding Convolution for Semantic Segmentation

1. 2 番目の層の 2 つの非ゼロ要素間の最大距離は、この層の畳み込みカーネルのサイズ以下です。

2.拡張係数を ZigZag に設定します。[1,2,3,1,2,3,1,2,3]

3.展開係数の公約数は1を超えることはできません[2,4,8]理不尽

 HDC の目標: 一連の拡張畳み込みの後、基礎となる特徴マップが完全にカバーされ、この領域に穴や欠落したエッジが存在しないこと

 5.1 最初のルールを理解する

2 番目の層の 2 つの非ゼロ要素間の最大距離は、この層のコンボリューション カーネルのサイズ以下です。

 

この Mi はどのようにして出てきたのですか(メッセージ 63 件) セマンティック セグメンテーション -- セマンティック セグメンテーションの畳み込みを理解する_DFann のブログ - CSDN ブログ

このブログで、著者はセマンティック セグメンテーションの畳み込みについての記事について質問しました。

ここに画像の説明を挿入

 最初のルール①の例:

 Mi は i 番目の層の 2 つの非ゼロ要素間の最大距離、ri は i 番目の層の拡大率です

最後の層はMi=riであると上で説明しましたので計算するとM3=r3=5、r2=2となり1となり他は同様です。

M2 = 2、2 番目の層の 2 つの非ゼロ要素間の最大距離がこの層の畳み込みカーネルのサイズ以下であることを満たします。

 最初のルールの例②:

 

 (畳み込みカーネルはすべて 3×3、左側の拡張率は [1,2,5]、右側の拡張率は [1,2,9] です。実行するコードについては付録を参照してください)この写真の

ルール 1 により、インフレ率は 1 から開始する必要があると結論付けることもできます。

高レベルの特徴マップの各ピクセルが下部の特徴マップの受容野のすべてのピクセルを使用できることを望みます。その場合、M は 1 に等しくなります。M=1 は、非ゼロ要素が (ギャップなしで) 隣接していることを意味し、M は 1 に等しいため、r は「強制的に」 1 になります。

 5.2 2 番目のルールを理解する

拡大率を鋸歯状に設定 (1、2、3、1、2、3)

私たちのネットワークでは、膨張率の分布は鋸歯状波のようなヒューリスティックに従います。つまり、多くのレイヤーがグループ化されて膨張率が増加する波の「立ち上がりエッジ」を形成し、次のグループが同じパターンを繰り返します。たとえば、膨張率 r = 2 のすべてのレイヤーについて、3 つのレイヤーをグループとして取得し、それらの膨張率をそれぞれ 1、2、および 3 に変更します。これにより、最上層は元の構成と同じ領域にある広範囲のピクセルからの情報にアクセスできるようになります。このプロセスはすべての層で繰り返されるため、最上層の受容野は変化しません。           

                         --------Understanding Convolution for Semantic Segmentation原文翻訳

 5.3 3 番目のルールを理解する

展開係数の公約数は1より大きくすることはできません

公約数が 1 より大きい場合でも、グリッド効果の問題は発生します。

上の図は、拡張率が [2,4,8] で、グリッド効果が表示されていることを示しています (コードについては付録を参照してください)。

要約すると、多層展開畳み込みの展開率の設計仕様は次のようになります。

1. 2 番目の層の 2 つの非ゼロ要素間の最大距離は、この層の畳み込みカーネルのサイズ以下です。

2.拡張係数を ZigZag に設定します。[1,2,3,1,2,3,1,2,3]

3.展開係数の公約数は1を超えることはできません[2,4,8]理不尽

5.4 HDC原理とアプリケーションでの画像分割効果を満たす伸長率設定

(拡張率が HDC 設計を満たしていない) 

(HDC設計の拡張率に対応するため)

(通常の標準的な多層畳み込み) 

(HDC 原則を満たす画像セグメンテーション効果と満たさない画像セグメンテーション効果)

付録 1: 拡張畳み込みコード

1次元の拡張畳み込み:

#一维膨胀卷积
conv1 = torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True)

2次元の拡張畳み込み:

#二维膨胀卷积
conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)

dilation = 1 が一般的なコンボリューションの場合、dilation > 1 は拡張コンボリューションです

注: 拡張畳み込み中のパディングは、拡張率拡張の値に関連します。

1次元の場合:

N はバッチ サイズ、C は複数のチャネルを表し、L は信号シーケンスの長さです。入力サイズと出力サイズを同じにしたい場合は、次の式でパディングを反転できます。

 二次元では:

  • o = output=32
  • i = input =32
  • p = padding=?  #未知量,需求
  • k = kernel_size=3
  • s = stride=1
  • d = dilation=2

 上記の特徴マップ計算式から、入力サイズと出力サイズを確実に一致させたい場合は、上記の式を使用して p を逆解きます。

既知の量を方程式に代入すると、次のようになります。

32=(32+2xパディング-2x(3-1)-1)/1+1

方程式を解くと次のようになります。

パディング=2

付録 2: HDC は拡張畳み込みコードを描画します

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

def dilated_conv_one_pixel(center: (int, int),
                           feature_map: np.ndarray,
                           k: int = 3,
                           r: int = 1,
                           v: int = 1):
    """
    膨胀卷积核中心在指定坐标center处时,统计哪些像素被利用到,
    并在利用到的像素位置处加上增量v
    Args:
        center: 膨胀卷积核中心的坐标
        feature_map: 记录每个像素使用次数的特征图
        k: 膨胀卷积核的kernel大小
        r: 膨胀卷积的dilation rate
        v: 使用次数增量
    """
    assert divmod(3, 2)[1] == 1

    left_top = (center[0] - ((k - 1) // 2) * r, center[1] - ((k - 1) // 2) * r)
    for i in range(k):
        for j in range(k):
            feature_map[left_top[1] + i * r][left_top[0] + j * r] += v

def dilated_conv_all_map(dilated_map: np.ndarray,
                         k: int = 3,
                         r: int = 1):
    """
    根据输出特征矩阵中哪些像素被使用以及使用次数,
    配合膨胀卷积k和r计算输入特征矩阵哪些像素被使用以及使用次数
    Args:
        dilated_map: 记录输出特征矩阵中每个像素被使用次数的特征图
        k: 膨胀卷积核的kernel大小
        r: 膨胀卷积的dilation rate
    """
    new_map = np.zeros_like(dilated_map)
    for i in range(dilated_map.shape[0]):
        for j in range(dilated_map.shape[1]):
            if dilated_map[i][j] > 0:
                dilated_conv_one_pixel((j, i), new_map, k=k, r=r, v=dilated_map[i][j])

    return new_map

def plot_map(matrix: np.ndarray):
    plt.figure()

    c_list = ['white', 'blue', 'red']
    new_cmp = LinearSegmentedColormap.from_list('chaos', c_list)
    plt.imshow(matrix, cmap=new_cmp)

    ax = plt.gca()
    ax.set_xticks(np.arange(-0.5, matrix.shape[1], 1), minor=True)
    ax.set_yticks(np.arange(-0.5, matrix.shape[0], 1), minor=True)

    plt.colorbar()

    thresh = 5
    for x in range(matrix.shape[1]):
        for y in range(matrix.shape[0]):

            info = int(matrix[y, x])
            ax.text(x, y, info,
                    verticalalignment='center',
                    horizontalalignment='center',
                    color="white" if info > thresh else "black")
    ax.grid(which='minor', color='black', linestyle='-', linewidth=1.5)
    plt.show()
    plt.close()

def main():

    dilated_rates = [2,4,8]

    size = 30
    m = np.zeros(shape=(size, size), dtype=np.int32)
    center = size // 2
    m[center][center] = 1

    for index, dilated_r in enumerate(dilated_rates[::-1]):
        new_map = dilated_conv_all_map(m, r=dilated_r)
        m = new_map
    print(m)
    plot_map(m)

if __name__ == '__main__':
    main()

おすすめ

転載: blog.csdn.net/qq_46073783/article/details/128383220