ImageVerifierCode 换一换
格式:DOCX , 页数:34 ,大小:28.96KB ,
资源ID:8078400      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/8078400.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Opencv249源码分析Extremely randomized trees.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Opencv249源码分析Extremely randomized trees.docx

1、Opencv249源码分析Extremely randomized treesOpencv2.4.9源码分析Extremely randomized trees一、原理 ET或Extra-Trees(Extremely randomized trees,极端随机树)是由PierreGeurts等人于2006年提出。该算法与随机森林算法十分相似,都是由许多决策树构成。但该算法与随机森林有两点主要的区别:1、随机森林应用的是Bagging模型,而ET是使用所有的训练样本得到每棵决策树,也就是每棵决策树应用的是相同的全部训练样本;2、随机森林是在一个随机子集内得到最佳分叉属性,而ET是完全随机的得到

2、分叉值,从而实现对决策树进行分叉的。对于第2点的不同,我们再做详细的介绍。我们仅以二叉树为例,当特征属性是类别的形式时,随机选择具有某些类别的样本为左分支,而把具有其他类别的样本作为右分支;当特征属性是数值的形式时,随机选择一个处于该特征属性的最大值和最小值之间的任意数,当样本的该特征属性值大于该值时,作为左分支,当小于该值时,作为右分支。这样就实现了在该特征属性下把样本随机分配到两个分支上的目的。然后计算此时的分叉值(如果特征属性是类别的形式,可以应用基尼指数;如果特征属性是数值的形式,可以应用均方误差)。遍历节点内的所有特征属性,按上述方法得到所有特征属性的分叉值,我们选择分叉值最大的那种

3、形式实现对该节点的分叉。从上面的介绍可以看出,这种方法比随机森林的随机性更强。对于某棵决策树,由于它的最佳分叉属性是随机选择的,因此用它的预测结果往往是不准确的,但多棵决策树组合在一起,就可以达到很好的预测效果。当ET构建好了以后,我们也可以应用全部的训练样本来得到该ET的预测误差。这是因为尽管构建决策树和预测应用的是同一个训练样本集,但由于最佳分叉属性是随机选择的,所以我们仍然会得到完全不同的预测结果,用该预测结果就可以与样本的真实响应值比较,从而得到预测误差。如果与随机森林相类比的话,在ET中,全部训练样本都是OOB样本,所以计算ET的预测误差,也就是计算这个OOB误差。在这里,我们仅仅介

4、绍了ET算法与随机森林的不同之处,ET算法的其他内容(如预测、OOB误差的计算)与随机森林是完全相同的,具体内容请看关于随机森林的介绍。 二、源码分析 下面是ET算法的类CvERTrees,它继承于CvRTrees类:cpp view plain copy 在CODE上查看代码片派生到我的代码片class CV_EXPORTS_W CvERTrees : public CvRTrees public: CV_WRAP CvERTrees(); virtual CvERTrees(); virtual bool train( const CvMat* trainData, int tflag,

5、const CvMat* responses, const CvMat* varIdx=0, const CvMat* sampleIdx=0, const CvMat* varType=0, const CvMat* missingDataMask=0, CvRTParams params=CvRTParams(); CV_WRAP virtual bool train( const cv:Mat& trainData, int tflag, const cv:Mat& responses, const cv:Mat& varIdx=cv:Mat(), const cv:Mat& sampl

6、eIdx=cv:Mat(), const cv:Mat& varType=cv:Mat(), const cv:Mat& missingDataMask=cv:Mat(), CvRTParams params=CvRTParams(); virtual bool train( CvMLData* data, CvRTParams params=CvRTParams() ); protected: virtual std:string getName() const; virtual bool grow_forest( const CvTermCriteria term_crit ); ; 我们

7、从CvERTrees类可以看出,它没有预测函数predict,因此,如果要进行ET的预测,调用的是它的父类CvRTrees内的predict函数。在训练样本时,CvERTrees类与CvRTrees类的训练过程是完全一致的,即在train函数内再调用grow_forest函数,而且两个类的train函数的输入参数的形式也是完全一样的。但在grow_forest函数内会有一点不同,那就是CvERTrees类中的grow_forest函数把全体训练样本都当成OOB样本,因此它不需要随机样本掩码矩阵变量sample_idx_mask_for_tree,而表示样本索引值变量的sample_idx_fo

8、r_tree保存的就是正常顺序的训练样本的索引值。ET算法与随机森林算法最大的不同就在于节点的分叉上,而这一点是体现在CvForestERTree类上的:cpp view plain copy 在CODE上查看代码片派生到我的代码片class CV_EXPORTS CvForestERTree : public CvForestTree protected: virtual double calc_node_dir( CvDTreeNode* node ); virtual CvDTreeSplit* find_split_ord_class( CvDTreeNode* n, int vi,

9、float init_quality = 0, CvDTreeSplit* _split = 0, uchar* ext_buf = 0 ); virtual CvDTreeSplit* find_split_cat_class( CvDTreeNode* n, int vi, float init_quality = 0, CvDTreeSplit* _split = 0, uchar* ext_buf = 0 ); virtual CvDTreeSplit* find_split_ord_reg( CvDTreeNode* n, int vi, float init_quality = 0

10、, CvDTreeSplit* _split = 0, uchar* ext_buf = 0 ); virtual CvDTreeSplit* find_split_cat_reg( CvDTreeNode* n, int vi, float init_quality = 0, CvDTreeSplit* _split = 0, uchar* ext_buf = 0 ); virtual void split_node_data( CvDTreeNode* n ); ; CvForestERTree类定义了一些专用于ET算法的计算分叉、得到最佳分叉属性的函数,下面我们就逐一介绍这些函数。 按最

11、佳分叉属性标注该节点的所有样本是被分配到左分支还是右分支:cpp view plain copy 在CODE上查看代码片派生到我的代码片double CvForestERTree:calc_node_dir( CvDTreeNode* node ) /表示特征属性的种类是属于左分支还是右分支,-1为左分支,1为右分支,如果该特征属性缺失,则为0 char* dir = (char*)data-direction-data.ptr; /n表示该节点的样本数量,vi表示分类的最佳特征属性 int i, n = node-sample_count, vi = node-split-var_idx;

12、double L, R; assert( !node-split-inversed ); /确保分叉不反转 if( data-get_var_type(vi) = 0 ) / split on categorical var /表示该特征属性是种类的形式 /开辟一块内存空间 cv:AutoBuffer inn_buf(n*sizeof(int)*(!data-have_priors ? 1 : 2); int* labels_buf = (int*)(uchar*)inn_buf; /labels指向该特征属性中各个样本所对应的种类,get_cat_var_data函数在ER算法中被重新定义

13、const int* labels = data-get_cat_var_data( node, vi, labels_buf ); / subset数组的每一位表示特征属性的种类,左分支的种类位是1,右分支的是0 const int* subset = node-split-subset; if( !data-have_priors ) /无先验概率 int sum = 0, sum_abs = 0; for( i = 0; i = 0)&(!data-is_buf_16u) | (idx != 65535)&(data-is_buf_16u) ) ? CV_DTREE_CAT_DIR(id

14、x,subset) : 0; /sum表示d累加求和,因为d也可能为负值,所以sum的含义为右分支比左分支多出的特征属性种类;sum_abs表示d的绝对值之和,表示的含义为被分叉的特征属性种类 sum += d; sum_abs += d & 1; diri = (char)d; /赋值 /L和R分别表示左右分支的特征属性的种类数量 R = (sum_abs + sum) 1; L = (sum_abs - sum) 1; else /有先验概率 const double* priors = data-priors_mult-data.db; /得到先验概率 double sum = 0, s

15、um_abs = 0; int *responses_buf = labels_buf + n; /responses指向该节点样本的分类,即响应值 const int* responses = data-get_class_labels(node, responses_buf); for( i = 0; i = 0 ? CV_DTREE_CAT_DIR(idx,subset) : 0; sum += d*w; sum_abs += (d & 1)*w; /增加了先验概率 diri = (char)d; /L和R分别表示左右分支的特征属性的种类数量 R = (sum_abs + sum) *

16、0.5; L = (sum_abs - sum) * 0.5; else / split on ordered var /表示该特征属性是数值的形式 /得到分叉属性的值split_val,如果样本的分叉属性的值小于该值,则被分叉为左节点,否则为右节点 float split_val = node-split-ord.c; /为该特征属性开辟一块内存空间 cv:AutoBuffer inn_buf(n*(sizeof(int)*(!data-have_priors ? 1 : 2) + sizeof(float); float* val_buf = (float*)(uchar*)inn_buf

17、; /用于存储各个样本当前特征属性的值 int* missing_buf = (int*)(val_buf + n); /表示各个样本是否缺失当前特征属性 const float* val = 0; /指向数组val_buf const int* missing = 0; /指向数组missing_buf / get_ord_var_data函数在ER算法中被重新定义,各个样本的vi特征属性的值存储在val_buf数组内,各个样本是否缺失该特征属性用missing_buf数组表示 data-get_ord_var_data( node, vi, val_buf, missing_buf, &v

18、al, &missing, 0 ); if( !data-have_priors ) /无先验概率 L = R = 0; for( i = 0; i n; i+ ) /遍历所有样本 if ( missingi ) /该样本缺失vi这个特征属性 diri = (char)0; /方向信息赋值为0 else if ( vali priors_mult-data.db; /得到先验概率 int* responses_buf = missing_buf + n; /responses指向该节点样本的分类,即响应值 const int* responses = data-get_class_labels

19、(node, responses_buf); L = R = 0; for( i = 0; i n; i+ ) /遍历所有样本 if ( missingi ) /该样本缺失vi这个特征属性 diri = (char)0; else double w = priorsresponsesi; /得到先验概率 if ( vali maxlr = MAX( L, R ); /表示左右分支最大值 return node-split-quality/(L + R); /得到规范化系数 特征为数值的分类树的分叉方法:cpp view plain copy 在CODE上查看代码片派生到我的代码片CvDTree

20、Split* CvForestERTree:find_split_ord_class( CvDTreeNode* node, int vi, float init_quality, CvDTreeSplit* _split, uchar* _ext_buf ) const float epsilon = FLT_EPSILON*2; /定义一个最小常数 const float split_delta = (1 + FLT_EPSILON) * FLT_EPSILON; /定义另一个常数 int n = node-sample_count; /该节点的样本数量 int m = data-get_

21、num_classes(); /样本数据的分类数 /为该特征属性vi开辟一块内存空间 cv:AutoBuffer inn_buf; if( !_ext_buf ) inn_buf.allocate(n*(2*sizeof(int) + sizeof(float); uchar* ext_buf = _ext_buf ? _ext_buf : (uchar*)inn_buf; float* values_buf = (float*)ext_buf; /用于存储各个样本在特征属性vi的值 int* missing_buf = (int*)(values_buf + n); /表示各个样本是否缺失当

22、前特征属性 const float* values = 0; /指向数组values_buf const int* missing = 0; /指向数组missing_buf /得到数组values_buf和missing_buf data-get_ord_var_data( node, vi, values_buf, missing_buf, &values, &missing, 0 ); int* responses_buf = missing_buf + n; /responses指向该节点样本的分类,即响应值 const int* responses = data-get_class_

23、labels( node, responses_buf ); double lbest_val = 0, rbest_val = 0, best_val = init_quality, split_val = 0; /得到不同分类的先验概率 const double* priors = data-have_priors ? data-priors_mult-data.db : 0; bool is_find_split = false; /表示是否找到了分叉属性 float pmin, pmax; /分别表示样本的特征属性vi的最小值和最大值 int smpi = 0; /表示缺失特征属性的样

24、本索引值 /得到第一个不缺失vi特征属性的样本 while ( missingsmpi & (smpi n) ) smpi+; assert(smpi n); /确保smpi的正确 /初始化pmin和pmax pmin = valuessmpi; pmax = pmin; for (; smpi n; smpi+) /遍历样本,得到pmin和pmax float ptemp = valuessmpi; /得到当前样本的vi的值 int ms = missingsmpi; /当前样本是否缺失该vi值 if (ms) continue; /缺失则遍历下一个样本 if ( ptemp pmax) /

25、更新pmax值 pmax = ptemp; float fdiff = pmax-pmin; /pmax与pmin的差值 /差值大于一个常数,表示前面计算的结果是有意义的,也就是得到了分叉属性 if (fdiff epsilon) is_find_split = true; /表示找到了分叉属性 cv:RNG* rng = data-rng; /表示随机数 /随机数为0和1之间的任意数,split_val为pmax与pmin之间任意一个数 split_val = pmin + rng-uniform(0.f, 1.f) * fdiff ; /如果split_val太接近pmax或pmin,则s

26、plit_val为一个定值 if (split_val - pmin = FLT_EPSILON) split_val = pmin + split_delta; if (pmax - split_val = FLT_EPSILON) split_val = pmax - split_delta; / calculate Gini index /计算基尼指数 if ( !priors ) /样本没有先验概率 cv:AutoBuffer lrc(m*2); /lc和rc分别表示分类的左、右分支 int *lc = lrc, *rc = lc + m; int L = 0, R = 0; /表示左

27、、右分支的样本数 / init arrays of class instance counters on both sides of the split for(int i = 0; i m; i+ ) /数组lc和rc清零 lci = 0; rci = 0; for( int si = 0; si n; si+ ) /遍历所有样本 int r = responsessi; /该样本的响应值 float val = valuessi; /该样本的特征属性vi的值 int ms = missingsi; /当前样本是否缺失该vi值 if (ms) continue; /缺失则遍历下一个样本 if ( val split_val ) /左分支 lcr+; L+; else /右分支 rcr+; R+; /得到分类后的基尼指数best_val for (int i = 0; i m; i+) lbest_val += lci*lci; rbe

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1