理解分段式结构方程模型的构建方法
前言-写在前面
在进行一些论文研读的过程中,我发现针对模型复杂生态系统(比如农田土壤微生物的宏基因组学研究),研究者会将微生物基因丰度、环境因子等整合到一个SEM模型当中,由此来观察各变量之间直接或间接的相互影响。但是,细究某些论文后会发现,研究者的SEM计算并没有声明数据的类型,比如数据的一些基本要素,包括正态性及是否相互独立,以及是否存在时间自相关等情况;此外研究者也并未声明采用的是哪种SEM模型进行的计算。不同的SEM模型,对于数据的这些基本要素的要求不同,相同数据在不同SEM中计算得出的结论也许会有极大的差异。鉴于此,详细了解SEM的一些基本理论及适用范围,将有助于实现更加科学的模型计算,得出的结论也会更符合原始数据对应的生态学意义。
这篇文章中,我将了解到:
(1)SEM的基本概念
(2)传统SEM与分段式SEM的差别(应用条件、实现方法)
(3)有助于理论理解的2个实际例子
文中斜体为自己理解的注释。
非统计学专业翻译,译文仅供参考,欢迎批评指正。
转载须获得作者授权
原文标题:PIECEWISESEM: Piecewise structural equation modelling in R for ecology, evolution, and systematics, Jonathan S. Lefcheck, Methods in Ecology and Evolution 2015.
摘要
1,生态学家和进化生物学家依赖着逐渐复杂的统计工具来描述复杂的自然系统。其中有一个被称为结构功能模型(SEM)的工具已经在生态学领域获得了极大关注。SEM是一种路径分析工具,可用来分析解决生态系统中多种变量之间的复杂关系。
2,已有的关于SEM的计算是基于变量之间的协方差,而不是变量的真实值。虽然这种SEM可以进行各种模型的拟合,但是也限制了各种细节数据的整合。最新发展的SEM允许使用本地化估算方法同时实现正态-非正态分布、随机效应及不同相关性结构的计算,但是这种实现并不能自动化计算,这就限制了在复杂模型中SEM的计算。
3,在这里,我开发了一个基于R程序语言的开源R包PIECEWISESEM,可用来执行确证性路径分析。这个包将SEM方法扩展到了目前使用的所有线性模型(广义)、最小二乘模型(系统发生)以及混合效应模型。此外,我还提供了两个例子,第一个涉及到随机效应和时间自相关,第二个涉及到系统发育的独立性比较。
4,我的目标是提供一个用户友好且易于执行的SEM实现方法,且这种方法能够体现数据生成的生态学及方法学过程。
关键词:确证性路径分析,图形理论,混合模型,网络
引言
想要弄明白大自然的错综复杂性的欲望,是所有科学向前发展的唯一推动力。然而,直至上个世纪末,生态学家及进化生物学家也几乎只能弄清单个或少数几个因素对某个响应变量的影响。这种是因为计算能力的限制以及在严谨的实验中进行简化的必要性。然而,随着现代计算机的出现以及大尺度观测变得容易进行,使用复杂工具来处理复杂自然系统中多方面数据集的需求逐渐增加。结构方程模型(SEM)便提供了这样一种工具。
结构方程模型是一种概率模型,它在一个因果性网络中整合了多个预测因子和响应变量。模型通常使用路径图来进行表示,其中箭头代表观测变量之间的指向关系(见Fig.1和2)。这种指向关系可通过模型中对应各个路径的一系列结构方程获得。相较于传统的建模方法,SEMs具有以下两个主要特点。
1. 路径代表假设的因果关系。这其实违背了那句名言 "相关性不代表因果性"。事实上,相关性确实意味着因果性,但是因果的方向尚未确定,因为人们不知道是A导致B发生、还是B导致A发生或者A和B是第三个未知变量的结果。如果使用观察或者实验得到的先验知识,人们就能作出有依据的假设,从而判断A、B及其它可能影响它们之间关联的变量之间的因果结构。SEM允许直接检验这些假定的因果结构。从这个角度来讲,因为SEM明确地检验A导致B发生的这种假设,故其实际上与传统的线性模型相背离。关于以上这种思想的更深入的讨论超出了这篇文章的范围,但是在Pearl(2012)和Bollen&Pearl(2013)的文章中可以找到更多有关因果性及其与SEM关系的讨论。
2. 变量可同时作为预测变量和响应变量。通过让一个变量在一条路径中充当响应变量,并在另一条路径当中充当预测变量,这样SEM就可以检验并量化其它单一模型无法实现的间接或级联效应(e.g. Grace et al. 2007)。
结构方程模型中需要将生态学或进化学问题进行结构化并进行检验,且在一个单一网络中同时实现评估多个因果假设。
传统的SEMs使用最大似然方法来估计参数值,这些参数能最好地重现观察变量-协变量矩阵的整体。然后可以使用卡方检验来评估SEM的拟合优度,并于观察到的协方差矩阵进行比较。然而,这种方法假定所有的观测独立且所有变量服从(多重)正态分布。此外这种方法还限制了最小观测次数,因为这种传统SEM拟合中需要有足够的*度来估计整个变量-协变量矩阵(Grace 2006)。
这些限制催生了一种基于图论应用的有向无环的,或者说分段式的SEMs的并行发展。首先,在分段式SEM中,将各条路径图转换为(结构化的)线性方程集合,并且进行独立估算。这种将所有方程进行同时计算的全局估算转换为每个方程分开计算的局部估算的处理,会有利于各种分布(正态或非正态)及取样设计的数据的拟合 (Shipley 2000a, 2009)。此外,理论上来说分段式SEMs还可进行更小的数据集的拟合,因为拟合特定组分模型(可理解为单个局部估算方程模型)只需要对应足够的*度便可 (Shipley 2000a)。最后,它可以结合从分类学或系统发育中获得的进化距离来解决共同进化史的潜在混淆效应(Von Hardenberg & Gonzalez-Voyer 2013)。因为分段式SEM并没有合并潜在变量或复合变量,故我通常把它称为验证性路径分析。尽管有这三点不同,但鉴于Grace et al. (2012)将局部估算纳入了所谓“第三代SEM”,我还是会继续把这种分段式SEM称为SEM。
由于分段式SM并不产生有效的全局协方差矩阵,因此需要进行替代性的拟合优度检验。替代的典型方法是使用Shipley的有向分离检验。这种方法用来检验所有变量是条件独立的这一假设。说的直白一些,条件独立意味着这些未连接的变量间不存在遗失的关系(指定路径就存在关系,不指定的就不存在关系,Fig.1中的前一年夏季的海藻冠层面积与第二年的波浪扰动间就不存在关系) (Shipley 2000a)。定向分离检验的第一步,是需要获得与假设路径图有关且满足条件独立要求的最小集合,我们称之为基集。基集可以转化为一个线性方程组集合,且每一个线性方程都可以像其它任何线性模型一样被处理。对于任意一个给定的独立要求的变量的显著性,也就是p值,都可以估计且提取。可通过结合方程1所示的统计检验(Fisher’s C检验)的基集中的所有p值来进行定向分离检验。
其中
Pi表示包含k个变量的基集中的第i个独立变量。
基于这个公式,C就可以与具有2k个*度的卡方分布相比较。当有微弱的证据支持条件独立变量之和时,我们假设的关系就可看作与数据是一致的。公式中得出的C所代表的这些关系的集合有时是随机的,在这种情况下卡方检验的P值可能大于我们选择的显著性检验阈值(一般为0.05)。我们可以在Shipley(2000a, 2009)的这些文章中找到关于基集的推到过程的一些例子。
Shipley (2013)的文章中指出了Fisher’s C统计检验可以通过赤池信息准则的一个值来获得,公式如下
AIC=C+2K---公式2
其中
C指公式1中的C,K是*度的似然值(不要与基集中的独立变量数小k相混淆)。因为这个估计值并不是从最大似然数中获得,所以这个K值有时代表C统计量信息准则(CIC,参照 Cardon et al. 2011)。公式2可被扩展适用到少样本(变量)(AICc)的情况中,特别是当参数的个数超过了总样本数的n/40时,修正的AICc=C+2K(n/(n-K-1))。
分段式SEM的应用受限于基集的正确规范化及估算结果,且这种应用不能手动实现,对复杂模型则更不能实现了。为解决此问题,我提供了基于R程序语言的完全文档化且开源的程序包,并命名为PIECEWISESEM。这个包可实现分段式SEM的各种计算,包括构建基集、执行全体或各组分模型的拟合优度检验、计算AIC值、返回(标准化的)估计参数、绘制局部相关性以及产生预测信息。SEMs的构建基于一系列的结构方程,这些方程可由R中的大多数常见的线性建模函数指定,因此可以实现正态-非正态分布、层次结构以及不同的估计参数的计算。本文中,我给出了两个实际的例子。第一个结合了混合效应模型及时间相关观测,第二个涉及到由系统发育独立对比得到的非独立性数据。执行所有这些分析的数据和R代码都可以在文章附件当中获得。
例子1:风暴频率与海藻森林食物网
这个例子使用的数据来自于Byrnes et al. (2011),他们研究了风暴事件对美国加利福利亚州海藻森林的多样性及食物网结构的影响。研究者整合了针对海藻森林的各种生态学调查数据,包括35个样点及八年的基于文献数据的潜在食物网联系、基于物理检测站的波浪高度及频率数据、基于卫星图像的海藻冠层面积数据。基于这些数据,他们使用关于这一海藻系统的先验知识以及实验数据(先验知识,也就是已经知道特定的因果性是存在的),在一个单一因果网络中汇总了这些变量。然后,他们使用传统方差-协方差SEM来估算了这个模型。
Byrnes et al. 假设冬季风暴产生的波浪扰动可能影响已有海藻的数量,这种数量会对春季冠层面积产生交互影响。春季冠层反过来会影响夏季冠层面积,夏季冠层面积又会受到物理作用力(指风暴)的影响。冠层面积的大小、春季或夏季的季节变化,都将为诸如藻类、固着底栖无脊椎动物以及它们的消费者(捕食者)等各种生物提供特殊结构的栖息地。栖息地中总物种丰度,将最终决定我们所观察到的食物网中潜在营养连接的数量(或称连接强度,指每一个观测物种对应到的捕食关系的平均数量)。
上述例子最原始的分析是使用LAVAAN包(Rosseel 2012)执行的。模型卡方拟合优度检验的结果(ka square = 8.784, P = 0.118)显示数据进行了充分的拟合。Byrnes et al. (2011)的研究表明,春季冠层面积的大小受到波浪扰动及前期冠层面积交互的强烈影响:如果前一年的冠层面积增加,波浪扰动对次年春季冠层面积的影响变得更负相关。春季冠层面积对物种丰度有着直接的影响,且通过影响夏季冠层面积间接影响着物种丰度。物种丰度又反过来增加了食物网的复杂性。然而他们注意到,路径系数的相乘结果(0.38×0.29=0.11)显示,比起间接影响,春季冠层面积对于物种丰度的直接负向影响的量级更大(标准化β=-0.23)。因此,他们认为冬季风清除的春季冠层事实上能够增加物种丰度(通过减少强烈的直接负向影响),并最终在短期内增加食物网的复杂性。然而,如果考虑到海藻面积冠层面积降低带来的影响,那珊瑚礁在受到连续多年波浪的冲击后,总物种丰度应该降低才对。
Byrnes et al. (2011)的分析中将各观测数据看作是相互独立的。然而事实上,距离较近的观测点可能具有相同的特征,且在一个观测点中,观测时间间隔较近的数据的相似程度可能高于观测间隔较远的数据。为了解决这两个问题,我使用分段式SEM重新拟合了他们的原始模型。重新分析的第一步,我将使用NLME包 (Pinheiro et al. 2013)将观测变量拟合到一般线性混合效应模型当中,由此解决样点之间的非独立性。虽然也可以使用分段式SEM计算,当我还是将变量进行log转化(而不是进行整数拟合)到泊松分布中,以有助于将与原始分析进行直接比较。对于每一个组分模型,我都拟合了样点的随机影响并且只让模型截距发生变化。然后我将组分模型整合到一个串行中,并将串行传递给sem.fit函数。这个函数可以返回SEM的定向分离检验的结果、Fisher’s C 统计量和AIC值。接下来,使用sem.coefs函数来获得标准化回归系数(通过均值和标准误进行标准化,参照Byrnes et al.)。
Fisher’s C统计量与卡方分布的数据比较(C10=15.64,P=0.11)显示,混合模型的分段式SEM生成的数据与 LAVAAN包产生的一致。重新分析的结果可见于fig1b当中。一般情况下,使用sem.model.fits函数计算的基于混合和随机效应的R^2值,分段式SEM模型解释的方差一般要比传统SEM的要大。
Fig.1a,b显示的两个模型存在着诸多不同点。首先,即使它们的影响方向不变,前一年海藻冠层面积以及其与波浪扰动间的交互作用对于春季冠层面积的影响均减少了2/3。Fig.1b中最重要的结论是春季冠层面积与物种丰度之间的负相关关系不显著。基于层次结构的嵌套观测结果,之前认为由冠层面积所导致的变异被重新分配到了随机(空间)变异当中。如此一来,基于分段式SEM的分析结果便显示了波浪扰动能直接或间接地减少春季冠层面积,从而间接地减少食物网的复杂性(波浪扰动破坏了一连串的正向干扰过程:首先减少了春季和夏季的冠层面积,进而减少了物种丰度,并最终降低了食物网的复杂性)。
第二个重分析中,我解决了样点间的非独立性及潜在的时间自相关问题。步骤为:首先保持与之前一致的随机结构;然后从NLME包(Pinheiro et al. 2013)的CAR1函数中,使用一个连续自回归的自相关结构对样点年份之间的相关性进行了建模。通过对Fisher’s C统计量与卡方分布进行比较(C8=7.84, P=0.45),我发现这种分析可以很好地再现数据。重分析结果可见Fig.1c。
与没有自相关结构的分段式SEM相比,每个组分模型的方差解释量稍微更大一些。但是,两种分段式模型间的显著差异较少。春季冠层面积与物种丰度之间的路径仍然不显著。夏季冠层面积与波扰动之间出现了显著正相关,而且前一年的冠层面积与物种丰度间的相关性由显著变成了不显著。然而,使用AIC对两种分段式SEMs进行比较后发现,加入CAR1自相关结构的模型比只加入层次随机结构的模型的拟合效果要差 (AICc=97.69 cf. 81.44)(一般而言AIC越小,拟合效果越好)。
总的来说,这种重分析揭示了对于数据层次结构的建模,会使相同原始数据出现不同的解释结果:波浪扰动主要通过清除物种栖息地来降低食物网复杂性。虽然我的这一结论支持(Byrnes et al, 2011)的整体结论:他们的研究认为风暴事件(比如说波浪扰动)应该会降低食物网复杂性,具体过程为重复不断的波浪扰动事件降低了物种丰度,然后降低了食物网复杂性;然而我所展示出来的影响过程为,第一次风暴扰动清除了栖息地,从而降低了食物网的复杂性(也就是说,两种模型的主要结论相似,但是过程解释不相同)。此外,AIC模型比较显示,对潜在时间自相关进行建模并不能增加我们理解这个相互作用系统的能力。
Byrnes等人(2011)对模型的进一步探索发现,将总物种丰度分解为营养成分后,冠层面积的降低显著减少了藻类数量,但并不是他们一开始分析的那样减少了固着无脊椎动物或移动型消费者物种丰度(参照附件数据)。对样点的随机效应建模有可能稀释了富藻与贫藻样点间的差异,因此在简单的分段式SEM中更难观察到藻类丰度对总物种丰度的贡献 (Fig. 1b,c)。这些进一步的分析证实了对Byrnes等人 (2011)研究工作的深入探索是有必要的,因为这能使统计学输出的结论能更加符合系统生物学过程。
海绵虾的真社会性及生态成功学
在第二个例子当中,我使用来自海绵虾的一个属(Synalpheus)的种群及生态学数据去探索生态成功学(我将ecological success翻译为生态成功学,可理解为种群成功占据了优势生态位)的驱动因素。这个属的物种展示了一系列的社会结构,从成对形成到真社会性,每个群体有一个繁殖的雌性。这些Synalpheus种表现出的复杂的社会结构已经被假设为可以有生态学上的优势去获得更强的竞争能力及资源获取能力(换句话说,真社会性的物种群落结构可获得更有利的生态位,从而从各方面有利于种群的发展)。为了验证这一假设,Duffy & Macdonald(2010) 整理了Belize地区20种Synalpheus的雌性体重、寄主种类的数量(寄主范围)和单位面积丰度(proportional regional abundance)的数据。他们进一步计算了每个物种的真社会性指数。他们假设群落的真社会学物种越多(例如单个雌性生成更多的后代),群落就会占据更广泛的寄主,并由此会导致群落会更容易捍卫它们的寄主(类似于领土)(例如在研究区域内达到更高的群落物种丰度)。此外研究者还假设寄主范围可能与物种体型有关,因为大多数真社会性物种的体型都比较小。
第一步,我使用LAVAAN包的sem函数来拟合传统SEM,并且假定20各数据点(物种)是相互独立的。模型拟合的数据结果良好(ka^2=0.653,P=0.419),结果见Fig.2a。有两条显著的路径值得关注,真社会性对于基于物种体重的寄主范围强烈正向影响 (标准化β=0.58),以及寄主范围对相对丰度的强烈正向影响(0.47)。但是,真社会性与相对丰度之间并没有显著的直接相关关系。由此可见,真社会性物种的成功(占据生态位)在极大程度上是由于它们占据有大范围的寄主。正因为这些物种占据了广泛的栖息地(寄主),因此它们组成了总群落丰度的很大一部分。但是这个模型并不支持这种假设:真社会性赋予了这些物种直接的优势以帮助物种维持并获取特殊的生存资源。
当然,Duffy & Macdonald (2010)文章中正确指出了这些物种并不独立,因为一些物种与其它物种之间相关性密切。为解决这一问题,我在Fig.1a(原文1a,事实上应该为2a)重新拟合了SEM。此外我还根据这地区Synalpheus物种 (Hultgren & Duffy 2012)的系统发育距离,进一步地固定了模型相关性矩阵。使用APE包(Paradis, Claude & Strimmer 2004)的corBrownian函数,计算得到来自系统发育树的模型相关性,并且使用NLME包(Pinheiro et al. 2013)中的gls函数拟合了组分模型。将组分模型存储在一个串行数据中,然后使用sem.fit函数计算了SEM。最终模型计算得到的数据很好(C8=0.57, P=0.751),结果见Fig. 2b。
Fig.2所示的两个SEM有着明显的差异,其中基于系统发育的SEM出现了生物量与寄主范围的显著负相关影响(-0.32),这支持物种尺寸确实有重要影响这一结论。即使存在物种尺寸效应,真社会性对于寄主范围仍然有显著正相关影响(而且事实上相关性指数更大了,达到0.80)。和Fig.2a所示的SEM一样,真社会性对于单位区域丰度(% Abundance)并没有直接影响。同样地,这种关系也是通过寄主范围来调节的。使用CAPER包中的pgls函数重复以上分析,这个函数可以估计一个新增的标度参数λ,并产生几乎一样的结果(见附件)。
在Duffy & Macdonald (2010) 的原始文章中,他们使用多元线性回归来探索这些变量之间的关系。在考虑了体型和进化差异后,他们发现真社会性与相对丰度及寄主范围均有强烈的正相关关系。这里,使用SEM对他们的数据的进行了重分析,我发现真社会性与相对丰度之间的关系并不直接,而是占据了更广泛的寄主后的间接影响,且这个结论并不能从单个单独的多元回归中推断得出。系统发育方法在SEM中的扩充使用,有利于进化生态学中更加复杂、多变量假设数据的检验,并且能得到一些重要的观点。
讨论
在本文中,我简要介绍了分段式SEM的基本概念,并且将分段式SEM应用到了两个实际例子当中。在两个实例中,我通过引入随机变异或进化距离,确认了数据存在非独立性,并由此得出了迥异于多重回归或传统方差-协方差SEM的推论。此外我还展示了如何将一个R包-PIECEWISESEM快速且简便地应用于局部估计。事实上,这个包已被用于探索大叶藻床生态系统功能的驱动因子 (Duffy et al. 2015),以及研究实验性河流口岸中尺度生态系统中不同营养级中功能多样性的影响因素(Lefcheck & Duffy 2015),以及量化草原功能多样性的生物及非生物驱动力(Jing et al. 2015)。
------我是分割线------
译文总结
1,模型的适用条件上
传统SEM要求所有变量间相互独立,且均为正态分布;piecewiseSEM则对这些要求不作限制,甚至变量间存在时间相关也没问题。传统SEM对观测次数有最低要求,以使*度能达到检验的最低阈值。
2,模型的实现手段上
传统SEM对模型进行全局估计,也就是将各变量与其它变量间同时建立一个模型,并使用卡方检验计算模型拟合参数;
piecewiseSEM需要先构建一个基集,基集中的各组分方程的结合能扩展为原始变量(这类似于线性代数中的基的概念,基中的各向量是线性无关的,原矩阵的向量可由基中的部分向量组合得到)。
3,模型的评价参数上
传统SEM采用卡方检验,piecewiseSEM采用Fisher's C统计量。
4,原始数据及代码链接
https://besjournals.onlinelibrary.wiley.com/doi/full/10.1111/2041-210X.12512
推荐阅读
-
NeurIPS 2022 | 最强斗地主AI!网易互娱AI Lab提出基于完美信息蒸馏的方法-完美信息蒸馏(PTIE) 在斗地主游戏中,非完美信息的引入主要是由于三位玩家均不能看到别人的手牌,对于任意一位玩家而言,仅可知道其余两位玩家当前手牌的并集,而难于精准判断每位玩家当前手牌。完美信息蒸馏的思路是针对这种非完美问题,构建一个第三方角色,该角色可以看到三位玩家的手牌,该角色在不告知每位玩家完美信息的情况下通过信息蒸馏的方式引导玩家打出当前情况下合理的出牌。 以强化学习常用的 Actor-Critic 算法为例,PTIE 在 Actor-Critic 算法的应用中可以利用 Critic 的 Value 输出作为蒸馏手段来提升 Actor 的表现。具体而言即在训练中 Critic 的输入为完美信息(包含所有玩家的手牌信息),Actor 的输入为非完美信息(仅包含自己手牌信息),此种情况下 Critic 给予的 Value 值包含了完美信息,可以更好地帮助 Actor 学习到更好的策略。 从更新公式上来看,正常的 Actor-Critic 算法 Actor 更新的方式如下: 在 PTIE 模式下,对于每个非完美信息状态 h,我们可以在 Critic 中构建对应的完美信息状态 D(h),并用 Critic 的输出来更新 Actor 的策略梯度,从而达到完美信息蒸馏的效果。 PTIE 框架的整体结构如下图所示: 无论是训练还是执行过程中智能体都不会直接使用完美信息,在训练中通过蒸馏将完美信息用于提升策略,从而帮助智能体达到一个更高的强度。 PTIE 的另一种蒸馏方式是将完美信息奖励引入到奖励值函数的训练中,PerfectDou 提出了基于阵营设计的完美信息奖励 node reward,以引导智能体学习到斗地主游戏中的合作策略,其定义如下: 如上所示,完美信息部分 代表 t 时刻地主手牌最少几步可以出完,在斗地主游戏中可以近似理解为是距游戏获胜的距离, 代表 t 时刻地主阵营和农民阵营距游戏获胜的距离之差, 为调节系数。通过此种奖励设计,在训练时既可以一定程度地引入各玩家的手牌信息(出完的步数需要知道具体手牌才能计算),同时也鼓励农民以阵营的角度做出决策,提升农民的合作性。 特征构建: PerfectDou 针对牌类游戏的特点主要构建了两部分特征:牌局状态特征和动作特征。其中牌局状态特征主要包括当前玩家手牌牌型特征、当前玩家打出的卡牌牌型特征、玩家角色、玩家手牌数目等常用特征,动作特征主要用于刻画当前状态下玩家的所有可能出牌,包括了每种出牌动作的牌型特征、动作的卡牌数目、是否为最大动作等特征。 牌型特征为 12 * 15 的矩阵,如下图所示: 该矩阵前 4 行代表对应每种卡牌的张数,5-12 行代表该种卡牌的种类和对应位置。 网络结构和动作空间设计 针对斗地主游戏出牌组合数较多的问题,PerfectDou 基于 RLCard 的工作上对动作空间进行了简化,对占比最大的两个出牌牌型:飞机带翅膀和四带二进行了动作压缩,将整体动作空间由 27472 种缩减到 621 种。 PerfectDou 策略网络结构如下图所示: 策略网络结构同样分为两部分:状态特征部分和动作特征部分。 在状态特征部分,LSTM 网络用于提取玩家的历史行为特征,当前牌局状态特征和提取后的行为特征会再通过多层的 MLP 网络输出当前的状态信息 embedding。 在动作特征部分,每个可行动作同样会经过多层 MLP 网络进行编码,编码后的动作特征会与其对应的状态信息 embedding 经过一层 MLP 网络计算两者间的相似度,并经由 softmax 函数输出对应的动作概率。 实验结果
-
理解分段式结构方程模型的构建方法
-
F#探险之旅(二):函数式编程(上)-函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP)、命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程。回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前。第二种FP语言是Lisp,产生于1958,早于Cobol一年。Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟,至今已是最流行的编程范式。有道是“*代有语言出,各领风骚数十年”。 尽管强大的FP语言(SML,Ocaml,Haskell及Clean等)和类FP语言(APL和Lisp是现实世界中最成功的两个)在1950年代就不断发展,FP仍停留在学院派的“象牙塔”里;而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天,FP的潜力终被认识——它是用来解决更复杂的问题的(当然更简单的问题也不在话下)。 纯粹的FP将程序看作是接受参数并返回值的函数的集合,它不允许有副作用(side effect,即改变了状态),使用递归而不是循环进行迭代。FP中的函数很像数学中的函数,它们都不改变程序的状态。举个简单的例子,一旦将一个值赋给一个标识符,它就不会改变了,函数不改变参数的值,返回值是全新的值。 FP的数学基础使得它很是优雅,FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题,它的优势之一就是融合了多种编程范式,允许开发人员按照需要采用最好的范式。 关于FP的更多内容建议阅读一下这篇文章:Why Functional Programming Matters(中文版)。F#中的函数式编程 从现在开始,我将对F#中FP相关的主要语言结构逐一进行介绍。标识符(Identifier) 在F#中,我们通过标识符给值(value)取名字,这样就可以在后面的程序中引用它。通过关键字let定义标识符,如: let x = 42 这看起来像命令式编程语言中的赋值语句,两者有着关键的不同。在纯粹的FP中,一旦值赋给了标识符就不能改变了,这也是把它称为标识符而非变量(variable)的原因。另外,在某些条件下,我们可以重定义标识符;在F#的命令式编程范式下,在某些条件下标识符的值是可以修改的。 标识符也可用于引用函数,在F#中函数本质上也是值。也就是说,F#中没有真正的函数名和参数名的概念,它们都是标识符。定义函数的方式与定义值是类似的,只是会有额外的标识符表示参数: let add x y = x + y 这里共有三个标识符,add表示函数名,x和y表示它的参数。关键字和保留字关键字是指语言中一些标记,它们被编译器保留作特殊之用。在F#中,不能用作标识符或类型的名称(后面会讨论“定义类型”)。它们是: abstract and as asr assert begin class default delegate do donedowncast downto elif else end exception extern false finally forfun function if in inherit inline interface internal land lazy letlor lsr lxor match member mod module mutable namespace new nullof open or override private public rec return sig static structthen to true try type upcast use val void when while with yield 保留字是指当前还不是关键字,但被F#保留做将来之用。可以用它们来定义标识符或类型名称,但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性,最好不要使用。它们是: atomic break checked component const constraint constructor continue eager event external fixed functor global include method mixinobject parallel process protected pure sealed trait virtual volatile 文字值(Literals) 文字值表示常数值,在构建计算代码块时很有用,F#提供了丰富的文字值集。与C#类似,这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等,在此不再赘述,详细信息请查看F#手册。 与C#一样,F#中的字符串常量表示也有两种方式。一是常规字符串(regular string),其中可包含转义字符;二是逐字字符串(verbatim string),其中的(")被看作是常规的字符,而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示: let message = "Hello World"r"n!" // 常规字符串let dir = @"C:"FS"FP" // 逐字字符串let bytes = "bytes"B // byte 数组let xA = 0xFFy // sbyte, 16进制表示let xB = 0o777un // unsigned native-sized integer,8进制表示let print x = printfn "%A" xlet main = print message; print dir; print bytes; print xA; print xB; main Printf函数通过F#的反射机制和.NET的ToString方法来解析“%A”模式,适用于任何类型的值,也可以通过F#中的print_any和print_to_string函数来完成类似的功能。值和函数(Values and Functions) 在F#中函数也是值,F#处理它们的语法也是类似的。 let n = 10let add a b = a + blet addFour = add 4let result = addFour n printfn "result = %i" result 可以看到定义值n和函数add的语法很类似,只不过add还有两个参数。对于add来说a + b的值自动作为其返回值,也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说,它定义在add的基础上,它只向add传递了一个参数,这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念,F(x, y) = x + y,G(y) = F(4, y),实际上G(y) = 4 + y,G也是一个函数,它接收一个参数,这个地方是不是很类似?这种只向函数传递部分参数的特性称为函数的柯里化(curried function)。 当然对某些函数来说,传递部分参数是无意义的,此时需要强制提供所有参数,可是将参数括起来,将它们转换为元组(tuple)。下面的例子将不能编译通过: let sub(a, b) = a - blet subFour = sub 4 必须为sub提供两个参数,如sub(4, 5),这样就很像C#中的方法调用了。 对于这两种方式来说,前者具有更高的灵活性,一般可优先考虑。 如果函数的计算过程中需要定义一些中间值,我们应当将这些行进行缩进: let halfWay a b = let dif = b - a let mid = dif / 2 mid + a 需要注意的是,缩进时要用空格而不是Tab,如果你不想每次都按几次空格键,可以在VS中设置,将Tab字符自动转换为空格;虽然缩进的字符数没有限制,但一般建议用4个空格。而且此时一定要用在文件开头添加#light指令。作用域(Scope)作用域是编程语言中的一个重要的概念,它表示在何处可以访问(使用)一个标识符或类型。所有标识符,不管是函数还是值,其作用域都从其声明处开始,结束自其所处的代码块。对于一个处于最顶层的标识符而言,一旦为其赋值,它的值就不能修改或重定义了。标识符在定义之后才能使用,这意味着在定义过程中不能使用自身的值。 let defineMessage = let message = "Help me" print_endline message // error 对于在函数内部定义的标识符,一般而言,它们的作用域会到函数的结束处。 但可使用let关键字重定义它们,有时这会很有用,对于某些函数来说,计算过程涉及多个中间值,因为值是不可修改的,所以我们就需要定义多个标识符,这就要求我们去维护这些标识符的名称,其实是没必要的,这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型,但F#仍能确保类型安全。所谓类型安全,其基本意义是F#会避免对值的错误操作,比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。 let changeType = let x = 1 let x = "change me" let x = x + 1 print_string x 在本例的函数中,第一行和第二行都没问题,第三行就有问题了,在重定义x的时候,赋给它的值是x + 1,而x是字符串,与1相加在F#中是非法的。 另外,如果在嵌套函数中重定义标识符就更有趣了。 let printMessages = let message = "fun value" printfn "%s" message; let innerFun = let message = "inner fun value" printfn "%s" message innerFun printfn "%s" message printMessages 打印结果: fun value inner fun valuefun value 最后一次不是inner fun value,因为在innerFun仅仅将值重新绑定而不是赋值,其有效范围仅仅在innerFun内部。递归(Recursion)递归是编程中的一个极为重要的概念,它表示函数通过自身进行定义,亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。 使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数: let rec factorial x = match x with | x when x < 0 -> failwith "value must be greater than or equal to 0" | 0 -> 1 | x -> x * factorial(x - 1) 这里使用了模式匹配(F#的一个很棒的特性),其C#版本为: public static long Factorial(int n) { if (n < 0) { throw new ArgumentOutOfRangeException("value must be greater than or equal to 0"); } if (n == 0) { return 1; } return n * Factorial (n - 1); } 递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心,可能会写出不能终止的递归。匿名函数(Anonymous Function) 定义函数的时候F#提供了第二种方式:使用关键字fun。有时我们没必要给函数起名,这种函数就是所谓的匿名函数,有时称为lambda函数,这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数,通常就不需要起名。在后面的“列表”一节中你会看到这样的例子。除了fun,我们还可以使用function关键字定义匿名函数,它们的区别在于后者可以使用模式匹配(本文后面将做介绍)特性。看下面的例子: let x = (fun x y -> x + y) 1 2let x1 = (function x -> function y -> x + y) 1 2let x2 = (function (x, y) -> x + y) (1, 2) 我们可优先考虑fun,因为它更为紧凑,在F#类库中你能看到很多这样的例子。 注意:本文中的代码均在F# 1.9.4.17版本下编写,在F# CTP 1.9.6.0版本下可能不能通过编译。 F#系列随笔索引页面
-
计算机视觉中,究竟有哪些好用的目标跟踪算法(下)-快速变形主要因为CF是模板类方法。容易跟丢这个比较好理解,前面分析了相关滤波是模板类方法,如果目标快速变形,那基于HOG的梯度模板肯定就跟不上了,如果快速变色,那基于CN的颜色模板肯定也就跟不上了。这个还和模型更新策略与更新速度有关,固定学习率的线性加权更新,如果学习率太大,部分或短暂遮挡和任何检测不准确,模型就会学习到背景信息,积累到一定程度模型跟着背景私奔了,一去不复返。如果学习率太小,目标已经变形了而模板还是那个模板,就会变得不认识目标。(举个例子,多年不见的同学,你很可能就认不出了,而经常见面的同学,即使变化很大你也认识,因为常见的同学在你大脑里面的模型在持续更新,而多年不见就是很久不更新) 快速运动主要是边界效应(Boundary Effets),而且边界效应产生的错误样本会造成分类器判别力不够强,下面分训练阶段和检测阶段分别讨论。 训练阶段,合成样本降低了判别能力。如果不加余弦窗,那么移位样本是长这样的: 除了那个最原始样本,其他样本都是“合成”的,100*100的图像块,只有1/10000的样本是真实的,这样的样本集根本不能拿来训练。如果加了余弦窗,由于图像边缘像素值都是0,循环移位过程中只要目标保持完整那这个样本就是合理的,只有目标中心接近边缘时,目标跨越边界的那些样本是错误的,这样虽不真实但合理的样本数量增加到了大约2/3(padding= 1),即使这样仍然有1/3(3000/10000)的样本是不合理的,这些样本会降低分类器的判别能力。再者,加余弦窗也不是“免费的”,余弦窗将图像块的边缘区域像素全部变成0,大量过滤掉分类器本来非常需要学习的背景信息,原本训练时判别器能看到的背景信息就非常有限,我们还加了个余弦窗挡住了背景,这样进一步降低了分类器的判别力(是不是上帝在我前遮住了帘。不是上帝,是余弦窗)。 检测阶段,相关滤波对快速运动的目标检测比较乏力。相关滤波训练的图像块和检测的图像块大小必须是一样的,这就是说你训练了一个100*100的滤波器,那你也只能检测100*100的区域,如果打算通过加更大的padding来扩展检测区域,那样除了扩展了复杂度,并不会有什么好处。目标运动可能是目标自身移动,或摄像机移动,按照目标在检测区域的位置分四种情况来看: 如果目标在中心附近,检测准确且成功。 如果目标移动到了边界附近但还没有出边界,加了余弦窗以后,部分目标像素会被过滤掉,这时候就没法保证这里的响应是全局最大的,而且,这时候的检测样本和训练过程中的那些不合理样本很像,所以很可能会失败。 如果目标的一部分已经移出了这个区域,而我们还要加余弦窗,很可能就过滤掉了仅存的目标像素,检测失败。 如果整个目标已经位移出了这个区域,那肯定就检测失败了。 以上就是边界效应(Boundary Effets),推荐两个主流的解决边界效应的方法,但速度比较慢,并不推荐用于实时场合。