hexianhao 2019-02-09
本文假设您熟悉神经网络的概念。
让我们看看PCA对图像的作用。
左边的图像是原始图像。右边的图像是应用PCA然后将其转换回原始尺寸后的合成图像。
右边的图像和左边的图像是一样的,只是有点模糊。现在,如果我们把右边的图像输入到神经网络,而不是左边的,会怎么样呢?你认为会发生什么?
由于右侧的图像具有较少数量的像素,因此神经网络将在较少数量的特征上操作。因此,训练阶段所花费的时间将减少。
PCA代表主成分分析。顾名思义,给定机器学习数据集,我们感兴趣的是找到最重要的主组件,即表示底层数据集的“重要特征”。“重要特征”是什么意思呢?正如上面的图片(代表猫)所显示的,我们只需要保留那些告诉我们图像包含什么的像素。换句话说,我们不需要在图像中使用不必要的像素来表示无用的东西,比如背景、家具上的条纹或图像中的许多细节。
如何将“重要特征”编码到程序中呢?我们使用方差!如果我们要测量所有特征的方差(图像中的像素),那么我们就会清楚哪些特征是重要的。最重要的特征将具有大方差,这表明该特征的值在决定其输出标签方面起着重要的作用。同样,小方差告诉我们,该特征的值不会影响我们试图预测的输出标签。
从数学上讲,PCA通过找到k个向量将u维度减小到k维度:u(1),u(2),...,u(k),在其上投影数据,以便最小化投影误差。通过最小化投影误差,我们将保留数据的最大方差。
注意: PCA不仅适用于图像。我们甚至可以将其应用于数字数据。重点是,我们将确定最重要的特征并拒绝剩余的特征。
最后,当我们说我们保留了重要的特征,抛弃了剩下的特征(方差较小),我们并不是说我们计算每个特征的方差,只保留那些值较高的特征。这是一个错误,我们将因此失去重要的信息!我们执行主成分分析的方法是通过计算新的特征来获取最大的方差。此外,我们计算的新特征的总数应该小于现有特征的总数。
让我们先了解PCA背后的直觉。现实生活中的机器学习数据集通常是高维的。特别是在处理图像时,我们将每个像素视为一个特征。这实际上是我们这方面的一个大错,因为大多数像素都没用,但是,我们给所有机器学习(ML)模型提供了图像中存在的所有像素。我们给出所有像素的原因是我们不知道如何有效地表示图像以便机器学习(ML)模型轻松学习。因此,作为预处理步骤,(因为我们无法有效地表示图像),我们尝试降低图像的尺寸,以便机器学习(ML)模型可以容易地了解图像中存在的内容。这被称为“ 维度诅咒 ”。一个“诅咒”的原因是,当你不断增维度时,ML算法开始越来越难以在巨大的空间中找到训练数据(N维)。
为了解决维数诅咒,解决方案是减少维度,即减少维数。目标是用较少的变量(特征)来表示实例,同时我们必须尽可能多地保留数据中的结构。我们可以施加的更严格的约束(使机器学习模型变得容易)是“ 仅保留影响类别可分离性的结构 ” 。”
现在,有两种方法可以减少维数:
注意:我们选择方差的原因是方差保留了输入数据集中点之间的距离。此外,在大多数ML模型的基本观点中,点之间的距离是唯一重要的。
让我们看看如何找到保留最大方差的最重要特征:
我们从大小为NXM的X开始,以大小为KX M的Z结束。基本上我们将N维数据集缩减为K(<N)维数据集。这是一个很棒的改进!
注意:您看到的上述猫图像是附加步骤的结果。到目前为止,通过以上4个步骤,您可以将大小为NXM的机器学习数据集缩小为KX M的大小。但是我们无法绘制像素数较少的图像。因此,我们通过在'U_reduce'和'Z'(如前所述)之间执行矩阵乘法来重构原始图像。得到的矩阵的大小为NXM,可以绘制成图像。
现在的问题是,通过选择K (< N)个特征,我们保留了多少方差?一旦你看到代码,它就会很明显。我们确保保留90%的方差。在下一节中,我将给出非常清楚地演示如何执行PCA的Python代码。请注意,我使用基本Python和Numpy实现了整个代码。我没有使用任何预定义的库(如scikit-learn),其中pca()函数是内置的!
既然我们已经讨论了什么是PCA,它如何有助于加速神经网络训练以及PCA背后的数学,现在让我们将它应用于以下数据集:
为了清楚起见,可以参考以下Python代码段:
def pca(X, var, required_k=None): """ Does dimensionality reduction by applying principal component analysis X is a numpy matrix of size (N X M) var is the amount of variance to be retained (between 0 and 100) if 'required_k' is specified, then 'var' is ignored and the first 'required_k' eigen-vectors are returned """ cov = (1/X.shape[1]) * (X @ X.T) u, s, v = np.linalg.svd(cov) u_reduced = None X_reduced = None if required_k == None: total = np.sum(s) accum = 0 k = None for index in range(s.shape[0]): accum = accum + s[index] if (accum / total) * 100 >= var: k = index break if k == None: print("Could not attain the variance specified (" + str(var) + "%)") var = (accum / total) * 100 print("New variance retained is: " + str(var) + "%") k = s.shape[0] - 1 else: print("Retaining " + str(var) + "% variance, k = " + str(k)) u_reduced = u[:, :k] X_reduced = u_reduced.T @ X else: print("Retaining top " + str(required_k) + " eigen-vectors") u_reduced = u[:, :required_k] X_reduced = u_reduced.T @ X return X_reduced, u_reduced def reverse_pca(X_reduced, u_reduced): """ Given 2 matrices of size K X M and N X K, reverse pca is performed to return a matrix of size N X M """ return u_reduced @ X_reduced def print_principal_components(U, img_size, num=1): """ Given the eigen vectors present in U (of size NXK) and the image size to be plotted, this function plots the first 'num' principal components """ for i in range(num): plot_image_from_dataset(U, img_size, index=i)
在本文中,我们了解了PCA,它背后的数学,它如何有助于加速神经网络训练时间以及涉及PCA的实际应用。