【问题标题】:Using PCA to Reduce # Dimensions in Training Set for CNN使用 PCA 减少 CNN 训练集中的 # 维数
【发布时间】:2021-10-17 16:51:00
【问题描述】:

简短版:我在使用 PCA 减少训练数据的维数时遇到了困难。训练数据是为 2D CNN 构建的,该 CNN 将图形图像分为三类。

模型目的

我是主成分分析的新手。我有一个 2D 卷积神经网络,它将图形图像(36 x 36 像素)分类为三个类别之一,例如:

改进模型

我意识到大部分像素都是白色的,所以 CNN 效率非常低,需要很长时间来训练。我开始了解降维技术并尝试使用 PCA。我将我的一张训练图像转换为灰度图像并可视化“特征图”(如左图所示)。然后我根据特征图重建了原件(如右图所示)。

X=grayscale 

pca_oliv = PCA(n_components = 36)
X_proj = pca_oliv.fit_transform(X)

print(np.cumsum(pca_oliv.explained_variance_ratio_))

plt.imshow(np.reshape(pca_oliv.components_, (36,36)), cmap=plt.cm.bone, interpolation='nearest')

问题

但我知道它可以做得更好。这是 n=36 尺寸。通过绘制解释方差,我找到了 3 个维度的肘部。这意味着只需要 36 个维度中的 3 个维度,我就可以保留 91.7% 的方差。

但如果我将 pca_oliv = PCA(n_components = 36) 更改为 pca_oliv = PCA(n_components = 3),一切都会变得混乱:ValueError: cannot reshape array of size 108 into shape (36,36)。为什么?我做错了什么?

MWE

pip install tensorflow
pip install numpy
pip install matplotlib

"""# Import Libraries"""

# Import Libraries
import tensorflow as tf
from tensorflow import keras
from keras.models import Sequential
from keras.layers import Dense, Flatten, Conv2D, MaxPooling2D, Dropout
from tensorflow.keras import layers
from tensorflow.keras.utils import to_categorical
import numpy as np
import matplotlib.pyplot as plt

plt.style.use('fivethirtyeight')

"""# Load Dataset"""

import pathlib
dataset_url = "*/TrainingSet.tar.gz"
data_dir = tf.keras.utils.get_file(origin = dataset_url,
                                   fname = "TrainingSet",
                                   untar = True)
data_dir = pathlib.Path(data_dir)

"""# Display # Images to check"""

print(list(data_dir.glob('*/*.png')))
image_count = len(list(data_dir.glob('*/*.png')))
print(image_count)

"""# Display sample image"""

pip install sklearn

import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
import tensorflow_datasets as tfds
from sklearn.decomposition import PCA

graphs = list(data_dir.glob('*/*.png'))
PIL.Image.open(str(graphs[6]))

"""# Define Image Dimensions & Batch Size"""

batch_size = 32
img_height = 36
img_width = 36

"""# Create Training & Validation Sets (80%, 20%)"""

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

val_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

"""# Define 3 Classes"""

class_names = ['Cubic Sinusoidal', 'Linear Sinusoidal', 'Quadratic Sinusoidal']
print(class_names)

"""# Supervised Learning (9 Samples from the Training Set)"""

!pip install skimage

from skimage import data
from skimage.color import rgb2gray

import matplotlib.pyplot as plt

subGraphs = []

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    subGraphs.append(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

subGraphs = np.array(subGraphs)
print(subGraphs.shape)

grayscale = rgb2gray(subGraphs[1])
print(grayscale.shape)

X=grayscale 

pca_oliv = PCA(n_components = 36)
X_proj = pca_oliv.fit_transform(X)

print(np.cumsum(pca_oliv.explained_variance_ratio_))
plt.plot(np.cumsum(pca_oliv.explained_variance_ratio_))

plt.imshow(np.reshape(pca_oliv.components_, (36,36)), cmap=plt.cm.bone, interpolation='nearest')

X_inv_proj = pca_oliv.inverse_transform(X_proj)
X_proj_img = np.reshape(X_inv_proj,(1,36,36))

plt.imshow(X_proj_img[0], cmap=plt.cm.bone, interpolation='nearest')

作为参考,这是我的 Jupyter Notebook:PCA+CNN。如果有人可以提供帮助,那就太好了。

【问题讨论】:

  • 分享整个回溯。此外,在出错时使用.fit_transform 时,input 的形状是什么。
  • 请 1) 发布产生错误的代码的完整错误跟踪(不是PCA(n_components = 36) 2)删除之后出现的任何代码i> 错误,因为它与问题无关。另外,“MWE”不是您代码的准确术语,因为使用的数据不公开。

标签: python tensorflow machine-learning conv-neural-network pca


【解决方案1】:

PCA 用于减少维数,同时确保这种低维表示涵盖最大可能的变化。现在,想一想,你最初有多少个维度。正如,我看到你使用了(36, 36) 灰度图像。在这里,每个像素都是您的原始特征。同样,您拍摄了 9 张图像以在它们上应用 PCA

在这种情况下,您的 number of examples 小于 number of original features9 < 36*36,因此,您只需要 9 主成分即可涵盖全部方差。但是,如果您的示例数量大于 (36*36 = 1296) 的特征数量,那么您可以采用更大的值 n_components。请看这里,sklearn.decomposition.PCAWhy are there only n−1 principal components for n data if the number of dimensions is ≥n?

但无论如何,我不会深入了解PCA 的细节,而是描述您需要在代码中更改的内容。

grayscale = rgb2gray(subGraphs)
print(grayscale.shape)

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

由于PCA 期望输入形状为(number of examples, number of features) 因此,您必须将number of examples 保留在第一维中,第二维将是所有像素值(原始特征)。如果您使用了彩色图像,则需要将所有通道的特征包含在同一第二维中,有点像:

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

现在你可以申请PCA:

X=grayscale 

pca_oliv = PCA(n_components = 9)
X_proj = pca_oliv.fit_transform(X)

print(np.cumsum(pca_oliv.explained_variance_ratio_))
plt.plot(np.cumsum(pca_oliv.explained_variance_ratio_))

请注意,您不能将n_components 设置为超过9,因为您只使用了9 张图片。如果你看到X_proj 的形状,你会发现它的形状是(9, 9)。第一个9 是示例的数量,第二个9 是每个示例都表示在具有9 维度的低维空间中(n_components)。

最后,进行逆变换以恢复原始尺寸,(仅用于说明目的,您将使用X_proj 训练您的模型,因为它是较低维度的表示):

X_inv_proj = pca_oliv.inverse_transform(X_proj)
print(X_inv_proj.shape)
for index in range(len(X_inv_proj)): # 9                    
  X_proj_img = np.reshape(X_inv_proj[index],(36,36))
  plt.imshow(X_proj_img, cmap=plt.cm.bone, interpolation='nearest')
  plt.show()

同样,X_proj 包含您的 9 示例的低维表示(9 维度)。因为,它不是图像,所以你不需要重塑它。您可以直接使用它来训练您的模型,就好像这些 9 特征代表了您原来的 36*36 特征一样。

在这里,请注意,逆变换并不总是无损变换。在这里,在您的情况下,我们采用了9 主要组件(在这种情况下是最大可能的)。所以,本质上我们在得到PCA的同时采用了100%的变化,所以,当我们应用逆变换时,它会给我们返回变化的100%,即它会恢复原始数据。但是如果我们把n_components取一个更低的值,那么逆变换就不能完全恢复原来的信息,虽然X_inv_proj的形状不会改变,但是它所持有的信息不会改变是原始数据的完整信息。

【讨论】:

  • 感谢@hafiz031 的帮助。我想我开始明白我做错了什么。首先,PCA能得到的最大主成分数是我给出的例子数?因此,例如,如果我给出 9 个示例,那么最大值。 #PC = 9?所以随着#PC 的下降,我的重建变得更加模糊。这是为什么?另外,如何将 PCA 集成到我的 CNN 中?我是否将我的整个训练数据集输入 PCA,然后将结果输入我的 CNN,而不是 9 个示例?
  • @rb3652 不,它并不总是取决于示例的数量。很难在评论中描述整个事情,所以我通过提供链接作为参考来指导你,首先从这里了解PCA 的作用:stats.stackexchange.com/a/140579/245577
  • 主成分的最大数量是示例的数量——这只是一个特殊情况。当您的点数基本上小于(或等于)点数时。为什么?想象一下——你在二维空间中有 2 个点,你需要多少个最大维度来描述它们?答案只有一个维度。为什么?我们可以认为这些点在一条线上(在这种情况下为主轴)并定位这些点的位置。这条线(即沿这条线的分量或投影(主分量一词就是这样来的)。
  • @rb3652 ...现在认为这些2 点在3-dimensional 空间中。这次你需要描述它们的最大维度是多少?答案仍然是1。因为,无论这些2 点驻留在多少维(#dimension >= 2)中,我们只需要一维来描述它们。这就是这种特殊情况的来历。 (这个解释摘自@amoeba在这篇文章中的评论:stats.stackexchange.com/questions/123318/…
  • 现在,来看看一般情况,当#points > #dimensions,在这种情况下你将最大需要#dimensionsPCs。为什么?原始维度具有冗余(多个维度表示可以由另一个维度重现的信息)。因此,我们使用PCA 来消除这种冗余(没有dimensionprincipal axes 现在集体表示与not correlated 相同的信息,即一个轴持有的信息不能被另一个轴找到)。所以,这是有道理的,你永远不需要比原来的维数更多的principal axes(确实有冗余)......
猜你喜欢
  • 1970-01-01
  • 2014-01-02
  • 2016-11-01
  • 2013-09-20
  • 2021-12-21
  • 2017-12-12
  • 2021-03-17
  • 1970-01-01
  • 2021-08-11
相关资源
最近更新 更多