人群密度估计之CSRNet---Dilated Convolutional Neural Networks for Understanding the Highly Congested Scenes
作者:互联网
从广义上讲,目前有四种方法来计算人群中的人数:
1.基于检测的方法
在这里,即使用移动的窗口式探测器来识别图像中的人并计算其中的人数。用于检测的方法需要经过良好训练的分类器,其可以提取低级特征。尽管这些方法适用于检测面部,但它们在拥挤的图像上表现不佳,因为大多数目标对象不清晰可见。
2.基于回归的方法
我们无法使用上述方法提取低级功能,所以基于回归的方法在这方面就胜出了。我们首先从图像中裁剪补丁,然后为每个补丁提取低级特征。
3.基于密度估计的方法
我们首先为对象创建密度图。然后,该算法学习提取的特征与其对象密度图之间的线性映射。我们还可以使用随机森林回归等机器学习算法来学习输入输出之间的非线性映射关系。
4.基于CNN的方法
我们不是查看图像的补丁,而是使用CNN构建端到端的回归方法。这将整个图像作为输入并直接进行人群计数。 CNN在回归或分类任务方面运作良好,并且它们也证明了它们在生成密度图方面的价值。
CSRNet是我们将在本文中实现的一个模型,它可以部署更深入的CNN,用于捕获高级特征并生成高质量的密度图,而不会扩展网络复杂性。在深入代码部分之前,让我们先了解CSRNet。
论文中先提出了一些针对MCNN的实验,发现 MCNN 中过多的参数用于对输入图片的进行密度水平分类,然后通过实验中证明了MCNN中不同的通道收集到的特征差距不大,从而验证了MCNN中冗杂的网络结构是没有必要的。
论证图如下:
关于密度图的生成问题,采用了与MCNN中相同的策略,论文中直接用了MCNN里边生成.mat文件的方法,然后再生成.h5文件用于产生真值,此处有一个我认为比较好的关于生成过程的相关讲解:
高斯模糊算法:https://blog.csdn.net/farmwang/article/details/74452750
论文中采用的数据增强方式为:
将一张图片裁剪为9个部分,每个部分占1/4,前4个部分互相之间不重叠,后面5个随机。最后将这9张图片再镜像对称一下。
论文还提出了ablation study:即模型简化测试。
看看取消掉一些模块后性能有没有影响。 根据奥卡姆剃刀法则,简单和复杂的方法能达到一样的效果,那么简单的方法更可靠。
实际上ablation study就是为了研究模型中所提出的一些结构是否有效而设计的实验。 比如你提出了某某结构,但是要想确定这个结构是否有利于最终的效果,那就要将去掉该结构的网络与加上该结构的网络所得到的结果进行对比,这就是ablation study。
**
CSRNet的网络架构:
**
CSRNet使用已训练好的VGG-16的前13层网络作为前端,其中包括了10个卷积层和3个池化层(max-pooling)。因为有3个filter=2 x 2、stride=2的池化层,且卷积都是使用了padding=1、stride=1、filter=3 x 3的卷积层,所以 VGG-16的输出大小是原始输入大小的1/64, 比如原来是64 x 64, 输出就变成了8 x 8,同时,去掉了全连接层以适应输入图片尺寸变化。
CSRNet在后端使用了空洞卷积层(或者叫膨胀卷积层),这个要说的话篇幅就太长了,它的作用就是不通过pooling也能有较大的感受野,相比于传统的先池化再卷积再上采样的操作,这样做避免了由于池化产生的精度上的损失。原文说的是:deploy dilated convolutional layers as the back-end for extracting deeper information of saliency as well as maintaining the output resolution
参考下面的图像:
-
空洞卷积
-
空洞卷积与传统操作的优劣(通过他们提取的特征图的细节比较):
**
接下来就是把模型跑起来:
**
我们将在ShanghaiTech数据集上训练CSRNet。 这包含1198个注释图像,总共330,165人。
使用以下代码块克隆CSRNet-pytorch的官方存储库。 这包含用于创建数据集,训练模型和验证结果的完整代码:
git clone https://github.com/leeyeehoo/CSRNet-pytorch.git
请在继续操作之前按照官方github上的配置安装CUDA和PyTorch等。
现在,将数据集移动到上面克隆的存储库中并解压缩。
文件里边的 make_dataset.ipynb 用来创建基本真值(ground_truth)。
是先用MCNN里边的生成真值的文件来生成.mat(Matlab文件格式)文件,然后再是用这个来生
成.h5文件。
你需要改一下文件的路径(换成自己的路径),如下所示:
为每个图像生成密度图是一个耗时的步骤。 因此,在代码运行时,冲泡一杯咖啡。
到目前为止,我们已经为part_A_final中的图像生成了基本真值。 接下来请自行为part_B_final 图像训练集执行相同的操作。
让我们看一个示例图像并绘制其地面真实热图:
260就是该图的人数
**
训练模型开始了
**
现在,我们有图像以及相应的真值(ground_truth)。 是时候训练我们的模型!
我们将使用克隆目录中提供的.json文件。 我们只需要更改json文件中图像的位置。 为此,请打开.json文件,并将当前位置替换为图像所在的位置(建议用libreoffice 批量操作)。
请注意,所有这些代码都是用Python 2.7编写的。如果您正在使用任何其他Python版本,请进行以下更改:
比如python 3:
在model.py中,将第18行中的xrange更改为range
更改model.py中的第19行:list(self.frontend.state_dict().items())[i][1].data[:] = list(mod.state_dict().items())[i][1].data[:]
在image.py中,将ground_truth替换为ground_truth
把 image.py 中倒数第二行 cv2.resize(target,(target.shape[1]/8,target.shape[0]/8)。。。单除号‘ / ’换成’’ // ‘’.因为要进行取整操作。
现在,进入 你放置 CSRNet-pytorch库的文件夹位置,然后在这里打开终端
执行以下命令:
在这里,说两句:
- 源码里边默认是不开启数据增强的,但是路径还是重复了4遍。。。所以,这样跑下去一定会过拟合,观察是否过拟合:看你每跑完一个 epoch 后都会输出一个mae 的值,如果这个值小于65了,就基本上是过拟合了(因为官方最好也就66)。更改方法就是看得懂源码的自己去改一下源码,只想随便跑一下的去把train.py中能够的epoch数减小就好了,大概减到100左右就好点了。
2.下面这行代码,part_A_train.json是训练集,part_A_val.json是验证集,官方的意思是,你最后需要合并出自己的验证集和训练集。
python train.py part_A_train.json part_A_val.json 0 0
再次,请坐下来,因为这需要很多时间。 您可以通过减少 train.py 文件中的纪元数以加速该过程。 如果您不想等待,可以选择下载预先训练好的权重(该项目的github 上有,就是下载CSRNet的地方,不过要翻墙)
最后,让我们检查模型的实际表现。 我们将使用val.ipynb文件来验证结果。
进入val.ipynb,然后添加部分代码,位置以及代码如图(记得修改路径):
mae = 0
for i in range(len(img_paths)):
img = transform(Image.open(img_paths[i]).convert('RGB')).cuda()
gt_file = h5py.File(img_paths[i].replace('.jpg','.h5').replace('images','ground_truth'),'r')
groundtruth = np.asarray(gt_file['density'])
output = model(img.unsqueeze(0))
mae += abs(output.detach().cpu().sum().numpy()-np.sum(groundtruth))
print (mae/len(img_paths))
以及:
from matplotlib import cm as c
path = '/home/ao_han/文档/program/CSRNet/Shanghai/part_A_final/test_data/images_train/1.jpg'
img = transform(Image.open(path).convert('RGB')).cuda()
output = model(img.unsqueeze(0))
print("Predicted Count : ",int(output.detach().cpu().sum().numpy()))
temp = np.asarray(output.detach().cpu().reshape(output.detach().cpu().shape[2],output.detach().cpu().shape[3]))
plt.imshow(temp,cmap = c.jet)
plt.show()
temp = h5py.File('/home/ao_han/文档/program/CSRNet/Shanghai/part_A_final/test_data/ground_truth/IMG_100.h5', 'r')
temp_1 = np.asarray(temp['density'])
plt.imshow(temp_1,cmap = c.jet)
print("Original Count : ",int(np.sum(temp_1)) + 1)
plt.show()
print("Original Image")
plt.imshow(plt.imread(path))
plt.show()
位置如下图所示:
此时的MAE值为65.966,这已经非常好了。
这是它生成的预测图和真值图的区别:
其实,,,这是我从它github上下载下来的它的模型(即已经跑好了的模型)
下面,看看我自己跑的(2080ti 跑了一天左右,这个是最初没有跑的,数据增强没有开启,过拟合了结果。。。):
这是测试的结果:
现在让我们检查单个图像上的预测:
看到没有,,,这个MAE这么大。。。
到此,模型已经建立完毕。
大家可以关注我一下(狗头保命),我会一直跟进人群技术这方面的最新进展,下一篇是CSRNet 的源码解析(pytorch版本的),再下一篇是SFCN (CVPR2019)。
本文基于该博客改进:https://blog.csdn.net/weixin_41697507/article/details/89436973
标签:Convolutional,密度估计,img,Dilated,卷积,CSRNet,图像,output,part 来源: https://blog.csdn.net/weixin_44585583/article/details/95865143