CNN による画像分類で使われる前処理・テスト時処理まとめ

とりあえず ImageNet 系の論文で、目に入ったものから順々にまとめていきます。情報・ツッコミ歓迎。

前処理・Data Augmentation

Mean Subtraction

入力画像から平均を引く。[103.939, 116.779, 123.68] を各ピクセルから引く。VGG はこれ。

Per-pixel Mean Subtraction

入力画像から平均を引く。ピクセル・チャンネルごとに計算された平均を引く。即ち、224x224x3 個の値について個別に平均を計算し用いる。AlexNet 論文から使われており、ResNet もこれ

Random Crop

256x256 ピクセルに画像をリサイズし、そこから 224x224 のパッチをランダムに取り出す。AlexNet 論文で使われていた。ちなみに Chainer の ImageNet サンプルはこれと Horizontal Flip をやっている(これしかやっていないので相応の精度しか出ない)。

Horizontal Flip

画像をランダムにフリップする。ImageNet では縦方向はなく水平方向の flip のみが使われるようであり、AlexNet 論文以降必ず使われているようだ。

Scale Augmentation

まず画像をリサイズする。[256, 480] からランダムに短辺の長さを選ぶ。次に、224x224 のパッチをそこからランダムサンプルする。

VGG 論文から使われており、ResNet 本家論文でも使われる。

Aspect Ratio Augmentation

上の Scale Augmentation に加え画像のアスペクト比を [¾, 4/3] で変換する・・・ぽい?(論文の記述が短くわかりにくい)

GoogLeNet の論文で使われている。FAIR の ResNet 再現記事でも使われており、本家から 1.2% の精度向上に寄与したらしい。

Color Augmentation

AlexNet 論文で行われた方法は以下である。各ピクセルの RGB を 3 次元のベクトルの集合だと考え PCA をかける。ガウス分布でノイズを生成し、固有ベクトル方向にノイズを加える。乱数は各ピクセルではなくパッチ全体に対して共通。論文によると AlexNet の精度への寄与は 1% 程度。ResNet 本家論文でも使われている。PCA した結果はここにあったり。

“Some Improvements on Deep Convolutional Neural Network Based Image Classification” 論文で行われた方法は以下である。contrast, brightness, color を、[0.5, 1.5] の間でランダムに変更する。変更の順番もランダムに選択する。(ご丁寧に、Python image library (PIL) を使ったと書いてある。)その後で、AlexNet 論文と同様の操作を行う。FAIR の ResNet 再現記事ではこれを利用したと書いてあったが、精度への寄与はとても小さかったらしい。

テスト時

Ensemble

複数のモデルを独立に学習し、それらの予測を平均する。

GoogLeNet 論文では、ネットワークは同じだが入力の処理法を変えた 7 つのモデルをアンサンブルしているらしい。GoogLeNet の論文は全体的に詳細が濁されているのでよくわからない。single crop だと top-5 error が 2% 弱程度向上。

ResNet 本家論文では、34B, 34C, 50, 101, 152×2 の 6 モデルをアンサンブルしている。fully-convolutional-form で top-5 error に 1% 弱程度向上。

10-crop Testing

テスト画像 1 つから data augmentation と類似した手順で 10 個のパッチを切り出し、それぞれに対する予測を平均して答える。

AlexNet 論文では、(4 スミ+中央)×(反転の有無)で 10 個のパッチを切り出している。GoogLeNet は 144 パッチも試してる。

GoogLeNet 論文では、crop 数の精度への影響が載っている。top-5 error で、10 crops で約 1% 弱向上、144 crops で 2% 強向上(下表は GoogLeNet 論文より引用)。

f:id:iwiwi:20161231213228p:plain

Fully-convolutional-form Testing

まず、全結合層たちを畳み込み層とみなす。例えば、直前の画像サイズが s×s であれば、最初の全結合層は s×s → 1×1 の畳み込み層であるとみなす。すると、ネットワークは fully convolutional (全レイヤーが畳み込み)となる。fully convolutional なネットワークの利点は、入力の画像サイズが変化しても適用することができることである(ただし、出力サイズも変化する)。

テスト画像をリサイズする。この時の画像サイズは、学習で使っている画像サイズと一致しているとは限らないし、正方形とも限らない。例えば、短辺を 480 にする。ネットワークをこの画像に適用する。出力を average pooling してそれを予測とする。

さらに、テスト画像のサイズを複数試し、その結果の平均を用いる。例えば、ResNet 本家論文では短辺を 224, 256, 384, 480, 640 になるようにリサイズしている。また、horizontal flip も試して平均を取る。

VGG から使われている。ResNet 本家論文を見るところ、10-crop Testing と比べて、大体 2% 程度精度に寄与している。

Chainer で全結合層を畳み込み層にするコードの例を mitmul さんから貰ったので貼っておきます。

def linear2conv(model, name, feature_size=1):
    """Convert Linear layer to 1x1 Convolution Layer
    args:
        model (chainer.Chain): The input model
        name (str): Name of a Linear link that will be converted to 1x1 conv
            ex. '/predictor/trunk/fc6'
        feature_size (int): The feature map size of convolution layer
    """
    target = model
    lnames = [n for n in name.split('/') if len(n) > 0]
    for l in lnames[:-1]:
        target = target.__dict__[l]
    t = target.__dict__[lnames[-1]]
    assert ('Linear' in str(t.__class__))
    out_dim, in_dim = t.W.data.shape
    in_dim = in_dim // (feature_size ** 2)
    conv = L.Convolution2D(in_dim, out_dim, feature_size)
    W = t.W.data.reshape((out_dim, in_dim, feature_size, feature_size))
    conv.W.data, conv.b.data = W, t.b.data
    target.__dict__[lnames[-1]] = conv
    return model

参考文献

謝辞

  • 宮戸さん
  • mitmul さん