使用对象检测进行复杂图像分类方案

使用MobileNet和转移学习进行政策识别

本文内容介绍深度转移学习,作为一种利用多个数据源来克服数据稀缺性问题的方法。

处理图像

使用对象检测进行复杂图像分类方案

我们的目标是从训练图像中提取差分信号

在我们尝试为复杂策略构建分类器之前,让我们首先看一下MNIST数据集,以便更好地理解关键图像分类概念,然后我们将这些概念放在一起并将他们应用到我们的数据集。

使用对象检测进行复杂图像分类方案

MNIST数据集中的图像样本

要在MNIST上训练分类模型,我们首先需要一种方法来表示我们的图像和标签 。有许多方法可以将图像表示为张量,矩阵或向量。

对于我们的第一个模型,我们将使用矢量表示。为此,我们首先将图像展平为长矢量。

当我们将此过程应用于尺寸为28 x 28图像像素的下面“3”的图像时,将产生长度为784像素的平坦阵列。

使用对象检测进行复杂图像分类方案

MNIST图像28×28图像像素,它将产生长度为784的扁平阵列。

现在即使我们很容易看到这个图像并且知道它是一个“3”,计算机本身并不知道这一点,我们需要训练一个模型来学习如何识别图像中有一个“3” 。为此,我们首先需要一种表示上图中包含“3”图像这一事实的方法。

编码图像标签

为了实现,我们将每个图像与一个独热编码标签相关联,其中第一个索引对应于数字0,最后一个对应于数字9。

使用对象检测进行复杂图像分类方案

MNIST 3的独热编码矢量表示

当我们训练模型时,我们使用此值作为目标。该Keras下面的代码加载MNIST数据

from keras.datasets import mnist 
from keras.utils import np_utils 
output_dim = nb_classes = 10 
batch_size = 128 
nb_epoch = 5
# the data, shuffled and split between train and test sets 
(x_train, y_train), (x_test, y_test) = mnist.load_data()
input_dim = 784 #28*28 
X_train = x_train.reshape(60000, input_dim) 
X_test = x_test.reshape(10000, input_dim) 
X_train = X_train.astype('float32') 
X_test = X_test.astype('float32') 
X_train /= 255 
X_test /= 255
Y_train = np_utils.to_categorical(y_train, nb_classes) 
Y_test = np_utils.to_categorical(y_test, nb_classes)

使用对象检测进行复杂图像分类方案

现在我们已经处理了MNIST图像及其标签,让我们使用Keras训练我们的第一个图像分类模型。

线性模型

Logistic回归(LR)是一种基本的机器学习技术,它使用线性加权特征组合并生成不同类别的基于概率的预测。

使用对象检测进行复杂图像分类方案

要在MNIST上训练LR模型,我们应用以下步骤:

  1. 初始化784个值的随机权重向量
  2. 取第一个784位 MNIST训练图像矢量,如上面的“3”,并乘以我们的权重向量。
  3. 取我们的乘法结果并将每个784值相加,直到我们得到一个数字
  4. 将数字传递给一个函数,该函数获取我们的总和并将其拟合到0-9之间的分布和独热编码输出。对于第一个例子,这个数字很可能是不正确的,因为我们乘以了随机值
  5. 将输出向量与图像标签向量进行比较,并使用损失函数计算我们的预测有多接近
  6. 对损失值应用SGD优化以更新权重向量中的每个值。

然后,我们对MNIST训练集中的每个图像重复此过程。对于每个图像,更新权重值,以便它们可以更好地将输入的MNIST向量转换为与其标签匹配的值。

使用对象检测进行复杂图像分类方案

机器学习过程

当我们在我们的训练集上完成上述步骤时,称为Epoch。在第一个Epoch之后,值仍然可能很差但是在对数据集进行混洗并重复几个Epochs的过程之后,线性模型学习线性权重,它们收敛于数据的适当表示。

下面的Keras代码显示了此过程的结果。

from keras.models import Sequential 
from keras.layers import Dense, Activation 
model = Sequential() 
model.add(Dense(output_dim, input_dim=input_dim, activation='softmax')) 
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) 
history = model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,verbose=1, validation_data=(X_test, Y_test)) 
score = model.evaluate(X_test, Y_test, verbose=0) 
print('Test Loss:', score[0]) 
print('Test accuracy:', score[1])

使用对象检测进行复杂图像分类方案

Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 1s 16us/step - loss: 1.2899 - acc: 0.6898 - val_loss: 0.8185 - val_acc: 0.8255
Epoch 2/5
60000/60000 [==============================] - 1s 17us/step - loss: 0.7228 - acc: 0.8374 - val_loss: 0.6113 - val_acc: 0.8588
Epoch 3/5
60000/60000 [==============================] - 1s 11us/step - loss: 0.5912 - acc: 0.8575 - val_loss: 0.5281 - val_acc: 0.8724
Epoch 4/5
60000/60000 [==============================] - 1s 11us/step - loss: 0.5280 - acc: 0.8681 - val_loss: 0.4821 - val_acc: 0.8800
Epoch 5/5
60000/60000 [==============================] - 1s 13us/step - loss: 0.4897 - acc: 0.8749 - val_loss: 0.4514 - val_acc: 0.8858
Test Loss: 0.4514175675392151
Test accuracy: 0.8858

使用对象检测进行复杂图像分类方案

非线性模型(MLP)

使用对象检测进行复杂图像分类方案

可以想象,仅基于一个输出递增和求和权重向量值是不一定是很好的,并且在某些情况下可能是无效的。

毕竟,并非所有数据都是线性的。

以下示例为两个名为spam和not spam的图像类。无论我们如何更新我们的权重,我们都无法学习线性权重来区分这些类。

使用对象检测进行复杂图像分类方案

但是,如果我们有一种方法可以组合多个线性模型以获得更好的表示能力呢?然后我们可以训练一个可以区分两个图像类的模型。

使用对象检测进行复杂图像分类方案

我们可以通过前馈神经网络来实现这一点。

使用对象检测进行复杂图像分类方案

多层感知

为了使MLP工作,我们需要一个非线性激活函数,例如RELU。

下面的代码显示了如何在MNIST上训练多层感知器以获得比我们的线性模型提供的更好的结果。

from keras.models import Sequential 
from keras.layers import Dense, Activation 
output_dim = nb_classes = 10 
batch_size = 128 
nb_epoch = 5
model = Sequential() 
model.add(Dense(input_dim, input_dim=input_dim, activation='relu')) 
model.add(Dense(input_dim, input_dim=input_dim, activation='relu'))
model.add(Dense(output_dim, input_dim=input_dim, activation='softmax')) 
model.compile(optimizer='sgd', loss='categorical_crossentropy', metrics=['accuracy']) 
history = model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,verbose=1, validation_data=(X_test, Y_test)) 
score = model.evaluate(X_test, Y_test, verbose=0) 
print('Test Loss:', score[0]) 
print('Test accuracy:', score[1])

使用对象检测进行复杂图像分类方案

Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 9s 150us/step - loss: 1.0790 - acc: 0.7676 - val_loss: 0.5100 - val_acc: 0.8773
Epoch 2/5
60000/60000 [==============================] - 9s 143us/step - loss: 0.4401 - acc: 0.8866 - val_loss: 0.3650 - val_acc: 0.9011
Epoch 3/5
60000/60000 [==============================] - 12s 194us/step - loss: 0.3530 - acc: 0.9032 - val_loss: 0.3136 - val_acc: 0.9127
Epoch 4/5
60000/60000 [==============================] - 16s 272us/step - loss: 0.3129 - acc: 0.9124 - val_loss: 0.2868 - val_acc: 0.9188
Epoch 5/5
60000/60000 [==============================] - 12s 203us/step - loss: 0.2875 - acc: 0.9194 - val_loss: 0.2659 - val_acc: 0.9246
Test Loss: 0.2659078140795231
Test accuracy: 0.9246

使用对象检测进行复杂图像分类方案

当然我们也会有很多非常大的图像

使用对象检测进行复杂图像分类方案

注意MLP模型比我们简单的线性模型更准确,但更慢。当我们的图像大于500Kb到1Mb时,处理我们的图像作为一个序列的计算成本越来越高,另外在我们的序列数据中检测复杂分层模式变得更困难。

这种维度的诅咒,是计算机视觉领域在2012年AlexNet问世之前停滞不前的关键原因之一。

我们将图像表示为一个矩阵(28x28),而不是将完整图像作为向量表示传递,并提取具有代表性的特征来进行分类决策。我们通过尝试将边缘作为模型的特征来深入研究传统的图像特征提取。

我们先拍摄如下图像。

使用对象检测进行复杂图像分类方案

然后我们采用预定义的图像蒙板,在这种情况下是一个用于提取边缘的索贝尔矩阵

使用对象检测进行复杂图像分类方案

我们将sobel矩阵蒙版应用于我们的图像,如过滤器一样

使用对象检测进行复杂图像分类方案

当我们可视化生成的图像时,我们得到以下边缘,我们可以将其用作特征

使用对象检测进行复杂图像分类方案

卷积神经网络简介

CNN是一个深层神经网络,由一堆层组成,这样一层的输出被馈送到下一层 。通常,CNN开始在卷积层和汇集层(下采样)之间交替,然后以分类部分的完全连接层结束。

卷积

卷积层是一组滤波器。每个滤波器由权重(W)矩阵和偏差(b)定义。

使用对象检测进行复杂图像分类方案

我们使用池来降低前一层的维度,从而加快网络的速度。

使用对象检测进行复杂图像分类方案

许多不同的池方法,最大池化和均值池化最常见的

这是一个最大池化和均值池化的示例,步长为2:

使用对象检测进行复杂图像分类方案

各种池操作

综合起来:

在大多数CNN中,我们堆叠了一组卷积层和池化层,直到我们得到一组代表性的特征,我们可以将其展平并用于类预测。

使用对象检测进行复杂图像分类方案

下面的代码显示了如何从上面训练MNIST图像上的CNN。

from keras.layers import Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
 activation='relu',
 input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes, activation='softmax'))
model.compile(loss=keras.losses.categorical_crossentropy,
 optimizer=keras.optimizers.Adadelta(),
 metrics=['accuracy'])
model.fit(x_train, y_train,
 batch_size=batch_size,
 epochs=nb_epoch,
 verbose=1,
 validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

使用对象检测进行复杂图像分类方案

Train on 60000 samples, validate on 10000 samples
Epoch 1/5
60000/60000 [==============================] - 177s 3ms/step - loss: 0.2638 - acc: 0.9204 - val_loss: 0.0662 - val_acc: 0.9790
Epoch 2/5
60000/60000 [==============================] - 173s 3ms/step - loss: 0.0882 - acc: 0.9732 - val_loss: 0.0404 - val_acc: 0.9865
Epoch 3/5
60000/60000 [==============================] - 166s 3ms/step - loss: 0.0651 - acc: 0.9806 - val_loss: 0.0350 - val_acc: 0.9883
Epoch 4/5
60000/60000 [==============================] - 163s 3ms/step - loss: 0.0549 - acc: 0.9836 - val_loss: 0.0334 - val_acc: 0.9887
Epoch 5/5
60000/60000 [==============================] - 159s 3ms/step - loss: 0.0472 - acc: 0.9859 - val_loss: 0.0322 - val_acc: 0.9899
Test loss: 0.03221080291894468
Test accuracy: 0.9899

使用对象检测进行复杂图像分类方案

在MNIST数据集中我们有成千上万的训练例子,但我们使用转移学习就可以不需要那么大量的数据。从头开始训练一个深度神经网络需要成千上万的图像,但是训练一个已经在某些领域中学习了特征的神经网络却需要很少量的图像数据就够用了。

转移学习简介

使用对象检测进行复杂图像分类方案

转移学习是使用预先适应我们的问题后训练出来的模型。在转移学习中,我们利用在基础模型训练期间学到的特征和概念。旧的和新的预测层的输入与基本模型相同,我们只是重新使用训练的特征。然后我们训练这个修改过的网络,或者只训练新预测层的新权重,或者整个网络的所有权重。

例如,当我们有一小组图像与现有训练模型处于类似域时,可以使用这种方法。在我们的例子中,这意味着使在ImageNet图像上训练的网络适应策略分类的任务。

预训练模型(MobileNet)

我们选择使用预训练的MobileNet模型作为基础模型。虽然有许多分类架构,但我们将使用MobileNet,因为它可以在CPU上快速运行并提供强大的结果。

from keras.layers import Dense,GlobalAveragePooling2D
from keras.applications import MobileNet
from keras.preprocessing import image
from keras.applications.mobilenet import preprocess_input
from keras.preprocessing.image import ImageDataGenerator
from keras.models import Model
from keras.optimizers import Adam
base_model=MobileNet(weights='imagenet',include_top=False) #imports the mobilenet model and discards the last 1000 neuron layer.
x=base_model.output
x=GlobalAveragePooling2D()(x)
x=Dense(1024,activation='relu')(x) #we add dense layers so that the model can learn more complex functions and classify for better results.
x=Dense(1024,activation='relu')(x) #dense layer 2
x=Dense(512,activation='relu')(x) #dense layer 3
preds=Dense(2,activation='softmax')(x) #final layer with softmax activation
model=Model(inputs=base_model.input,outputs=preds)

使用对象检测进行复杂图像分类方案

for layer in model.layers[:20]:
 layer.trainable=False
for layer in model.layers[20:]:
 layer.trainable=True
Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.6/mobilenet_1_0_224_tf_no_top.h5
17227776/17225924 [==============================] - 13s 1us/step

使用对象检测进行复杂图像分类方案

让我们来看看这个MobileNet模型

使用对象检测进行复杂图像分类方案

处理我们的数据

下面的代码显示了如何使用Keras库在我们的自定义策略上训练自定义MobileNet模型。

训练数据/测试数据

train_datagen=ImageDataGenerator(preprocessing_function=preprocess_input) #included in our dependencies
train_generator=train_datagen.flow_from_directory(
'/data/dataset/Beverages/Train/',
target_size=(224,224),
color_mode='rgb',
batch_size=32,
class_mode='categorical',
shuffle=True)
test_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)
test_generator = test_datagen.flow_from_directory(
 directory=r"/data/dataset/Beverages/Test/",
 target_size=(224, 224),
 color_mode="rgb",
 batch_size=1,
 class_mode='categorical',
 shuffle=False,
 seed=42
)

使用对象检测进行复杂图像分类方案

Found 180 images belonging to 2 classes.
Found 60 images belonging to 2 classes.

使用对象检测进行复杂图像分类方案

查看图像数据样本

i = 0
for data in test_generator:
 if i > 3: break 
 else: i+=1
 img, cls = data
 print(np.argmax(cls))
 plt.imshow(img[0])
 plt.show()

使用对象检测进行复杂图像分类方案

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
0

使用对象检测进行复杂图像分类方案

使用对象检测进行复杂图像分类方案

lipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
0

使用对象检测进行复杂图像分类方案

使用对象检测进行复杂图像分类方案

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
0

使用对象检测进行复杂图像分类方案

使用对象检测进行复杂图像分类方案

Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
0

使用对象检测进行复杂图像分类方案

使用对象检测进行复杂图像分类方案

训练模型

model.compile(optimizer='Adam',loss='categorical_crossentropy',metrics=['accuracy'])
# Adam optimizer
# loss function will be categorical cross entropy
# evaluation metric will be accuracy
step_size_train=train_generator.n//train_generator.batch_size
model.fit_generator(generator=train_generator,
 steps_per_epoch=step_size_train,
 epochs=5)

使用对象检测进行复杂图像分类方案

Epoch 1/5
5/5 [==============================] - 96s 19s/step - loss: 0.8017 - acc: 0.7313
Epoch 2/5
5/5 [==============================] - 77s 15s/step - loss: 0.0101 - acc: 1.0000
Epoch 3/5
5/5 [==============================] - 79s 16s/step - loss: 0.0289 - acc: 0.9937
Epoch 4/5
5/5 [==============================] - 111s 22s/step - loss: 0.0023 - acc: 1.0000
Epoch 5/5
5/5 [==============================] - 87s 17s/step - loss: 0.0025 - acc: 1.0000

使用对象检测进行复杂图像分类方案

基准模型

正如我们在下面看到的,MobileNet是一个非常强大的模型,用于学习和表示我们的玩具政策。

from utils import classification_report
y_true = np.concatenate([np.argmax(test_generator[i][1], axis=1) for i in range(test_generator.n)])
y_pred = np.argmax(model.predict_generator(test_generator, steps=test_generator.n), axis=1)
classification_report(y_true, y_pred)

使用对象检测进行复杂图像分类方案

precision recall f1-score support
 0 1.00 1.00 1.00 30
 1 1.00 1.00 1.00 30
 micro avg 1.00 1.00 1.00 60
 macro avg 1.00 1.00 1.00 60
weighted avg 1.00 1.00 1.00 60
Confusion matrix, without normalization
[[30 0]
 [ 0 30]]
Normalized confusion matrix
[[1. 0.]
 [0. 1.]]

使用对象检测进行复杂图像分类方案

使用对象检测进行复杂图像分类方案

但是,如果我们的策略更加复杂,那么我们以这种方式进行建模可能很困难。

相关推荐