Skip to content

使用 tensorflow2 实现的 yolov2 算法(you only look once)

Notifications You must be signed in to change notification settings

970814/yolov2-by-tf2

Repository files navigation

yolov2 by tf2


使用 tensorflow2.0 实现的 YOLO(you only look once) v2算法

YOLO 是一个实时目标检测系统

该项目实现了该系统的全部细节,包括模型构建、Loss函数、目标检测、以及如何从零训练一个目标检测系统,以便扩展至训练自定义的目标检测系统。


算法效果

检测结果


如何使用

环境要求

  1. Anconda 2020.11
  2. Conda 4.9.2
  3. Python 3.7.10
  4. Tensorflow 2.0.0

  1. 检测图片中的目标
python test_tect.py
  1. 保存yolo_v2模型
python save_model.py
  1. 使用保存的yolo_v2模型检测图片
python load_model_and_test_detect.py
  1. 从零训练网络,在2个样本的训练集上训练一个过拟合的模型
python train_model_overfit.py
  1. 使用前面训练的过拟合模型进行目标检测
python load_overfit_model_and_test_detect.py

算法原理


1. 网络架构

2. 网络的输出


网络最终输出一个(19,19,425)的张量,我们可以将其转换成(19,19,5,85)的张量, 其中[i,j,a,:]表示在第[i,j]单元格的第aanchor-box的预测结果,由4部分组成

  1. [0:2] 存储了对象中心在单元格内的位置(x,y)坐标
    • 经过sigmoid函数映射,范围限制在0~1
  2. [2:4] 存储了对象的宽高(w,h)
    • 经过exp函数映射得到关于对应anchor-box的宽高系数,必须大于0
  3. [4:5] 存储了该anchor-box包含对象的置信度(概率)
    • 经过sigmoid函数映射,范围限制在0~1
  4. [5:85] 存储了该anchor-box包含的对象关于80个类别的概率分布
    • 经过softmax归一化,范围限制在0~1,总和为1

注意网络输出值并没有经过上面所描述的映射,也就是说我们让网络学会的是这些函数的输入值。


3. 人工标签

维度是(K,5)的张量,K为图片中包含的对象数量,每个对象由3部分决定

  1. [0:2] 存储了对象中心在整张图片的相对位置(lx,ly),范围在0~1
  2. [2:4] 存储了对象的宽高(lw,lh),范围在0~1
  3. [4:5] 存储了对象的类别class,范围在0~79

4. 人工标签转换

人工标签的维度是(K,5),显然与网络输出维度不符合,为了计算网络loss,我们将 人工标签转换得到(19,19,5)维度的张量detectors_mask(19,19,5,5)维度的张量matching_true_boxes


  1. detectors_mask

元素为bool类型,detectors_mask[i,j,a]True, 则表明在第[i,j]单元格的第aanchor-box的存在对象


  1. matching_true_boxes

detectors_mask[i,j,a]True, 则matching_true_boxes[i,j,a,:]存储了对象信息,由3部分决定

  1. [0:2] 存储了对象中心在单元格内的位置(x,y)坐标
    • 变换规则,(lx,ly) * (19,19) = (19lx ,19ly) = (u,v)(x,y) = (u,v) - floor((u,v))
  2. [2:4] 存储了对象的宽高(w,h),与网络输出的宽高含义一致
    • 变换规则,(lw,lh) ⊙ (19,19) = (19lw ,19lh) = (p,q)(w,h) = log((p,q) / (anchorW,anchorH))
  3. [4:5] 存储了对象的类别class,范围在0~79
    • 可以使用one_hot函数转换成相应的softmax标签

5. Loss函数计算

loss


Loss = 识别Loss+分类Loss+定位Loss,均采用平方差Loss,上述表达式中detectors_mask 前面提到过

  1. object_detections

object_detections(i,j,a)True,表示该位置预测框与一个真实对象框很吻合(具体是IOU>threshold=0.6) ,此时即使该位置本不应存在对象即detectors_mask(i,j,a)=False也不做no-obj loss计算。原因如下:

  • 训练网络的时候,人工标注的对象是分配到一对(grid cell,anchor-box)中,然而一个单元格中包含多个anchor-box, 实际上如果存在一个目标形状和多个anchor-box都接近(IOU接近),那么对象具体分配到哪一个anchor-box都是合理的, 因此网络在多个位置都输出了预测框也都是合理的,尽管我们标注的位置仍然只会选择一个最优IOU(grid cell,anchor-box)位置, 因此我们可以放宽要求,如果在人工标注位置的附近网络也说存在对象,并且预测框和人工标注框很吻合,那么我们将既不惩罚也不激励网络,保持中立。 并且这些多余的预测结果可被非最大值印制算法滤去。 另外一方面如果我们要求的输出非常严格,对这些地方进行 no-obj loss惩罚,这样会拥有太多的负例,因为一张图片, 网络将预测19*19*5=1805个框,通常人工标注的对象少于100个,那么负例将会是1705个,这可能导致网络最终学会了检测某个位置无对象。

  1. 4个权重系数,这里实现上分别取值为lambda_obj=5lambda_noobj=1lambda_coord=1lambda_class=1

  2. 字母N表示类别的数量,yolov2系统中是80


6. 随机梯度下降减少Loss值

0

1

2

3

4

5

6

7

8

9

10


关于反向传播算法如何计算参数梯度的实现可以参考我的另外两个项目实现

如果使用tensorflow框架,梯度计算将由框架自动完成,意味着我们只需要实现向前传播算法和损失函数,这是使用框架实现模型的一个极大好处。


7. 进行预测

输入图片是一个(608,608,3)的张量,经过我们训练的D-CNN(具有23个卷积层的深度卷积网络)后, 网络最终输出一个(19,19,425)的张量,转换成(19,19,5,85)的张量,也就是(19,19,5)个目标检测结果, 其中每个检测结果有 该位置存在对象的置信度conf = [4:5]80个类别的概率分布prob=[5:85], 因此每个类别的得分为score = conf * prob,然后我们取得分最高的类别作为检测结果, 因为有(19,19,5)个目标检测结果,因此有19*19*5=1805个得分,我们过滤掉得分较低的预测(score<threshold=0.6), 剩下的都是具有较高得分的检测结果,但因为训练时,我们没惩罚包含对象的附近的检测结果,因此网络存在多位置检测同一个对象的可能, 所以接下来我们对各个类使用非最大值印制算法过滤,得出最终的目标检测结果。这部分原理和实现可以 参考utils.py文件中的convert_filter_and_non_max_suppression函数


参考资料

About

使用 tensorflow2 实现的 yolov2 算法(you only look once)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages