基于MSCNN的人群密度估计之密度等级分类网络

密度等级分类网络

基于MSCNN的人群密度估计:

分类目标

密度分类网络的目的是根据数据集的情况先将图片进行粗略分类,过滤出不同等级的人员密度,减轻人数估计网络训练的难度和提高准确度。密度等级被分成3类,分别为无(图片中不包含人)、低密度(图片中包含1到99个人)、高密度(人数大于100),使用0,1,2作为类别标签,采用one-hot编码,使用交叉熵作为网络的损失函数。

网络架构

由于分类目标简单,所以使用去掉全连接层的vgg16网络作为特征提取网络,后面接3个自定义的全连接层最后分类输出。vgg16网络固定不参与训练,只训练自定义的三层全连接网络。在加载vgg16的时候,需要预先下载好训练好的模型,这里需要注意的地方是如果不加载vgg的输出层即代码中的"include_top=False"则下载的模型是"vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5",否则是"vgg16_weights_tf_dim_ordering_tf_kernels.h5",我已将本次用的模型上传到我的百度网盘,请在项目主页上查看。

    def model(self):
        # finetune from the base model VGG16
        base_model = VGG16(include_top=False,
                           weights=self.vgg_weights_path,
                           input_shape=(224, 224, 3))
        # base_model.summary()
        out = base_model.layers[-1].output
        out = layers.Flatten()(out)
        out = layers.Dense(1024, activation='relu')(out)
        # 因为前面输出的dense feature太多了,我们这里加入dropout layer来防止过拟合
        out = BatchNormalization()(out)
        out = layers.Dropout(0.5)(out)
        out = layers.Dense(512, activation='relu')(out)
        out = layers.Dropout(0.3)(out)
        out = layers.Dense(128, activation='relu')(out)
        out = layers.Dropout(0.3)(out)
        out = layers.Dense(3, activation='softmax')(out)
        tuneModel = Model(inputs=base_model.input, outputs=out)

        # vgg层不参与训练
        for layer in tuneModel.layers[:19]:
            layer.trainable = False

        return tuneModel

训练代码:

    def train(self, args_):
        tuneModel = self.model()
        tuneModel.compile(loss='categorical_crossentropy',
                          optimizer=optimizers.Adam(lr=3e-4))
        if os.path.exists(self.weights_path):
            tuneModel.load_weights(self.weights_path, by_name=True)
            print('success load weights ')

        batch_size = int(args_['batch'])
        callbacks = self.get_callbacks()
        history = tuneModel.fit_generator(DenseDataset().gen_train(batch_size, 224),
                                          steps_per_epoch=DenseDataset().get_train_num() // batch_size,
                                          validation_data=DenseDataset().gen_valid(batch_size, 224),
                                          validation_steps=DenseDataset().get_valid_num() // batch_size,
                                          epochs=int(args_['epochs']),
                                          callbacks=callbacks)
        if args_['show'] != 'no':
            self.train_show(history)

唯一需要注意的地方是在生成训练数据的时候标签应该是one-hot编码的,而标签工具保存的值是"0,1,2"所以在数据生成器里需要将"0,1,2"转成ont-hot编码。keras提供了转换的API keras.utils.to_categorical(),具体代码请参加https://github.com/zzubqh/CrowdCount/src/data.py

     while True:
         if i + batch_size >= n:
             np.random.shuffle(index_all)
             i = 0
             continue
         batch_x, batch_y = [], []
         for j in range(i, i + batch_size):
             x, y = self.get_img_data(index_all[j], size)
             batch_x.append(x)
             batch_y.append(y)
         i += batch_size         
         yield np.array(batch_x), to_categorical(np.array(batch_y), num_classes=3)

在训练了20个epcho后得到96%的正确率,分类测试结果如下:
在这里插入图片描述测试的时候发现有些大于100的图片被误分到了0类,后续这里需要改进!

发布了63 篇原创文章 · 获赞 55 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_36810544/article/details/104158591
今日推荐