Keras分类-物体检测

18

我正在使用Keras和Python进行分类和物体检测,已经成功将猫/狗的分类准确率达到80%以上,暂时对此结果满意。我的问题是如何从输入图像中检测猫或狗?我感到完全困惑。我想使用自己的高度而不是从互联网上预训练的高度。

这是目前我的代码:

from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img

#########################################################################################################
#VALUES
# dimensions of our images.
img_width, img_height = 150, 150

train_data_dir = 'data/train'
validation_data_dir = 'data/validation'
nb_train_samples = 2000 #1000 cats/dogs
nb_validation_samples = 800 #400cats/dogs
nb_epoch = 50
#########################################################################################################

#MODEL
model = Sequential()
model.add(Convolution2D(32, 3, 3, input_shape=(3, img_width, img_height)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Convolution2D(32, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Convolution2D(64, 3, 3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))

model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])


# this is the augmentation configuration we will use for training
train_datagen = ImageDataGenerator(
        rescale=1./255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True)
##########################################################################################################
#TEST AUGMENTATION
img = load_img('data/train/cats/cat.0.jpg')  # this is a PIL image
x = img_to_array(img)  # this is a Numpy array with shape (3, 150, 150)
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 3, 150, 150)

# the .flow() command below generates batches of randomly transformed images
# and saves the results to the `preview/` directory
i = 0
for batch in train_datagen.flow(x, batch_size=1,
                          save_to_dir='data/TEST AUGMENTATION', save_prefix='cat', save_format='jpeg'):
    i += 1
    if i > 20:
        break  # otherwise the generator would loop indefinitely
##########################################################################################################
# this is the augmentation configuration we will use for testing:
# only rescaling
test_datagen = ImageDataGenerator(rescale=1./255)

#PREPARE TRAINING DATA
train_generator = train_datagen.flow_from_directory(
        train_data_dir, #data/train
        target_size=(img_width, img_height),  #RESIZE to 150/150
        batch_size=32,
        class_mode='binary')  #since we are using binarycrosentropy need binary labels

#PREPARE VALIDATION DATA
validation_generator = test_datagen.flow_from_directory(
        validation_data_dir,  #data/validation
        target_size=(img_width, img_height), #RESIZE 150/150
        batch_size=32,
        class_mode='binary')


#START model.fit
history =model.fit_generator(
        train_generator, #train data
        samples_per_epoch=nb_train_samples,
        nb_epoch=nb_epoch,
        validation_data=validation_generator,  #validation data
        nb_val_samples=nb_validation_samples)


model.save_weights('savedweights.h5')
# list all data in history
print(history.history.keys())

#ACC VS VAL_ACC
plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy ACC VS VAL_ACC')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
# summarize history for loss
#LOSS VS VAL_LOSS
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss LOSS vs VAL_LOSS')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()


model.load_weights('first_try.h5')

现在我已将猫和狗分类,接下来我需要怎么做才能输入一张图片,并对其进行处理以找到其中的猫或狗,并用边界框标出来呢?我完全是新手,甚至不确定我是否以正确的方式解决了这个问题。 谢谢。

更新 抱歉晚些才发布结果,前几天无法工作。 我正在导入一张图像并将其重塑为1,3,150,150的形状,因为150,150的形状会出现错误:

Exception: Error when checking : expected convolution2d_input_1 to have 4 dimensions, but got array with shape (150L, 150L)

导入图像:

#load test image
img=load_img('data/prediction/cat.155.jpg')
#reshape to 1,3,150,150
img = np.arange(1* 150 * 150).reshape((1,3,150, 150))
#check shape
print(img.shape)

然后我已经将def predict_function(x)更改为:

def predict_function(x):
    # example of prediction function for simplicity, you
    # should probably use `return model.predict(x)`
   # random.seed(x[0][0])
  #  return random.random()
   return model.predict(img)

现在当我运行:
best_box = get_best_bounding_box(img, predict_function)
print('best bounding box %r' % (best_box, ))

我得到的输出为最佳边界框:无

所以我只运行了:

model.predict(img)

并获得以下内容:

model.predict(img)
Out[54]: array([[ 0.]], dtype=float32)

所以它根本不检查是猫还是狗... 有什么想法吗?

注意:当def predict()function(x)使用时:

random.seed(x[0][0])
   return random.random()

我确实得到输出结果,它勾选复选框并选择最佳结果。

1个回答

18
您构建的机器学习模型和您想要实现的任务并不相同。该模型尝试解决分类任务,而您的目标是检测图像中的对象,这是一项对象检测任务
分类问题具有布尔问题,而检测问题具有不止两个答案。
你可以尝试以下三种可能性:


1. 使用滑动窗口结合您的模型

裁剪定义大小的框(例如从20X20到160X160)并使用滑动窗口。对于每个窗口,尝试预测它是狗的概率,并最终选择您预测的最大窗口。

这将生成多个边界框候选项,您将使用获得的最高概率选择边界框。

这可能会很慢,因为我们需要在数百个样本上进行预测。

另一个选项是尝试在您的网络之上实现RCNN另一个链接)或Faster-RCNN网络。这些网络基本上减少了要使用的边界框窗口候选数。

更新 - 计算滑动窗口示例

以下代码演示如何执行滑动窗口算法。您可以更改参数。

import random
import numpy as np

WINDOW_SIZES = [i for i in range(20, 160, 20)]


def get_best_bounding_box(img, predict_fn, step=10, window_sizes=WINDOW_SIZES):
    best_box = None
    best_box_prob = -np.inf

    # loop window sizes: 20x20, 30x30, 40x40...160x160
    for win_size in window_sizes:
        for top in range(0, img.shape[0] - win_size + 1, step):
            for left in range(0, img.shape[1] - win_size + 1, step):
                # compute the (top, left, bottom, right) of the bounding box
                box = (top, left, top + win_size, left + win_size)

                # crop the original image
                cropped_img = img[box[0]:box[2], box[1]:box[3]]

                # predict how likely this cropped image is dog and if higher
                # than best save it
                print('predicting for box %r' % (box, ))
                box_prob = predict_fn(cropped_img)
                if box_prob > best_box_prob:
                    best_box = box
                    best_box_prob = box_prob

    return best_box


def predict_function(x):
    # example of prediction function for simplicity, you
    # should probably use `return model.predict(x)`
    random.seed(x[0][0])
    return random.random()


# dummy array of 256X256
img = np.arange(256 * 256).reshape((256, 256))

best_box = get_best_bounding_box(img, predict_function)
print('best bounding box %r' % (best_box, ))

示例输出:

predicting for box (0, 0, 20, 20)
predicting for box (0, 10, 20, 30)
predicting for box (0, 20, 20, 40)
...
predicting for box (110, 100, 250, 240)
predicting for box (110, 110, 250, 250)
best bounding box (140, 80, 160, 100)


2. 为目标检测任务训练新网络

您可以查看包含20个类别的Pascal数据集 (这里有示例),其中两个类别是猫和狗。

该数据集将对象位置作为Y目标。


3. 使用现有网络完成此任务

最后但并非最不重要的,您可以重复使用现有网络,甚至可以通过“知识转移”(keras示例在此处)为特定任务做准备。

请查看以下convnets-keras库。

因此,请选择您最佳的方法,并向我们更新结果。


非常感谢您的回复!!! 我会先尝试滑动窗口,您能否给一个示例代码来说明如何做?抱歉,我很新手Python和Keras。 - Powisss
1
我已经添加了虚拟窗口的示例,希望能有所帮助,请在结果上进行更新。 - ShmulikA
我会尝试的,谢谢您。我会在这里留下结果反馈! - Powisss
我已经更新了问题并发布了结果,大家有什么想法现在是出了什么问题吗?;/ - Powisss
尝试使用model.predict([x]),但您仍需要调整输入图像的大小以适应模型输入向量的大小。我建议您打开另一个问题来帮助您解决这个特定问题。 - ShmulikA
谢谢user7438048,我会开一个新的线程。但是你的方案是正确的,我将把它标记为答案。再次感谢! - Powisss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接