使用 Convnet 的对象中心检测总是返回图像的中心而不是对象的中心

Posted

技术标签:

【中文标题】使用 Convnet 的对象中心检测总是返回图像的中心而不是对象的中心【英文标题】:Object center detection using Convnet is always returning center of image rather than center of object 【发布时间】:2018-08-14 00:37:24 【问题描述】:

我有一个约 150 张图像的小型数据集。每个图像都有一个放置在地板上的对象(白色和黑色的矩形框)。所有图像中的对象都相同,但地板的图案不同。目标是训练网络找到图像的中心。每张图片的维度为256x256x3

Train_X 的大小为150x256x256x3,Train_y 的大小为150x2(这里的150 表示图像总数)

我知道 150 张图像是一个太小的数据集,但我可以放弃一些准确性,因此我在 Conv 网络上训练了数据。这是我使用的convnet的架构

Conv2D 层(过滤器大小为 32) 激活Relu Conv2D 层(过滤器大小为 64) 激活Relu 平面层 密集(64)层 激活Relu 密集(2) 激活 Softmax model.compile(loss='mse', optimizer='sgd')

观察:即使在训练数据上,训练模型也总是返回图像 0.5,0.5 的归一化中心作为“对象”的中心。当我在 train_X 上运行预测函数时,我希望得到一个矩形对象的中心而不是图像的中心。由于我的转换层选择,我得到了这个输出吗?

【问题讨论】:

尝试将激活切换到sigmoid。当您使用 softmax 时,您会在输出中添加一个虚假条件 - 主要是 - 坐标总和为 1 我也试过 softmax 但结果是一样的。我不确定为什么所有训练集和测试集的预测值都将归一化的图像中心作为对象的中心。 softmaxsigmoid? 我的意思是说我也尝试过使用 sigmoid。仍然将归一化中心作为预测输出。也尝试了 MSE、ASE 作为损失函数,但仍然遇到同样的问题 【参考方案1】:

我认为在最后几层中使用“SoftMax”激活是您的网络性能不佳的主要原因,因此您可以使用 Relu 或任何其他线性激活或使用非激活。我还建议您使用 PreTrained 网络中间输出,例如 VGG,这样您就不需要训练 Conv 部分而只需训练密集部分。如果您的数据很少,您可以使用 keras 图像生成器来增强更多图像,如下所示。

(x_train, y_train), (x_test, y_test) = cifar10.load_data()
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)
datagen = ImageDataGenerator(
    featurewise_center=True,
    featurewise_std_normalization=True,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(x_train)
# fits the model on batches with real-time data augmentation:
model.fit(datagen.flow(x_train, y_train, batch_size=32),
          steps_per_epoch=len(x_train) / 32, epochs=epochs)
# here's a more "manual" example
for e in range(epochs):
    print('Epoch', e)
    batches = 0
    for x_batch, y_batch in datagen.flow(x_train, y_train, batch_size=32):
        model.fit(x_batch, y_batch)
        batches += 1
        if batches >= len(x_train) / 32:
            # we need to break the loop by hand because
            # the generator loops indefinitely
            break

所以总结一下就是这样做:

删除 Softmax 激活或使用 ReluLeakyRelu 等线性激活。 使用预训练网络进行特征提取。 使用图像增强创建更多图像。

【讨论】:

【参考方案2】:

您基本上是在尝试解决回归问题。除了您所做的之外,您还可以尝试其他一些事情:

    使用ImageAugmentation 技术生成更多数据。此外,标准化图像。 使用更多的卷积层制作更深的模型。 对卷积层使用适当的权重初始化器可能是 He-normal。 在层之间使用BatchNormalization 使过滤器值的meanstd 分别等于0 和1。 使用交叉熵损失,因为它有助于更​​好地计算梯度。在 MSE 中,梯度随着时间的推移变得非常小,尽管它似乎更适合回归问题。 尝试将优化器更改为 Adam。 如果您的数据集中有更多类,并且存在类不平衡问题,您可以使用 Focal loss,这是一种交叉熵损失的变体,它对错误分类的标签的惩罚比正确分类的标签更大分类标签。此外,减少批量大小上采样应该会有所帮助。 使用贝叶斯优化技术对模型进行超参数调优。

示例模型代码:

with open(os.path.join(DATA_DIR, 'mnist.pickle'), 'rb') as fr:
    X_train, Y_train, X_val, Y_val = pickle.load(fr)
X_train = X_train.reshape(60000, 784)
X_val = X_val.reshape(10000, 784)
X_train = X_train.astype('float32')
X_val = X_val.astype('float32')
X_train /= 255
X_val /= 255
nb_classes = 10
Y_train = to_categorical(Y_train, nb_classes)
Y_val = to_categorical(Y_val, nb_classes)
return X_train, Y_train, X_val, Y_val

def build_model(input_shape, dropout=True):
    model = Sequential()
    model.add(Conv2D(32, (5,5), activation='relu', kernel_initializer='he_uniform', padding='valid', input_shape=input_shape))
    model.add(BatchNormalization())
    model.add(MaxPooling2D((2,2), strides=1, padding='valid'))
    if dropout:
        model.add(Dropout(0.2))
    model.add(Conv2D(64, (3,3), activation='relu', kernel_initializer='he_uniform', padding='valid'))
    model.add(Conv2D(128, (3,3), activation='relu', kernel_initializer='he_uniform', padding='valid'))
    model.add(BatchNormalization())
    model.add(MaxPooling2D((2,2), strides=2, padding='valid'))
    if dropout:
        model.add(Dropout(0.2))
    model.add(Flatten())
    model.add(Dense(100, activation='relu', kernel_initializer='he_uniform'))
    model.add(BatchNormalization())
    model.add(Dense(classes, activation='softmax', kernel_initializer='he_uniform'))
    # optimizer = SGD(lr=0.01, decay-1e-6, momentum=0.9)
    optimizer = Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=None, decay=0.0, amsgrad=False)
    model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
    return model

【讨论】:

【参考方案3】:

由于您没有在详细信息中提及它,以下建议(如果您尚未实施)可能会有所帮助:

1) 规范化输入数据(例如,如果您正在处理输入图像,x_train = x_train/255 在将输入馈送到层之前)

2) 尝试对最后一个输出层进行线性激活

3) 在更高的时期运行拟合,并尝试不同的批量大小

【讨论】:

以上是关于使用 Convnet 的对象中心检测总是返回图像的中心而不是对象的中心的主要内容,如果未能解决你的问题,请参考以下文章

使用 PyTorch 的多标签、多类图像分类器 (ConvNet)

OpenCV 对象检测 - 中心点

如何从图像中检测和裁剪对象?

Tensorflow:如果我有一个训练有素的 MNIST 模型,我如何检测图像中的手写数字?

掌握可视化卷积神经网络模型,带你畅游图像识别技术领域

论文解读1——Rich feature hierarchies for accurate object detection and semantic segmentation