继上篇《基于几何特征的地面点云分割》之后,本文紧接着对其他地面点分割方法进行了研究,在最近的英伟达开发者大会(Nvidia GTC)上,获悉了一篇使用时空条件随机场方法(SpatioTemporal Conditional Random Fields)对地面点云进行分割方法(详情请见本博客翻译博文《Ground Estimation and Point Cloud Segmentation using SpatioTemporal Conditional Random Field(精读)》),此论文早在2017年就发表了,只是最近才通过GTC大会得知,然后通过作者找到了2017年的完整论文,遂决定进行尝试,有关于这篇论文的信息请根据本博客中论文翻译博文按需阅读。
关于条件随机场前期知识本文也会相应给出,之前没有这方面知识储备的同学可根据本文的预备知识章节链接,对相应的知识进行恶补。笔者绘制了此篇论文的知识结构树,如下图所示。本文就条件随机场知识在第1章进行粗略的阐述,如果已经具备条件随机场知识的同学移步第2章。
基于时空条件随机场进行地面点云分割知识谱逻辑图
预备知识
1. 空间地面模型
1.1 概率无向图模型
1.2 条件随机场
- 如何用简单易懂的例子解释条件随机场(CRF)模型?它和HMM有什么区别?
- 马尔科夫网络
- 室外场景三维点云数据的分割与分类P46
- 条件随机场-百度文库
- Conditional Random Field wiki
2. 推断求解
2.1 高斯模型
2.2 期望最大化算法(EM)
1. 条件随机场
1.1 条件随机场理论
条件随机场(Conditional Random Field, CRF)最初是由Laffery提出,用于对词性的分类,它是在最大熵模型和隐马尔科夫模型的基础上提出的一种判别式概率模型。条件随机场就是在假设输出变量具有马尔科夫性的前提下,利用给定的一组随机变量的条件来推断另一组随机变量的条件概率分布模型。由于本文的条件随机场主要用于三维点云的分类,所以,本文将主要讨论线性链条件随机场(Linear Chain Conditional Random Field)。
由于条件随机场是无向图模型的一种,故它满足无向图模型的任何属性,常常用 XX 和 YY 分别表示观察序列和与之对应的标记序列联合分布随机变量。在条件随机场的很多应用当中,都存在着一个隐过程,比如说在进行文本分类的过程中,就可以假设一段文本的标签只和该段文本的特征以及与该文本相连的链入链出等超链接有关,而与其他的因素没有任何关系。在应用条件随机场的过程中,有两项工作需要去做:一个是学习,一个是推断(类似与神经网络,学习出一个概率模型,然后用概率模型去判断新的无标记样本)。
(1) 学习: 给定一定量的观察序列集 X={X1,X2,...,Xn}X={X1,X2,...,Xn}, 以及与观察序列相对应的标签集 Y={Y1,Y2,...,Yn}Y={Y1,Y2,...,Yn}, 通过这两个序列集以及他们所构成的条件随机场模型,学习满足一定准则的势函数(Potential Function)。
(2) 推断:给定一个观察序列集 X={X1,X2,...,Xm}X={X1,X2,...,Xm}, 寻找出最优可能满足标签序列中每个观察变量属性的标签集即如公式:
根据图模型中知识可知,在图模型中,节点有两部分组成,一个是观察序列集 X={X1,X2,...,Xn}X={X1,X2,...,Xn}, 另外一个是标签集 Y={Y1,Y2,...,Yn}Y={Y1,Y2,...,Yn}, 而相邻的标签集节点由边连接,而观察集节点至少与一个标签节点相连,联合概率分布公式如下所示:
其中 ψc(X,Y)=exp(Q(c,X))ψc(X,Y)=exp(Q(c,X)) 为势函数,而 Q(c,X)Q(c,X) 则表示一个实数值函数,它用于计算给基团中的随机变量指派实数值标签所得到的概率,式子中的 Z(X)Z(X) 则为归一化因子(也称配分函数),表示为:
其条件随机场的节点模型表示如下图所示,灰色的节点代表观察值,白色的节点代表标签集。
条件随机场模型示意图
下面将会介绍一个条件随机场的参数化形式,条件随机场的图模型当中有一系列基团组成,这些基团内的元素个数要么为1,要么为2,因此基于这两种基团类型的条件随机场的概率模型如下公式所示:
式中 ψi(X,Yi)ψi(X,Yi) 依赖于单个节点,而 ϕi(X,Yi,Yi−1)ϕi(X,Yi,Yi−1) 依赖于两个节点之间构成的边,在模型当中均以对数线性形式表示出来,如下面公式所示:
上式中 ϕm(X,Y,i)ϕm(X,Y,i) 是一个状态特征函数,它仅仅与节点位置上的标签有关,而边特征函数 ϕk(X,Yi−1,Yi,i)ϕk(X,Yi−1,Yi,i) 是一个转移特征函数,它只与当前节点标签以及先前节点的标签有关,系数 θmθm 和 μkμk 为表示特征函数值的权重,他们将会在学习过程中得到,尤其是转移特征函数,他能突显出连接成一条边的两个节点之间的特征的相似性,在语句分类任务或者在机器学习上的分类都显得尤为重要。为了书写方便,经常将状态特征函数与转移特征函数统一为特征函数 fi(X,Yi,Yi−1,i)fi(X,Yi,Yi−1,i)表示第 jj 个特征函数,它对应的参数由 μkμk 决定,那么给定观测序列所对应的标签的联合概率如下公式所示:
由于归一化因子 Z(X)Z(X) 独立于标签,故在求解过程中只需计算 Y^Y^,如公式:
而在条件随机场中,学习与推断过程往往是交叉进行的,在学习过程中,每次迭代时,系统都会计算已经有标签的训练数据的最佳估计,并根据误差来更新模型,进而进行下一次迭代。
1.2 条件随机场开源工具
条件随机场开源工具主流的有以下两个:
- CRF++: https://web.archive.org/web/20100421020327/http://crfpp.sourceforge.net/
- FlexCRFs:http://flexcrfs.sourceforge.net/
这两个库都是为自然语言处理任务而开发出来的,当然也可以根据需要应用到自己的数据格式上,如图像,点云等。其他的更多的开源库请参见条件随机场维基百科。
2. 激光雷达点云的地面条件随机场模型的构建
2.1 论文内容理解
地面模型的构建请参见本博客博文《Ground Estimation and Point Cloud Segmentation using SpatioTemporal Conditional Random Field(精读)》,这里不再赘述。下面对于论文内容提出自己的见解。
1. 地面随机场模型(Proposed Model)
- 条件随机场中,节点 Ni=(nxi,nyi)Ni=(nxi,nyi) 不是点云中的点,而是经过加工之后的与节点所在位置坐标邻域相关内点相关的点,Gi={hxi,sxi,syi}Gi={hxi,sxi,syi} 属于隐藏节点,个人推测是由势函数计算得出的形式来推理出每个变量的物理意义。对于地面节点的随机场模型,在后续推断中使用了高斯模型来近似计算,目的是为了减少计算量。同时在每个节点 NiNi 邻域内的局部点云点的 labellabel 属性须一致,而节点的具体操作可用栅格来代替,栅格的中心点坐标等价于节点坐标;
- 局部特征函数,即论文中观测势函数(measurement potential),相关数据为 MiMi, MiMi为与节点 NiNi 相关的点云点集(注意是点云点集,而不是节点点集)。理由是,因为这个函数属于条件随机场中的局部特征函数,那么基于局部信息函数只与节点自身包含信息有关,而与周围节点信息无关,这里将要与下面第3项对比理解;
- 边特征函数,在此论文中包含节点平滑势函数(node smoothness potential)和时间交叉函数(temporal interaction potential):
(1). 节点平滑势函数:相关数据为 NiNi, NiNi 为节点邻域内节点(注意是节点点集,而不是点云点集),在论文中与邻近位置的两个节点有关;
(2). 时间交叉势函数:相关数据为一个时间点的隐变量 Gt−1iGit−1 相关,而这个值通过激光雷达所在车辆的运动相关,根据传感器 IMU, GPS 和里程计数据来推导得出。
2. 推断(Inference)
GMM + EM 算法
3. CRF++ 库应用于地面点分割
3.1 特征模板与数据
CRF++库进行训练时的三个文件,建议放在同一文件夹:
- 特征模板文件:
crf_template
(无后缀名) - 数据文件:
train.data
,test.data
1. 特征模板
按照CRF++官网说明,根据对特定任务的点云数据分割,设置自己的特征模板,例如(关于为什么这样写特征模板,以后有机会单独开博说明):
# Unigram
U00:%x[0,0]
U01:%x[0,1]
U02:%x[0,2]
U03:%x[0,3]
U04:%x[0,4]
U05:%x[0,5]
U10:%x[-1,0]
U11:%x[-1,1]
U12:%x[-1,2]
U10:%x[-1,3]
U11:%x[-1,4]
U12:%x[-1,5]
U20:%x[1,0]
U21:%x[1,1]
U22:%x[1,2]
U23:%x[1,3]
U24:%x[1,4]
U25:%x[1,5]
U100:%x[0,0]/%x[1,0]
U101:%x[0,1]/%x[1,1]
U102:%x[0,2]/%x[1,2]
U103:%x[0,3]/%x[1,3]
U104:%x[0,4]/%x[1,4]
U105:%x[0,5]/%x[1,5]
U200:%x[0,0]/%x[-1,0]
U201:%x[0,1]/%x[-1,1]
U202:%x[0,2]/%x[-1,2]
U203:%x[0,3]/%x[-1,3]
U204:%x[0,4]/%x[-1,4]
U205:%x[0,5]/%x[-1,5]
U1000:%x[-1,0]/%x[0,0]/%x[1,0]
U1001:%x[-1,1]/%x[0,1]/%x[1,1]
U1002:%x[-1,2]/%x[0,2]/%x[1,2]
U1003:%x[-1,3]/%x[0,3]/%x[1,3]
U1004:%x[-1,4]/%x[0,4]/%x[1,4]
U1005:%x[-1,5]/%x[0,5]/%x[1,5]
# Bigram
B
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
2. 训练数据
同样根据CRF++官网,将自己点云计算得到的特征写入train.data
(测试集写入test.data
) 文件中,本文特征为:
[row, column, x, y, z, range, label]
- 1
数据如下所示:
0 0 12.462 0.012 0.551 12.4742 1
0 1 12.545 0.025 0.633 12.561 1
0 2 0 0 0 0 -1
0 3 12.519 0.064 0.632 12.5351 1
0 4 0 0 0 0 -1
0 5 12.857 0.107 0.644 12.8736 1
0 6 0 0 0 0 -1
0 7 0 0 0 0 -1
0 8 13.104 0.151 0.652 13.1211 1
0 9 0 0 0 0 -1
...
63 4237 3.784 -1.452 -1.774 4.42426 0
63 4238 0 0 0 0 -1
63 4239 3.79 -1.441 -1.775 4.4262 0
63 4240 0 0 0 0 -1
63 4241 0 0 0 0 -1
63 4242 3.796 -1.429 -1.775 4.42745 0
63 4243 3.8 -1.424 -1.776 4.42967 0
63 4244 0 0 0 0 -1
63 4245 3.815 -1.416 -1.781 4.44199 0
...
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
3.2 进行训练
由于CRF++并没有编写C/C++调试API接口,没法按照编译到系统库文件夹调用的方式进行编程,所以如果想将其代码包含到自己工程中只能用最古老的方法,把代码扣到自己工程文件中,关于怎样扣,读者自己尝试,此处不表。下面就通过命令行训练的方式进行试验。
1. 训练命令
在上述文件夹中打开终端,输入如下命令:
crf_learn crf_template train.data model_file
- 1
其中model_file
为训练生成的模型文件,也可以使用如下命令,生成.txt
文件方便查看文件:
crf_learn crf_template train.data model_file -t
- 1
2.训练过程及输出
CRF++: Yet Another CRF Tool Kit
Copyright(C) 2005 Taku Kudo, All rights reserved.
reading training data: 100.. 200.. 300.. 400.. 500.. 600.. 700.. 800..
Done! 1.94 s
Number of sentences: 823
Number of features: 1075862
Number of thread(s): 1
Freq: 1
eta: 0.00010
C: 1.00000
shrinking size: 20
Algorithm: CRF
iter=0 terr=0.99103 serr=1.00000 obj=54318.36623 diff=1.00000
iter=1 terr=0.35260 serr=0.98177 obj=44996.53537 diff=0.17161
iter=2 terr=0.35260 serr=0.98177 obj=21032.70195 diff=0.53257
iter=3 terr=0.23879 serr=0.94532 obj=13642.32067 diff=0.35138
iter=4 terr=0.15324 serr=0.88700 obj=8985.70071 diff=0.34134
iter=5 terr=0.11605 serr=0.80680 obj=7118.89846 diff=0.20775
iter=6 terr=0.09305 serr=0.72175 obj=5531.31015 diff=0.22301
iter=7 terr=0.08132 serr=0.68408 obj=4618.24644 diff=0.16507
iter=8 terr=0.06228 serr=0.59174 obj=3742.93171 diff=0.18953
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
iter
:迭代次数terr
:错误率serr
: 整段错误率obj
:当前对象值,当收敛到一个固定值时,训练停止diff
:相对误差
未完待续…