I.概要
データ前処理の基本から深層学習で使用される手法まで、すべてをよりよく理解するために、コード(Python / Numpyなど)でコーディングします。
分散や共分散行列など、データサイエンスと機械学習/深層学習の基本的でありながら非常に有用な概念から始めて、画像をニューラルネットワークにフィードするためのいくつかの前処理手法に進みます。特定のコードを使用して、各方程式の機能を理解してください。
生データのすべての変換を前処理してから、機械学習または深層学習アルゴリズムにフィードします。たとえば、生の画像で畳み込みニューラルネットワークをトレーニングすると、分類のパフォーマンスが低下する可能性があります。前処理は、トレーニングを高速化するためにも重要です(たとえば、センタリングやスケーリングの手法など)。
2.分散と共分散
変数の分散は、値がどの程度広く分布しているかを表します。共分散は、2つの変数間の依存度の尺度です。正の共分散は、2番目の変数の値も大きい場合に、最初の変数の値が大きいことを意味します。負の共分散とは、その逆を意味します。ある変数の大きな値は、別の変数の小さな値に関連付けられます。共分散値は変数のスケールに依存するため、分析が困難です。解釈しやすい相関係数を使用できます。これは、正規化された共分散です。
共分散行列は、変数について多くのことを伝えることができる一連のベクトルの分散と共分散を集約する行列です。対角線は、各ベクトルの分散に対応しています。
分散の計算式は次のとおりです。
ここで、nはベクトルの長さであり、ベクトルの平均です。たとえば、Aの最初の列ベクトルの分散は次のとおりです。
これは、共分散行列の最初のセルです。対角線上の2番目の要素は、Aの2番目の列ベクトルの分散に対応します。
注:行列Aから抽出されたベクトルは、Aの列に対応します。
他のセルは、Aからの2つの列ベクトル間の共分散に対応します。たとえば、最初の列と3番目の列の間の共分散は、共分散行列、つまり列1と行3(または列3と行1)にあります。
Aの1列目と3列目のベクトル間の共分散が-2.67に等しいことを確認しましょう。2つの変数XとYの間の共分散の式は次のとおりです。
変数XとYは、前の例の1番目と3番目の列ベクトルです。この式を分割してみましょう:
1. 合計記号は、反復する必要のあるベクトルの要素です。最初の要素(i = 1)から始めて、Xの最初の要素からベクトルXの平均を引いたものを計算します。
2.結果にYの最初の要素からベクトルYの平均を引いたものを掛けます。
3.ベクトルの要素ごとにこのプロセスを繰り返し、すべての結果の合計を計算します。
4.ベクトルの要素数で割ります。
1、例1
次の行列を使用して、最初の列ベクトルと3番目の列ベクトルの間の共分散を計算します。
と、、、、、そう_ _
つまり、共分散行列の値です。
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つのベクトル間の内積は、次のように表すことができます。
次に、ベクトル内の要素の数nで除算します。
これは、上記で見た共分散式と非常によく似ていることがわかります。
唯一の違いは、共分散式では、平均からベクトルの各要素を減算することです。そのため、内積を行う前にデータを中央に配置する必要があります。
ここで、行列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.関連データ
次に、ある列を別の列から指定して、依存データを作成しましょう。
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]]
4.前処理
1.平均正規化
平均の正規化は、各観測値から平均を削除するだけです。
、ここで、X'は正規化されたデータセット、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]]
2.標準化
正規化は、すべての機能を同じスケールに配置するために使用されます。これを行う方法は、ゼロ中心の各次元をその標準偏差で除算することです。ここで、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)デコレート
データを非相関化する必要があります。直感的には、相関関係がなくなるまでデータをローテーションします。下記参照:
問題は、無相関データの正しいローテーションをどのように見つけることができるかということです。実際、これは共分散行列の固有ベクトルが行うこととまったく同じです。これらは、データが最も広がる方向を示します。
したがって、特徴ベクトルに基づいてデータを射影することにより、データを非相関化できます。これには、目的の回転を適用し、寸法間の相関関係を削除する効果があります。手順は次のとおりです。
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
注: 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)と呼ばれます。
論文をチェックしてください、しかしこれは彼らが得たものです:
まず、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]を取得することです。
次の式を使用します。最小値は0なので、次のようになります。
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
また、形状(3072、3072)とUの合計から、Xの形状(1000、3072)がわかり、それを(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を使用します。他の値を試して、画像への影響を確認できます。