1 网络架构
1.1 整体结构
1.1.1 RCNN
(1) 图像中确定约为1000~2000的候选框
(2) 候选框内提取特征
(3) 分类判别候选框
(4) 候选框位置精修,边框回归
参考: 【目标检测】Faster RCNN算法详解
1.1.2 Fast RCNN
(1) 提升测试速度:将图像归一化直接送进网络
(2) 提升训练速度:候选区前几层特征不再重复计算
(3) 减小训练所需空间:类别判断和位置精挑统一用深度网络实现
参考: 【目标检测】Fast RCNN算法详解
1.2 深入细节
1.2.1 RPN
1.2.2 anchor
判断其中心区域是否是物体
参考:
[1] 大缺弦对anchor的回答
[2] 感受野计算
1.2.3 位置精修(边框回归)
(1) 位置回归损失函数:
L
o
s
s
=
∑
i
N
(
t
∗
i
−
w
^
∗
T
ϕ
5
(
P
i
)
)
2
(3.1)
Loss = \sum_i^N(t_*^i - \hat w_*^T\phi_5(P^i))^2 \tag{3.1}
Loss=i∑N(t∗i−w^∗Tϕ5(Pi))2(3.1)其中
t
x
=
(
G
x
−
P
x
)
/
P
w
,
t
y
类
似
(3.2)
t_x=(G_x−P_x)/P_w,t_y类似\tag{3.2}
tx=(Gx−Px)/Pw,ty类似(3.2)
t
w
=
log
(
G
w
/
P
w
)
,
t
h
类
似
(3.3)
t_w = \log (G_w / P_w), t_h类似\tag{3.3}
tw=log(Gw/Pw),th类似(3.3)
其中
t
x
t_x
tx用到归一化思想,而
t
w
t_w
tw用
l
o
g
log
log函数限制尺度大于0,当IOU较大时认为是线性变换
t
w
=
log
(
G
w
/
P
w
)
=
l
o
g
(
G
w
+
P
w
−
P
w
P
w
)
=
l
o
g
(
1
+
G
w
−
P
w
P
w
)
(3.4)
t_w = \log (G_w / P_w) = log(\frac{G_w + P_w - P_w}{P_w}) = log(1 + \frac{G_w-P_w}{P_w})\tag{3.4}
tw=log(Gw/Pw)=log(PwGw+Pw−Pw)=log(1+PwGw−Pw)(3.4)当
G
w
−
P
w
=
0
G_w−P_w=0
Gw−Pw=0是线性函数(因为
l
i
m
x
=
0
l
o
g
(
1
+
x
)
=
x
lim_{x=0}log(1+x) = x
limx=0log(1+x)=x)
(2) 使用smooth L1函数作为回归损失函数的优点:避免L2 loss缺点(对离群点比较敏感);避免L1 loss缺点在0处可能不存在导数,影响收敛.
s
m
o
o
t
h
L
1
=
{
0.5
x
2
∣
x
∣
<
1
∣
x
∣
−
0.5
o
t
h
e
r
w
i
s
e
smoothL1=\begin{cases} 0.5x^2 & |x| < 1 \\ |x| - 0.5 & otherwise \end{cases}
smoothL1={0.5x2∣x∣−0.5∣x∣<1otherwise
参考:
[1] 边框回归
[2] smoothl1损失函数
1.2.4 mAP值计算步骤
(1) precision就是计算模型预测到的所有正例中实际上是正例占的比例,
分母实际上是所有预测到所有该类物体的数目
p
r
e
c
i
s
i
o
n
=
T
P
T
P
+
F
P
(4.1)
precision=\frac{TP}{TP+FP}\tag{4.1}
precision=TP+FPTP(4.1)
而recall是实际上的正例成功预测为正例占比,
分母就是实际上ground truth数目即实际正例数
r
e
c
a
l
l
=
T
P
T
P
+
F
N
(4.2)
recall=\frac{TP}{TP+FN}\tag{4.2}
recall=TP+FNTP(4.2)
(2) 因为IOU容易标准化,而置信度容易影响AP值,所以通过改变置信度来改变recall值
矩形框IOU计算:两个矩形右下角坐标最小的x减去左上角坐标最大的x大于0则有交集(交集不为空),y轴上类似
# --------------------------------------------------------
# Fast R-CNN
# Copyright (c) 2015 Microsoft
# Licensed under The MIT License [see LICENSE for details]
# Written by Sergey Karayev
# --------------------------------------------------------
cimport cython
import numpy as np
cimport numpy as np
def compute_overlap(
np.ndarray[double, ndim=2] boxes,
np.ndarray[double, ndim=2] query_boxes
):
"""
Args
a: (N, 4) ndarray of float
b: (K, 4) ndarray of float
Returns
overlaps: (N, K) ndarray of overlap between boxes and query_boxes
"""
cdef unsigned int N = boxes.shape[0]
cdef unsigned int K = query_boxes.shape[0]
cdef np.ndarray[double, ndim=2] overlaps = np.zeros((N, K), dtype=np.float64)
cdef double iw, ih, box_area
cdef double ua
cdef unsigned int k, n
for k in range(K):
box_area = (
(query_boxes[k, 2] - query_boxes[k, 0] + 1) *
(query_boxes[k, 3] - query_boxes[k, 1] + 1)
)
for n in range(N):
iw = (
min(boxes[n, 2], query_boxes[k, 2]) -
max(boxes[n, 0], query_boxes[k, 0]) + 1
)
if iw > 0:
ih = (
min(boxes[n, 3], query_boxes[k, 3]) -
max(boxes[n, 1], query_boxes[k, 1]) + 1
)
if ih > 0:
ua = np.float64(
(boxes[n, 2] - boxes[n, 0] + 1) *
(boxes[n, 3] - boxes[n, 1] + 1) +
box_area - iw * ih
)
overlaps[n, k] = iw * ih / ua
return overlaps
(3) 按置信度排序,给recall分等级(VOC07分11个等级, 而VOC11后分n个等级,假设m个样本存在n个正例)
(4) 把每个recall等级的precision累加除以n(n个正例有n个等级)就是该类物体的AP值
A
P
=
1
n
∑
i
=
0
n
m
a
x
(
P
r
e
c
a
l
l
>
r
a
n
k
)
AP=\frac{1}{n}\sum_{i=0}^{n}max(P_{recall>rank})
AP=n1i=0∑nmax(Precall>rank)
(5) mAP就是所有AP值的平均值
参考:
[1] 目标检测模型的评估指标mAP详解(附代码)
[2] 目标检测中mAP计算
[3] mAP计算
1.3 其他知识点
1.3.1 奇异值分解
参考:
[1] 奇异值分解(SVD)原理详解及推导
[2] 矩阵的分解:满秩分解和奇异值分解
[3] 一个矩阵列满秩意味着什么
1.3.2 截断正态分布
理解截断意思:截断,并不意味着直接把原始密度函数两边去掉一部分;而是,截断后概率密度函数曲线会有一些变化,使得总面积仍然为1
f
(
x
;
μ
,
σ
,
a
,
b
)
=
1
σ
ϕ
(
x
−
μ
σ
)
Φ
(
b
−
μ
σ
)
−
Φ
(
a
−
μ
σ
)
f(x;\mu,\sigma,a,b) = \frac{\frac{1}{\sigma}\phi(\frac{x - \mu}{\sigma})}{\Phi(\frac{b - \mu}{\sigma}) - \Phi(\frac{a - \mu}{\sigma}) }
f(x;μ,σ,a,b)=Φ(σb−μ)−Φ(σa−μ)σ1ϕ(σx−μ)由累积分布函数有这样的认知
b
→
∞
⇒
Φ
(
b
−
μ
σ
)
=
1
b→∞⇒ Φ(b−μσ)=1
b→∞⇒Φ(b−μσ)=1
a
→
−
∞
⇒
Φ
(
a
−
μ
σ
)
=
0
a→−∞⇒ Φ(a−μσ)=0
a→−∞⇒Φ(a−μσ)=0
意义: 目的是克服饱和函数(像sigmoid),截断正态分布随机数更接近0,在ML当中常希望权重接近0(不过还是难预测)
参考
[1] 正态分布和截断正态分布区别
[2] 理解截断正态分布
2 实践总结
2.1 编译运行
源码分析:参考 Faster R-CNN 源码解析(Tensorflow版)
看的路径:tool中train,test,demo->创建网络的过程(特征提取,rpn,分类和回归)->数据处理和其他部分
2.1.1 编译 tf-faster rcnn
这篇文章对小白非常友好,感谢博主:编译faster rcnn
我的显卡是GTX1050, 安装cuda7.5版本使用的是sm_37(不知道为什么这样也可以)
2.1.2 cuda问题:
anaconda可以安装不同cudatookit但是不能超过它的内核,可以安装各种cudatoolkit,但是关于cuda最重要的内核驱动它并没有安装,无论安装哪个版本的cudatoolkit,都会调用系统的cuda内核
参考:anaconda管理cuda
tensorflow c++编译
tensorflow1.8
2.2 语法和常用API
(1) 使用@property
检查参数属性,有setter
才可读
(2) raise NotImplementedError
预留实现位置,若子类不实现就会报错
(3) argparse(参数解析器)
(4) sys.argv
:是一个列表,第一个元素是sys.argv
所在的python文件名(字符串类型)
(5) *args
传递一个可变参数的列表给函数实参,而**kwargs
则是字典形式,另外*args
在**kwargs
前面
(6) from ast import literal_eval
若进行运算的数据类型在python中存在则进行运算,否则不运算
(7) zip()
将几组可迭代对象的每个元素打包成一对对元组,并返回一个对象, for k, v in zip(a, b)
返回的k, v是a, b的元素
(8) cPickle
中dump
将对象序列化保存到本地的文件中, loads
从字符串变量中再入python对象(cPickle
用法)
(9) [:-1]选取的是除了最后项的所有元素
(10) tf.where(condition, a, b)把张量a中condition为False值的位置的元素用b中的代替,a和b的shape一样;可以结合tf.equal(a, C)使用, C为常数值
(11) tf.gather_nd,可以把向量的某些值提取出来为新的向量