摘要
- 提出YOLO v2 :代表着目前业界最先进物体检测的水平,它的速度要快过其他检测系统(FasterR-CNN,ResNet,SSD),使用者可以在它的速度与精确度之间进行权衡。
- 提出了一种新的联合训练算法( Joint Training Algorithm ),使用这种联合训练技术同时在ImageNet和COCO数据集上进行训练。YOLO9000进一步缩小了监测数据集与识别数据集之间的代沟。这种算法可以把这两种的数据集混合到一起。使用一种分层的观点对物体进行分类,用巨量的分类数据集数据来扩充检测数据集,从而把两种不同的数据集混合起来。 联合训练算法的基本思路就是:同时在检测数据集(COCO)和分类数据集(ImageNet)上训练物体检测器(Object Detectors),用检测数据集的数据学习物体的准确位置,用分类数据集的数据来增加分类的类别量、提升健壮性。
- 提出YOLO9000 :这一网络结构可以实时地检测超过9000种物体分类,这归功于它使用了WordTree,通过WordTree来混合检测数据集与识别数据集之中的数据。 All of our code and pre-trained models are available online at http://pjreddie.com/yolo9000/. 说白了一点,就是YOLOv2是在一个混合的大的数据集合上进行训练,然后在VOC2007数据集合上进行测试结果的。相比较之前的SSD等方法感觉有点不太公平。不过YOLO作者生撸硬调还是值得膜拜的。
BETTER
YOLO一代有很多缺点,作者希望改进的方向是:改善recall,提升定位的准确度,同时保持分类的准确度。YOLO2主要木雕是为了简化网络。
Batch Normalization
使用按批归一化对网络进行优化,让网络提高了收敛性,同时还消除了对其他形式的正则化(regularization)的依赖。通过对YOLO的每一个卷积层增加按批归一化, 最终使得mAP提高了2%,同时还使model正则化。 使用Batch Normalization可以从model中去掉Dropout,而不会产生过拟合。
High resolution classifier
目前业界标准的检测方法,都要先把分类器(classifier)放在ImageNet上进行预训练。从Alexnet开始,大多数的分类器都运行在小于256x256的图片上。而现在YOLO从224x224增加到了448x448,这就意味着网络需要适应新的输入分辨率。 为了适应新的分辨率,YOLO v2的分类网络以448x448的分辨率先在ImageNet上进行Fine Tune,Fine Tune10个epochs,给一定的时间让网络调整他的滤波器(filters),好让其能更好的运行在新分辨率上,还需要调优用于检测的Resulting Network。最终通过使用高分辨率,mAP提升了4%。
Convolution with anchor boxes
YOLO一代包含有全连接层,从而能直接预测Bounding Boxes的坐标值。 Faster R-CNN的方法只用卷积层与Region Proposal Network来预测Anchor Box的偏移值与置信度,而不是直接预测坐标值。作者发现通过预测偏移量而不是坐标值能够简化问题,让神经网络学习起来更容易。所以最终YOLO去掉了全连接层,使用Anchor Boxes来预测 Bounding Boxes。作者去掉了网络中一个Pooling层,这让卷积层的输出能有更高的分辨率。收缩网络让其运行在416416而不是448448。由于图片中的物体都倾向于出现在图片的中心位置,特别是那种比较大的物体,所以有一个单独位于物体中心的位置用于预测这些物体。YOLO的卷积层采用32这个值来下采样图片,所以通过选择416416用作输入尺寸最终能输出一个1313的Feature Map。 使用Anchor Box会让精确度稍微下降,但用了它能让YOLO能预测出大于一千个框,同时recall达到88%,mAP达到69.2%。
Dimension clusters
之前Anchor Box的尺寸是手动选择的,所以尺寸还有优化的余地。 为了优化,在训练集(training set)Bounding Boxes上跑了一下k-means聚类,来找到一个比较好的值。 如果我们用标准的欧式距离的k-means,尺寸大的框比小框产生更多的错误。因为我们的目的是提高先验框的IOU分数,这不能依赖于Box的大小,所以距离度量的使用:
d(box, centroid) = 1 - IOU(box, centroid)
这个地方我就特别想了想如何实现,就扒OpenCV来看看。
static inline float normL2Sqr(const float* a, const float* b, int n)
{
float s = 0.f;
for( int i = 0; i < n; i++ )
{
float v = a[i] - b[i];
s += v*v;
}
return s;
}
class KMeansDistanceComputer : public ParallelLoopBody
{
public:
KMeansDistanceComputer( double *_distances,
int *_labels,
const Mat& _data,
const Mat& _centers )
: distances(_distances),
labels(_labels),
data(_data),
centers(_centers)
{
}
void operator()( const Range& range ) const
{
const int begin = range.start;
const int end = range.end;
const int K = c