是否可以在用于更传统数据集 (CIFAR-10/MNIST) 的 CNN 模型中使用一组高光谱 1x1 像素?
Is it possible to use a collection of hyperspectral 1x1 pixels in a CNN model purposed for more conventional datasets (CIFAR-10/MNIST)?
我在 Keras/Tensorflow 中创建了一个有效的 CNN 模型,并成功地使用 CIFAR-10 和 MNIST 数据集测试了这个模型。功能代码如下所示:
import keras
from keras.datasets import cifar10
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout, Conv2D, Flatten, MaxPooling2D
from keras.layers.normalization import BatchNormalization
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
#reshape data to fit model
X_train = X_train.reshape(50000,32,32,3)
X_test = X_test.reshape(10000,32,32,3)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
# Building the model
#1st Convolutional Layer
model.add(Conv2D(filters=64, input_shape=(32,32,3), kernel_size=(11,11), strides=(4,4), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))
#2nd Convolutional Layer
model.add(Conv2D(filters=224, kernel_size=(5, 5), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))
#3rd Convolutional Layer
model.add(Conv2D(filters=288, kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
#4th Convolutional Layer
model.add(Conv2D(filters=288, kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
#5th Convolutional Layer
model.add(Conv2D(filters=160, kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))
model.add(Flatten())
# 1st Fully Connected Layer
model.add(Dense(4096, input_shape=(32,32,3,)))
model.add(BatchNormalization())
model.add(Activation('relu'))
# Add Dropout to prevent overfitting
model.add(Dropout(0.4))
#2nd Fully Connected Layer
model.add(Dense(4096))
model.add(BatchNormalization())
model.add(Activation('relu'))
#Add Dropout
model.add(Dropout(0.4))
#3rd Fully Connected Layer
model.add(Dense(1000))
model.add(BatchNormalization())
model.add(Activation('relu'))
#Add Dropout
model.add(Dropout(0.4))
#Output Layer
model.add(Dense(10))
model.add(BatchNormalization())
model.add(Activation('softmax'))
#compile model using accuracy to measure model performance
opt = keras.optimizers.Adam(learning_rate = 0.0001)
model.compile(optimizer=opt, loss='categorical_crossentropy',
metrics=['accuracy'])
#train the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=30)
从这一点开始,在使用上述数据集之后,我想更进一步,使用通道数多于灰度或 rgb 的数据集,因此包含高光谱数据集。在寻找高光谱数据集时,我遇到了 this 个。
这个阶段的问题是意识到这个高光谱数据集是一个图像,地面实况中的每个值都与每个像素相关。在这个阶段,我将数据重新格式化为高光谱 data/pixels.
的集合
为 x_train 和 x_test 重新格式化更正数据集的代码:
import keras
import scipy
import numpy as np
import matplotlib.pyplot as plt
from keras.utils import to_categorical
from scipy import io
mydict = scipy.io.loadmat('Indian_pines_corrected.mat')
dataset = np.array(mydict.get('indian_pines_corrected'))
#This is creating the split between x_train and x_test from the original dataset
# x_train after this code runs will have a shape of (121, 145, 200)
# x_test after this code runs will have a shape of (24, 145, 200)
x_train = np.zeros((121,145,200), dtype=np.int)
x_test = np.zeros((24,145,200), dtype=np.int)
xtemp = np.array_split(dataset, [121])
x_train = np.array(xtemp[0])
x_test = np.array(xtemp[1])
# x_train will have a shape of (17545, 200)
# x_test will have a shape of (3480, 200)
x_train = x_train.reshape(-1, x_train.shape[-1])
x_test = x_test.reshape(-1, x_test.shape[-1])
代码重新格式化 Y_train & Y_test 的地面实况数据集:
truthDataset = scipy.io.loadmat('Indian_pines_gt.mat')
gTruth = truthDataset.get('indian_pines_gt')
#This is creating the split between Y_train and Y_test from the original dataset
# Y_train after this code runs will have a shape of (121, 145)
# Y_test after this code runs will have a shape of (24, 145)
Y_train = np.zeros((121,145), dtype=np.int)
Y_test = np.zeros((24,145), dtype=np.int)
ytemp = np.array_split(gTruth, [121])
Y_train = np.array(ytemp[0])
Y_test = np.array(ytemp[1])
# Y_train will have a shape of (17545)
# Y_test will have a shape of (3480)
Y_train = Y_train.reshape(-1)
Y_test = Y_test.reshape(-1)
#17 binary categories ranging from 0-16
#Y_train one-hot encode target column
Y_train = to_categorical(Y_train)
#Y_test one-hot encode target column
Y_test = to_categorical(Y_test, num_classes = 17)
我的思考过程是,尽管初始图像被分解为 1x1 块,但每个块拥有的大量通道及其各自的值将有助于数据集的分类。
基本上我想将这个重新格式化的数据输入到我的模型中(在这个 post 的第一个代码片段中看到),但是我不确定我是否采取了错误的方法,因为我对这方面的专业知识缺乏经验。我期望输入 (1,1,200) 的形状,即 x_train 和 x_test 的形状分别为 (17545,1,1,200) 和 (3480,1,1,200)。
如果高光谱数据集作为具有多个通道的大图像提供给您,我认为每个像素的 classification 应该取决于它周围的像素(否则我不会将数据格式化为图像,即没有网格结构)。鉴于此假设,将输入图片分解为 1x1 部分并不是一个好主意,因为您正在失去网格结构。
我进一步假设通道的顺序是任意的,这意味着通道上的卷积可能没有意义(然而你并不打算这样做)。
您可能想要创建一个模型,将图像作为输入并输出包含每个像素的 classifications 的“图像”,而不是像您那样重新格式化数据。
IE。如果你有 10 classes 并以 (145, 145, 200) 图像作为输入,你的模型将输出 (145, 145, 10) 图像。在那个架构中,你不会有任何完全连接的层。您的输出层也将是一个卷积层。
但这意味着您将无法保留当前的架构。那是因为 MNIST/CIFAR10 和您的高光谱数据集的任务不一样。对于 MNIST/CIFAR10,您希望 class 完整地验证图像,而对于其他数据集,您希望为每个像素分配 class(同时很可能还使用每个像素周围的像素).
一些进一步的想法:
- 如果你想把高光谱数据集上的像素class化任务变成整个图像的class化任务,也许你可以将该任务重新表述为“class将高光谱图像验证为其中心(或左上角、右下角、(第 21、104)或其他)像素的 class”。为了从单个高光谱图像中获取数据,对于每个像素,我会移动图像,使目标像素位于所需位置(例如中心)。所有“脱离”边界的像素都可以插入图像的另一侧。
- 如果您想坚持像素化任务 class 但需要更多数据,可以将您拥有的单个高光谱图像拆分成许多较小的图像(例如 10x10x200)。您甚至可能想要使用许多不同尺寸的图像。如果您的模型只有卷积层和池化层,并且您确保保持图像的大小,那应该可行。
首先,假设您使用的高光谱图像是针对 semantic segmentation 问题而不是分类问题。
如果我们看看什么是神经网络中的卷积层,它不太可能工作得很好。它可能有效,但可能有更好的方法。
让我们看看这个 2D 卷积动画(由 Michael Plotke 授权 CC-BY-SA 3.0) :
我们可以看出,从本质上讲,二维卷积运算就像是对图像的某个区域应用一定大小的过滤器,然后对图像的所有区域重复这个操作。在尝试 learn/find 空间特征时,二维卷积通常用于神经网络:即相邻像素之间的关系。
摘自CS231n - Convolutional Networks
As we slide the filter over the width and height of the input volume we will produce a 2-dimensional activation map that gives the responses of that filter at every spatial position. Intuitively, the network will learn filters that activate when they see some type of visual feature such as an edge of some orientation or a blotch of some color on the first layer, or eventually entire honeycomb or wheel-like patterns on higher layers of the network.
通过使用大小为 1x1 的小块,您基本上去除了数据的空间维度。在这种情况下应用 2D 卷积没有太大意义。 (特别是考虑到该架构中使用的过滤器的大小,例如第一层中的 11x11)。
建议的方法:
- 找到一个更大的数据集,其中包含多个设计用于分类的图像:这可能是要走的路。在数据驱动的问题中,最重要的部分是数据。
- 如果对该图像的区域进行分类对您很重要,您可以对光谱数据像素使用更简单的网络架构 and/or 机器学习技术。这可能有效,但您仍然会丢失相邻像素之间的空间关系。
我在 Keras/Tensorflow 中创建了一个有效的 CNN 模型,并成功地使用 CIFAR-10 和 MNIST 数据集测试了这个模型。功能代码如下所示:
import keras
from keras.datasets import cifar10
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense, Activation, Dropout, Conv2D, Flatten, MaxPooling2D
from keras.layers.normalization import BatchNormalization
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
#reshape data to fit model
X_train = X_train.reshape(50000,32,32,3)
X_test = X_test.reshape(10000,32,32,3)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)
# Building the model
#1st Convolutional Layer
model.add(Conv2D(filters=64, input_shape=(32,32,3), kernel_size=(11,11), strides=(4,4), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))
#2nd Convolutional Layer
model.add(Conv2D(filters=224, kernel_size=(5, 5), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))
#3rd Convolutional Layer
model.add(Conv2D(filters=288, kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
#4th Convolutional Layer
model.add(Conv2D(filters=288, kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
#5th Convolutional Layer
model.add(Conv2D(filters=160, kernel_size=(3,3), strides=(1,1), padding='same'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))
model.add(Flatten())
# 1st Fully Connected Layer
model.add(Dense(4096, input_shape=(32,32,3,)))
model.add(BatchNormalization())
model.add(Activation('relu'))
# Add Dropout to prevent overfitting
model.add(Dropout(0.4))
#2nd Fully Connected Layer
model.add(Dense(4096))
model.add(BatchNormalization())
model.add(Activation('relu'))
#Add Dropout
model.add(Dropout(0.4))
#3rd Fully Connected Layer
model.add(Dense(1000))
model.add(BatchNormalization())
model.add(Activation('relu'))
#Add Dropout
model.add(Dropout(0.4))
#Output Layer
model.add(Dense(10))
model.add(BatchNormalization())
model.add(Activation('softmax'))
#compile model using accuracy to measure model performance
opt = keras.optimizers.Adam(learning_rate = 0.0001)
model.compile(optimizer=opt, loss='categorical_crossentropy',
metrics=['accuracy'])
#train the model
model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=30)
从这一点开始,在使用上述数据集之后,我想更进一步,使用通道数多于灰度或 rgb 的数据集,因此包含高光谱数据集。在寻找高光谱数据集时,我遇到了 this 个。
这个阶段的问题是意识到这个高光谱数据集是一个图像,地面实况中的每个值都与每个像素相关。在这个阶段,我将数据重新格式化为高光谱 data/pixels.
的集合为 x_train 和 x_test 重新格式化更正数据集的代码:
import keras
import scipy
import numpy as np
import matplotlib.pyplot as plt
from keras.utils import to_categorical
from scipy import io
mydict = scipy.io.loadmat('Indian_pines_corrected.mat')
dataset = np.array(mydict.get('indian_pines_corrected'))
#This is creating the split between x_train and x_test from the original dataset
# x_train after this code runs will have a shape of (121, 145, 200)
# x_test after this code runs will have a shape of (24, 145, 200)
x_train = np.zeros((121,145,200), dtype=np.int)
x_test = np.zeros((24,145,200), dtype=np.int)
xtemp = np.array_split(dataset, [121])
x_train = np.array(xtemp[0])
x_test = np.array(xtemp[1])
# x_train will have a shape of (17545, 200)
# x_test will have a shape of (3480, 200)
x_train = x_train.reshape(-1, x_train.shape[-1])
x_test = x_test.reshape(-1, x_test.shape[-1])
代码重新格式化 Y_train & Y_test 的地面实况数据集:
truthDataset = scipy.io.loadmat('Indian_pines_gt.mat')
gTruth = truthDataset.get('indian_pines_gt')
#This is creating the split between Y_train and Y_test from the original dataset
# Y_train after this code runs will have a shape of (121, 145)
# Y_test after this code runs will have a shape of (24, 145)
Y_train = np.zeros((121,145), dtype=np.int)
Y_test = np.zeros((24,145), dtype=np.int)
ytemp = np.array_split(gTruth, [121])
Y_train = np.array(ytemp[0])
Y_test = np.array(ytemp[1])
# Y_train will have a shape of (17545)
# Y_test will have a shape of (3480)
Y_train = Y_train.reshape(-1)
Y_test = Y_test.reshape(-1)
#17 binary categories ranging from 0-16
#Y_train one-hot encode target column
Y_train = to_categorical(Y_train)
#Y_test one-hot encode target column
Y_test = to_categorical(Y_test, num_classes = 17)
我的思考过程是,尽管初始图像被分解为 1x1 块,但每个块拥有的大量通道及其各自的值将有助于数据集的分类。
基本上我想将这个重新格式化的数据输入到我的模型中(在这个 post 的第一个代码片段中看到),但是我不确定我是否采取了错误的方法,因为我对这方面的专业知识缺乏经验。我期望输入 (1,1,200) 的形状,即 x_train 和 x_test 的形状分别为 (17545,1,1,200) 和 (3480,1,1,200)。
如果高光谱数据集作为具有多个通道的大图像提供给您,我认为每个像素的 classification 应该取决于它周围的像素(否则我不会将数据格式化为图像,即没有网格结构)。鉴于此假设,将输入图片分解为 1x1 部分并不是一个好主意,因为您正在失去网格结构。
我进一步假设通道的顺序是任意的,这意味着通道上的卷积可能没有意义(然而你并不打算这样做)。
您可能想要创建一个模型,将图像作为输入并输出包含每个像素的 classifications 的“图像”,而不是像您那样重新格式化数据。 IE。如果你有 10 classes 并以 (145, 145, 200) 图像作为输入,你的模型将输出 (145, 145, 10) 图像。在那个架构中,你不会有任何完全连接的层。您的输出层也将是一个卷积层。
但这意味着您将无法保留当前的架构。那是因为 MNIST/CIFAR10 和您的高光谱数据集的任务不一样。对于 MNIST/CIFAR10,您希望 class 完整地验证图像,而对于其他数据集,您希望为每个像素分配 class(同时很可能还使用每个像素周围的像素).
一些进一步的想法:
- 如果你想把高光谱数据集上的像素class化任务变成整个图像的class化任务,也许你可以将该任务重新表述为“class将高光谱图像验证为其中心(或左上角、右下角、(第 21、104)或其他)像素的 class”。为了从单个高光谱图像中获取数据,对于每个像素,我会移动图像,使目标像素位于所需位置(例如中心)。所有“脱离”边界的像素都可以插入图像的另一侧。
- 如果您想坚持像素化任务 class 但需要更多数据,可以将您拥有的单个高光谱图像拆分成许多较小的图像(例如 10x10x200)。您甚至可能想要使用许多不同尺寸的图像。如果您的模型只有卷积层和池化层,并且您确保保持图像的大小,那应该可行。
首先,假设您使用的高光谱图像是针对 semantic segmentation 问题而不是分类问题。
如果我们看看什么是神经网络中的卷积层,它不太可能工作得很好。它可能有效,但可能有更好的方法。
让我们看看这个 2D 卷积动画(由 Michael Plotke 授权 CC-BY-SA 3.0) :
我们可以看出,从本质上讲,二维卷积运算就像是对图像的某个区域应用一定大小的过滤器,然后对图像的所有区域重复这个操作。在尝试 learn/find 空间特征时,二维卷积通常用于神经网络:即相邻像素之间的关系。
摘自CS231n - Convolutional Networks
As we slide the filter over the width and height of the input volume we will produce a 2-dimensional activation map that gives the responses of that filter at every spatial position. Intuitively, the network will learn filters that activate when they see some type of visual feature such as an edge of some orientation or a blotch of some color on the first layer, or eventually entire honeycomb or wheel-like patterns on higher layers of the network.
通过使用大小为 1x1 的小块,您基本上去除了数据的空间维度。在这种情况下应用 2D 卷积没有太大意义。 (特别是考虑到该架构中使用的过滤器的大小,例如第一层中的 11x11)。
建议的方法:
- 找到一个更大的数据集,其中包含多个设计用于分类的图像:这可能是要走的路。在数据驱动的问题中,最重要的部分是数据。
- 如果对该图像的区域进行分类对您很重要,您可以对光谱数据像素使用更简单的网络架构 and/or 机器学习技术。这可能有效,但您仍然会丢失相邻像素之间的空间关系。