機械学習ノート-ディープラーニングのための前処理と画像ホワイトニング

I.概要

        データ前処理の基本から深層学習で使用される手法まで、すべてをよりよく理解するために、コード(Python / Numpyなど)でコーディングします。

        分散や共分散行列など、データサイエンスと機械学習/深層学習の基本的でありながら非常に有用な概念から始めて、画像をニューラルネットワークにフィードするためのいくつかの前処理手法に進みます。特定のコードを使用して、各方程式の機能を理解してください。

        生データのすべての変換を前処理してから、機械学習または深層学習アルゴリズムにフィードします。たとえば、生の画像で畳み込みニューラルネットワークをトレーニングすると、分類のパフォーマンスが低下する可能性があります。前処理は、トレーニングを高速化するためにも重要です(たとえば、センタリングやスケーリングの手法など)。

2.分散と共分散

        変数の分散は、値がどの程度広く分布しているかを表します。共分散は、2つの変数間の依存度の尺度です。正の共分散は、2番目の変数の値も大きい場合に、最初の変数の値が大きいことを意味します。負の共分散とは、その逆を意味します。ある変数の大きな値は、別の変数の小さな値に関連付けられます。共分散値は変数のスケールに依存するため、分析が困難です。解釈しやすい相関係数を使用できます。これは、正規化された共分散です。

正の共分散は、ある変数の大きな値が別の変数の大きな値に関連付けられていることを意味します(左)。負の共分散とは、ある変数の大きな値が別の変数の小さな値に関連付けられていることを意味します(右)。

        共分散行列は、変数について多くのことを伝えることができる一連のベクトルの分散と共分散を集約する行列です。対角線は、各ベクトルの分散に対応しています。

行列とその共分散行列。対角線は、各列ベクトルの分散に対応しています。

         分散の計算式は次のとおりです。

        V(\ boldsymbol {X})= \ frac {1} {n} \ sum_ {i = 1} ^ {n}(x_i- \ bar {x})^ 2

        ここで、nはベクトルの長さであり\ bar {x}、ベクトルの平均です。たとえば、Aの最初の列ベクトルの分散は次のとおりです。

        V(\ boldsymbol {A} _ {:, 1})= \ frac {(1-3)^ 2 +(5-3)^ 2 +(3-3)^ 2} {3} = 2.67

        これは、共分散行列の最初のセルです。対角線上の2番目の要素は、Aの2番目の列ベクトルの分散に対応します。

        注:行列Aから抽出されたベクトルは、Aの列に対応します。

        他のセルは、Aからの2つの列ベクトル間の共分散に対応します。たとえば、最初の列と3番目の列の間の共分散は、共分散行列、つまり列1と行3(または列3と行1)にあります。

共分散行列の位置。列は最初の変数に対応し、行は2番目の変数に対応します(またはその逆)。Aの1番目と3番目の列ベクトル間の共分散は、列1と行3の要素です(またはその逆=同じ値)。

        Aの1列目と3列目のベクトル間の共分散が-2.67に等しいことを確認しましょう。2つの変数XとYの間の共分散の式は次のとおりです。

        cov(\ boldsymbol {X}、\ boldsymbol {Y})= \ frac {1} {n} \ sum_ {i = 1} ^ {n}(x_i- \ bar {x})(y_i- \ bar {y })

        変数XとYは、前の例の1番目と3番目の列ベクトルです。この式を分割してみましょう:

        1.(x_1- \ bar {x}) 合計記号は、反復する必要のあるベクトルの要素です。最初の要素(i = 1)から始めて、Xの最初の要素からベクトルXの平均を引いたものを計算します。

        2.(x_1- \ bar {x})(y_1- \ bar {y})結果にYの最初の要素からベクトルYの平均を引いたものを掛けます。

        3.\ sum_ {i = 1} ^ {n}(x_i- \ bar {x})(y_i- \ bar {y})ベクトルの要素ごとにこのプロセスを繰り返し、すべての結果の合計を計算します。

        4.\ frac {1} {n} \ sum_ {i = 1} ^ {n}(x_i- \ bar {x})(y_i- \ bar {y})ベクトルの要素数で割ります。

1、例1

        次の行列\ boldsymbol {A} = \ begin {bmatrix} 1&3&5 \\ 5&4&1 \\ 3&8&6 \ end {bmatrix}を使用して、最初の列ベクトルと3番目の列ベクトルの間の共分散を計算します。

        \ boldsymbol {X} = \ begin {bmatrix} 1 \\ 5 \\ 3 \ end {bmatrix}、、、、、そう\ boldsymbol {Y} = \ begin {bmatrix} 5 \\ 1 \\ 6 \ end {bmatrix}_ \ boldsymbol {\ bar {x}} = 3_\ boldsymbol {\ bar {y}} = 4n = 3

        (X、Y)= \ frac {(1-3)(5-4)+(5-3)(1-4)+(3-3)(6-4){{3} = \ frac { -8} {3} =-2.67

        つまり、共分散行列の値です。

        Numpyを使用すると、関数np.covを使用して共分散行列を計算できます。Numpyで列をベクトルとして使用する場合は、パラメーターrowvar=Falseを使用する必要があることに注意してください。また、bias = Trueを使用すると、n-1ではなくnで除算できます。

A = np.array([[1, 3, 5], [5, 4, 1], [3, 8, 6]])
np.cov(A, rowvar=False, bias=True)

        計算結果

array([[ 2.66666667,  0.66666667, -2.66666667],
       [ 0.66666667,  4.66666667,  2.33333333],
       [-2.66666667,  2.33333333,  4.66666667]])

2、例2

        ドット積を使用して共分散行列を見つけることにより、Aの共分散行列を計算する別の方法があります。Aを0(ベクトルの平均からベクトルの各要素を引いたもの)の中心に置き、それをそれ自体の転置で乗算し、観測数で除算することができます。実装から始めましょう。次に、前の方程式との関係を理解し​​ようとします。

def calculateCovariance(X):
    meanX = np.mean(X, axis = 0)
    lenX = X.shape[0]
    X = X - meanX
    covariance = X.T.dot(X)/lenX
    return covariance

        行列Aで計算してみましょう。

calculateCovariance(A)

        計算結果

array([[ 2.66666667,  0.66666667, -2.66666667],
       [ 0.66666667,  4.66666667,  2.33333333],
       [-2.66666667,  2.33333333,  4.66666667]])

        結果は例1と同じです。

        2つのベクトル間の内積は、次のように表すことができます。\ boldsymbol {X ^ \ text {T} Y} = \ sum_ {i = 1} ^ {n}(x_i)(y_i)

内積は、ベクトルの各要素の積の合計に対応します。

         次に、ベクトル内の要素の数nで除算します。\ frac {1} {n} \ boldsymbol {X ^ \ text {T} Y} = \ frac {1} {n} \ sum_ {i = 1} ^ {n}(x_i)(y_i)

        これは、上記で見た共分散式と非常によく似ていることがわかります。

        cov(\ boldsymbol {X}、\ boldsymbol {Y})= \ frac {1} {n} \ sum_ {i = 1} ^ {n}(x_i- \ bar {x})(y_i- \ bar {y })

        唯一の違いは、共分散式では、平均からベクトルの各要素を減算することです。そのため、内積を行う前にデータを中央に配置する必要があります。

        ここで、行列Aがある場合、Aとその転置の間の内積は、新しい行列になります。

        

        これが共分散行列です!

 3.データと共分散行列の視覚化

        共分散行列とその目的をより深く理解するために、2Dデータでそれを視覚化する関数を作成します。共分散行列とデータの関係を確認できます。

        上で見たように、この関数は共分散行列を計算します。2つのサブプロットが作成されます。1つは共分散行列用で、もう1つはデータ用です。Seabornのheatmap関数は、カラーグラデーションを作成するために使用されます。小さい値は薄緑色に、大きい値は濃い青になります。データは散布図として表されます。パレットの色の1つを選択しますが、他の色を使用することもできます。

def plotDataAndCov(data):
    ACov = np.cov(data, rowvar=False, bias=True)
    print 'Covariance matrix:\n', ACov

    fig, ax = plt.subplots(nrows=1, ncols=2)
    fig.set_size_inches(10, 10)

    ax0 = plt.subplot(2, 2, 1)

    # Choosing the colors
    cmap = sns.color_palette("GnBu", 10)
    sns.heatmap(ACov, cmap=cmap, vmin=0)

    ax1 = plt.subplot(2, 2, 2)

    # data can include the colors
    if data.shape[1]==3:
        c=data[:,2]
    else:
        c="#0A98BE"
    ax1.scatter(data[:,0], data[:,1], c=c, s=40)

    # Remove the top and right axes from the data plot
    ax1.spines['right'].set_visible(False)
    ax1.spines['top'].set_visible(False)

        プロット関数ができたので、ランダムデータを生成して、共分散行列が何を教えてくれるかを視覚化します。Numpy関数np.random.normal()を使用して、正規分布からいくつかのデータを抽出します。

1.無関係なデータ

        この関数には、入力として分布の平均、標準偏差、および観測数が必要です。標準偏差が1の300個の観測値を持つ2つの確率変数を作成します。1つ目は平均1で、2つ目は平均2です。正規分布から300個の観測値を2回サンプリングすると、2つのベクトルは相関しません。

np.random.seed(1234)
a1 = np.random.normal(2, 1, 300)
a2 = np.random.normal(1, 1, 300)
A = np.array([a1, a2]).T
A.shape

        注1.T :元の形状が(2、300)であり、観測数を行にするため(したがって、形状(300、2))、データを転置します。

        注2np.random.seed :再現性のために同じ乱数と関数を使用します。

        データがどのように見えるかを確認しましょう:

array([[ 2.47143516,  1.52704645],
       [ 0.80902431,  1.7111124 ],
       [ 3.43270697,  0.78245452],
       [ 1.6873481 ,  3.63779121],
       [ 1.27941127, -0.74213763],
       [ 2.88716294,  0.90556519],
       [ 2.85958841,  2.43118375],
       [ 1.3634765 ,  1.59275845],
       [ 2.01569637,  1.1702969 ],
       [-0.24268495, -0.75170595]])

        2つの列ベクトルがあります。

        これで、分布が正規分布であるかどうかを確認できます。

sns.distplot(A[:,0], color="#53BB04")
sns.distplot(A[:,1], color="#0A98BE")
plt.show()
plt.close()

        分布の標準偏差は同じですが、平均が異なります(1と2)。だから、これはまさに私たちが求めていたものです!

        これで、データセットとその共分散行列を関数でプロットできます。

plotDataAndCov(A)
plt.show()
plt.close()

        結果は次のとおりです。

Covariance matrix:
[[ 0.95171641 -0.0447816 ]
 [-0.0447816   0.87959853]]
散布図で、これらの2つの次元が無相関であることがわかります。一方の次元に平均1があり、もう一方の次元に平均2があることに注意してください。また、共分散行列は、各変数の分散が非常に大きい(約1)のに対し、列1と2の共分散は非常に小さい(約0)ことを示しています。2つのベクトルが独立していることを確認したので、これは一貫しています(逆は必ずしも真実ではありません。共分散が0の場合、独立性は保証されません。

 2.関連データ

        次に、ある列を別の列から指定して、依存データを作成しましょう。

np.random.seed(1234)
b1 =  np.random.normal(3, 1, 300)
b2 = b1 + np.random.normal(7, 1, 300)/2.
B = np.array([b1, b2]).T
plotDataAndCov(B)
plt.show()
plt.close()

        データは次のように生成されます

Covariance matrix:
[[ 0.95171641  0.92932561]
 [ 0.92932561  1.12683445]]
2つの次元間の相関関係は、散布図に表示されます。線を引いて、xからyを予測するために使用でき、その逆も可能であることがわかります。共分散行列は対角ではありません(対角の外側にゼロ以外のセルがあります)。これは、次元間の共分散がゼロではないことを意味します。

4.前処理

1.平均正規化

        平均の正規化は、各観測値から平均を削除するだけです。

        \ boldsymbol {X'} = \ boldsymbol {X}-\ bar {x}、ここで、X'は正規化されたデータセット、Xは元のデータセット、\ bar {x} はXの平均です。

        データを0を中心に配置する効果があります。関数center()の実装を作成します。

def center(X):
    newX = X - np.mean(X, axis = 0)
    return newX

        上で作成した行列Bを試してみましょう。

BCentered = center(B)

print 'Before:\n\n'

plotDataAndCov(B)
plt.show()
plt.close()

print 'After:\n\n'

plotDataAndCov(BCentered)
plt.show()
plt.close()

        結果は次のとおりです。

Before:

Covariance matrix:
[[ 0.95171641  0.92932561]
 [ 0.92932561  1.12683445]]

After:

Covariance matrix:
[[ 0.95171641  0.92932561]
 [ 0.92932561  1.12683445]]
最初のプロットは元のデータBを再び示し、2番目のプロットは中央のデータを示しています(比較のためにx、y座標を見てください)。

 2.標準化

        正規化は、すべての機能を同じスケールに配置するために使用されます。これを行う方法は、ゼロ中心の各次元をその標準偏差で除算することです。\ boldsymbol {X'} = \ frac {\ boldsymbol {X}-\ bar {x}} {\ sigma _ {\ boldsymbol {X}}}ここで、X'は正規化されたデータセット、Xは元のデータセット、x¯はXの平均、σXはXの標準偏差です。

def standardize(X):
    newX = center(X)/np.std(X, axis = 0)
    return newX

        スケールが異なる別のデータセットを作成して、機能するかどうかを確認してみましょう。

np.random.seed(1234)
c1 =  np.random.normal(3, 1, 300)
c2 = c1 + np.random.normal(7, 5, 300)/2.
C = np.array([c1, c2]).T

plotDataAndCov(C)
plt.xlim(0, 15)
plt.ylim(0, 15)
plt.show()
plt.close()

        結果は次のとおりです。

Covariance matrix:
[[ 0.95171641  0.83976242]
 [ 0.83976242  6.22529922]]

         xスケールとyスケールが異なることがわかります。また、スケールの違いにより、相関が小さく見えることにも注意してください。それを正規化しましょう:

CStandardized = standardize(C)

plotDataAndCov(CStandardized)
plt.show()
plt.close()

        結果は次のとおりです。

Covariance matrix:
[[ 1.          0.34500274]
 [ 0.34500274  1.        ]]

         これで、スケールが同じであり、データセットが両方の軸に従ってゼロを中心としていることがわかります。ここで、共分散行列を見てください。各座標(左上のセルと右下のセル)の分散が1に等しいことがわかります。この新しい共分散行列は、実際には相関行列です。2つの変数(c1とc2)間のピアソン相関係数は0.54220151です。

3.アルビノ

        ホワイトニングまたは球面データは、共分散行列、単位行列(対角線上に1、他のセルに0、単位行列の詳細)を取得するために何らかの方法で変換することを意味します。これをホワイトノイズ基準ホワイトノイズと呼びます。

        ホワイトニングを実行するには、次の手順が必要です。

1- 零中心数据
2- 去相关数据
3- 重新调整数据

        ここでも、上記の行列Cを使用します。

(1)ゼロセンタリング

CCentered = center(C)

plotDataAndCov(CCentered)
plt.show()
plt.close()
Covariance matrix:
[[ 0.95171641  0.83976242]
 [ 0.83976242  6.22529922]]

 (2)デコレート

        データを非相関化する必要があります。直感的には、相関関係がなくなるまでデータをローテーションします。下記参照:

左のグラフは関連データを示しています。たとえば、x値が大きいデータポイントを取得する場合、yも大きくなる可能性があります。ここで、すべてのデータポイントを取得し、回転します(おそらく、反時計回りに約45度)。新しいデータ(右側にプロット)は、もはや関連性がありません。

         問題は、無相関データの正しいローテーションをどのように見つけることができるかということです。実際、これは共分散行列の固有ベクトルが行うこととまったく同じです。これらは、データが最も広がる方向を示します。

共分散行列の固有ベクトルは、分散を最大化する方向を示します。緑の線の方向は、分散が最大になる場所です。この線に投影された最小点と最大点を見てください。広がりは巨大です。これをオレンジ色の線の投影と比較してください。広がりは非常に小さいです。

         したがって、特徴ベクトルに基づいてデータを射影することにより、データを非相関化できます。これには、目的の回転を適用し、寸法間の相関関係を削除する効果があります。手順は次のとおりです。

1-计算协方差矩阵
2-计算协方差矩阵的特征向量
3-将特征向量矩阵应用于数据(这将应用旋转)

        関数を作成しましょう:

def decorrelate(X):
    XCentered = center(X)
    cov = XCentered.T.dot(XCentered)/float(XCentered.shape[0])
    # Calculate the eigenvalues and eigenvectors of the covariance matrix
    eigVals, eigVecs = np.linalg.eig(cov)
    # Apply the eigenvectors to X
    decorrelated = X.dot(eigVecs)
    return decorrelated

        ゼロ中心の行列Cを非相関化して、実際の動作を確認してみましょう。

plotDataAndCov(C)
plt.show()
plt.close()

CDecorrelated = decorrelate(C)
plotDataAndCov(CDecorrelated)
plt.xlim(-5,5)
plt.ylim(-5,5)
plt.show()
plt.close()
Covariance matrix:
[[ 0.95171641  0.83976242]
 [ 0.83976242  6.22529922]]
タイトル
Covariance matrix:
[[  5.96126981e-01  -1.48029737e-16]
 [ -1.48029737e-16   3.15205774e+00]]

        相関がもはや存在しないことがわかり、共分散行列(現在は対角行列)は、2つの次元間の共分散が0に等しいことを確認します。

(3)データを再スケーリングします

        次のステップは、無相関行列をスケーリングして、単位行列(対角線上の行列と他のセル上のゼロ)に対応する共分散行列を取得することです。これを行うには、各次元を対応する固有値の平方根で割ることにより、非相関データをスケーリングします。

def whiten(X):
    XCentered = center(X)
    cov = XCentered.T.dot(XCentered)/float(XCentered.shape[0])
    # Calculate the eigenvalues and eigenvectors of the covariance matrix
    eigVals, eigVecs = np.linalg.eig(cov)
    # Apply the eigenvectors to X
    decorrelated = X.dot(eigVecs)
    # Rescale the decorrelated data
    whitened = decorrelated / np.sqrt(eigVals + 1e-5)
    return whitened

10 ^ {-5}注: 0による除算を避けるため        に、最小値(ここ)を追加します。

CWhitened = whiten(C)

plotDataAndCov(CWhitened)
plt.xlim(-5,5)
plt.ylim(-5,5)
plt.show()
plt.close()
Covariance matrix:
[[  9.99983225e-01  -1.06581410e-16]
 [ -1.06581410e-16   9.99996827e-01]]

5.画像の美白

        前処理された画像データセットにホワイトニングを適用する方法を見てみましょう。このために、プロセスの詳細を提供するPal&Sudeep(2016)の論文を使用します。この前処理手法は、ゼロコンポーネント分析(ZCA)と呼ばれます。

        論文をチェックしてください、しかしこれは彼らが得たものです:

CIFAR10データセットからの白色化された画像。Pal&Sudeep(2016)の論文の結果。元の画像(左)とZCA後の画像(右)が表示されます。

         まず、CIFARデータセットをロードします。このデータセットはKerasから入手できます。

from keras.datasets import cifar10
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
X_train.shape

        CIFAR10データセットのトレーニングセットには、50,000枚の画像が含まれています。X_trainの形状は(50000、32、32、3)です。各画像は32x32ピクセルで、各ピクセルには3つの次元(R、G、B)が含まれています。各値は、0〜255の対応する色の明るさです。

        まず、画像のサブセット、たとえば1000のみを選択します。

X = X_train[:1000]
print X.shape

        次に、配列の形状を変更して、行ごとに1つの画像を持つフラットな画像データを作成します。32×32×3=3072であるため、各画像は(1、3072)になります。したがって、すべての画像を含む配列は(1000、3072)になります。

X = X.reshape(X.shape[0], X.shape[1]*X.shape[2]*X.shape[3])
print X.shape

        次のステップは、画像を表示できるようにすることです。Matplotlibの関数imshow()を使用して、画像を表示できます。形の画像(MxNx3)が必要なので、画像を形を変えて形から視覚化できる関数を作成しましょう(1、3072)。

def plotImage(X):
    plt.figure(figsize=(1.5, 1.5))
    plt.imshow(X.reshape(32,32,3))
    plt.show()
    plt.close()

        たとえば、ロードした画像を描画してみましょう。

plotImage(X[12, :])

         これで、画像を白くすることができます。

        1.最初のステップは、画像を再スケーリングして、255(ピクセル単位の最大値)で割って範囲[0、1]を取得することです。

        次の式を使用します\ frac {data --min(data)} {max(data)--min(data)}。最小値は0なので、次のようになります。\ frac {data} {max(data)} = \ frac {data} {255}

X_norm = X / 255.
print 'X.min()', X_norm.min()
print 'X.max()', X_norm.max()
X.min() 0.0
X.max() 1.0

        2.すべての画像から平均値を引きます。

        1つのアプローチは、各画像を取得し、各ピクセルからその画像の平均を削除することです(Jarrett et al。、2009)。このプロセスの背後にある直感は、各画像のピクセルを0を中心に配置することです。

        もう1つの方法は、画像ごとに3072ピクセル(R、G、Bの場合は32 x 32ピクセル)を取得し、すべての画像のそのピクセルの平均を差し引くことです。これは、ピクセルあたりの平均減算と呼ばれます。今回は、すべての画像に応じて、各ピクセルが0を中心とします。画像をネットワークにフィードすると、各ピクセルは異なる特徴として扱われます。ピクセルごとの平均減算では、各特徴(ピクセル)を0を中心に配置します。これはそれに対処するための一般的な方法です。

        ここで、1000枚の画像からピクセルごとの平均減算を実行します。私たちのデータは、これらの次元(画像、ピクセル)に沿って編成されています。1000枚の画像があるため、は(1000、3072)、32×32×3=3072ピクセルです。したがって、各ピクセルの平均値は、最初の軸から取得できます。

X_norm.mean(axis=0).shape
X_norm = X_norm - X_norm.mean(axis=0)
X_norm.mean(axis=0)

        ここで、ゼロ中心のデータの共分散行列を計算します。上で見たように、np.cov()Numpyの関数を使用して計算できます。

        行列から2つの可能な相関行列Xを計算できます。行間または列間の相関です。この場合、行列の各行Xは画像であるため、行列の行は観測値に対応し、行列の列は特徴(画像ピクセル)に対応します。ホワイトニングの目的はこれらの相関関係を削除して、アルゴリズムが高次の関係に焦点を合わせることができるようにすることであるため、ピクセル間の相関関係を計算する必要があります

        これを行うには、パラメーターNumpyを設定します rowvar=False。列を変数(または機能)として使用し、行を観測値として使用します。

cov = np.cov(X_norm, rowvar=False)

        共分散行列の形状は、ピクセルの各ペア間の相関を表すために3072 x 3072である必要があります(3072ピクセルあります)。

        共分散行列の特異値とベクトルを計算し、それらを使用してデータセットを回転させます。

U,S,V = np.linalg.svd(cov)
print np.diag(S)
print '\nshape:', np.diag(S).shape

         diag(\ frac {1} {\ sqrt {diag(\ boldsymbol {S})+ \ epsilon}})また、形状(3072、3072)とUの合計\ boldsymbol {U ^ {\ text {T}}}から、Xの形状(1000、3072)がわかり、それを(3072、1000)に転置する必要があります。だから\ boldsymbol {X} _ {ZCA}形は

(3072、3072)。 (3072、3072)。 (1000、3072)^ {\ text {T}} =(3072、3072)。 (3072、1000)=(3072、1000)転置後の初期データセットの形状に対応します。

epsilon = 0.1
X_ZCA = U.dot(np.diag(1.0/np.sqrt(S + epsilon))).dot(U.T).dot(X_norm.T).T

        画像を再スケーリングしてみましょう:

X_ZCA_rescaled = (X_ZCA - X_ZCA.min()) / (X_ZCA.max() - X_ZCA.min())
print 'min:', X_ZCA_rescaled.min()
print 'max:', X_ZCA_rescaled.max()

        最後に、美白の前後の画像を比較することで、美白の効果を確認できます。

         Pal&Sudeep(2016)の論文の画像のように見えます。イプシロン=0.1を使用します。他の値を試して、画像への影響を確認できます。

おすすめ

転載: blog.csdn.net/bashendixie5/article/details/124448227