boost.cpp文件下:

bool CvCascadeBoost::train( const CvFeatureEvaluator* _featureEvaluator,
int _numSamples,
int _precalcValBufSize, int _precalcIdxBufSize,
const CvCascadeBoostParams& _params )

函数是boost方法的入口函数。

    // 部分代码,设置参数
set_params( _params );
// 如果是logit或gentle的boost方式,需要从_featureEvaluator->cls 中拷贝样本的类别信息到 data->responses
// 因为这两种boost方法计算式把类别从0/1该为-1/+1使用
if ( (_params.boost_type == LOGIT) || (_params.boost_type == GENTLE) )
data->do_responses_copy();
// 设置所有样本初始权值为1/n
update_weights( 0 ); cout << "+----+---------+---------+" << endl;
cout << "| N | HR | FA |" << endl;
cout << "+----+---------+---------+" << endl; do
{
CvCascadeBoostTree* tree = new CvCascadeBoostTree;
// 训练一个弱分类器,弱分类器是棵CART树
if( !tree->train( data, subsample_mask, this ) )
{
delete tree;
break;
}
cvSeqPush( weak, &tree );
// 根据boost公式更新样本数据的权值
update_weights( tree );
// 根据用户输入参数,把一定比例的(0.05)权值最小的样本去掉
trim_weights();
// subsample_mask 保存每个样本是否参数训练的标记(值为0/1);没有可用样本了,退出训练
if( cvCountNonZero(subsample_mask) == 0 )
break;
}
// 如果当前强分类器达到了设置的虚警率要求或弱分类数目达到上限停止
while( !isErrDesired() && (weak->total < params.weak_count) );

后续的执行流程可以参见http://blog.csdn.net/beerbuddys/article/details/40712957

void CvDTree::try_split_node( CvDTreeNode* node )
{
CvDTreeSplit* best_split = 0;
int i, n = node->sample_count, vi;
bool can_split = true;
double quality_scale; calc_node_value( node ); if( node->sample_count <= data->params.min_sample_count ||
node->depth >= data->params.max_depth )
can_split = false; if( can_split && data->is_classifier )
{
// check if we have a "pure" node,
// we assume that cls_count is filled by calc_node_value()
int* cls_count = data->counts->data.i;
int nz = 0, m = data->get_num_classes();
for( i = 0; i < m; i++ )
nz += cls_count[i] != 0;
if( nz == 1 ) // there is only one class
can_split = false;
}
else if( can_split )
{
if( sqrt(node->node_risk)/n < data->params.regression_accuracy )
can_split = false;
} if( can_split )
{
best_split = find_best_split(node);
// TODO: check the split quality ...
node->split = best_split;
}
if( !can_split || !best_split )
{
data->free_node_data(node);
return;
} quality_scale = calc_node_dir( node );
if( data->params.use_surrogates )
{
// find all the surrogate splits
// and sort them by their similarity to the primary one
for( vi = 0; vi < data->var_count; vi++ )
{
CvDTreeSplit* split;
int ci = data->get_var_type(vi); if( vi == best_split->var_idx )
continue; if( ci >= 0 )
split = find_surrogate_split_cat( node, vi );
else
split = find_surrogate_split_ord( node, vi ); if( split )
{
// insert the split
CvDTreeSplit* prev_split = node->split;
split->quality = (float)(split->quality*quality_scale); while( prev_split->next &&
prev_split->next->quality > split->quality )
prev_split = prev_split->next;
split->next = prev_split->next;
prev_split->next = split;
}
}
}
split_node_data( node );
// 为结点的左右计算输出值
    try_split_node( node->left );
try_split_node( node->right );
}

其中calc_node_value计算结点的value,对应代码是

void
CvBoostTree::calc_node_value( CvDTreeNode* node )

然后执行到tree.cpp中的:

CvDTreeSplit* CvDTree::find_best_split( CvDTreeNode* node )
{
DTreeBestSplitFinder finder( this, node );
// 在开启TBB情况下,多核并行处理
cv::parallel_reduce(cv::BlockedRange(0, data->var_count), finder); CvDTreeSplit *bestSplit = 0;
if( finder.bestSplit->quality > 0 )
{
bestSplit = data->new_split_cat( 0, -1.0f );
memcpy( bestSplit, finder.bestSplit, finder.splitSize );
} return bestSplit;
}

进一步看operator()函数

//tree->find_split_ord_reg函数对特征vi找到最优的阈值。
void DTreeBestSplitFinder::operator()(const BlockedRange& range)
{
int vi, vi1 = range.begin(), vi2 = range.end();
int n = node->sample_count;
CvDTreeTrainData* data = tree->get_data();
AutoBuffer<uchar> inn_buf(2*n*(sizeof(int) + sizeof(float))); for( vi = vi1; vi < vi2; vi++ )
{
CvDTreeSplit *res;
int ci = data->get_var_type(vi);
if( node->get_num_valid(vi) <= 1 )
continue; if( data->is_classifier )
{
if( ci >= 0 )
res = tree->find_split_cat_class( node, vi, bestSplit->quality, split, (uchar*)inn_buf );
else
res = tree->find_split_ord_class( node, vi, bestSplit->quality, split, (uchar*)inn_buf );
}
else
{
if( ci >= 0 )
res = tree->find_split_cat_reg( node, vi, bestSplit->quality, split, (uchar*)inn_buf );
else // 找到特征vi对应的最优分割,也就是求取最优阈值
res = tree->find_split_ord_reg( node, vi, bestSplit->quality, split, (uchar*)inn_buf );
}
// 更新bestSplit为quality最高的分割
if( res && bestSplit->quality < split->quality )
memcpy( bestSplit.get(), split.get(), splitSize );
}
}

find_split_ord_reg要做的事情就是寻找最优分割,找到一个阈值将数据分为两部分,并保证两边的总体误差最小。

策略是:将特征值排序,然后依次测试最优阈值为values[i]和values[i+1]的中值。

CvDTreeSplit*
CvBoostTree::find_split_ord_reg( CvDTreeNode* node, int vi, float init_quality, CvDTreeSplit* _split, uchar* _ext_buf )
{
const float epsilon = FLT_EPSILON*2;
const double* weights = ensemble->get_subtree_weights()->data.db;
int n = node->sample_count;
int n1 = node->get_num_valid(vi); cv::AutoBuffer<uchar> inn_buf;
if( !_ext_buf )
inn_buf.allocate(2*n*(sizeof(int)+sizeof(float)));
uchar* ext_buf = _ext_buf ? _ext_buf : (uchar*)inn_buf; float* values_buf = (float*)ext_buf;
int* indices_buf = (int*)(values_buf + n);
int* sample_indices_buf = indices_buf + n;
const float* values = 0;
const int* indices = 0;
// 计算所有样本的第vi个haar特征值,values为特征值数组,已经从小到大排序
data->get_ord_var_data( node, vi, values_buf, indices_buf, &values, &indices, sample_indices_buf );
float* responses_buf = (float*)(indices_buf + n);
const float* responses = data->get_ord_responses( node, responses_buf, sample_indices_buf ); int i, best_i = -1;
double L = 0, R = weights[n];
double best_val = init_quality, lsum = 0, rsum = node->value*R; // compensate for missing values
for( i = n1; i < n; i++ )
{
int idx = indices[i];
double w = weights[idx];
rsum -= responses[idx]*w;
R -= w;
} // find the optimal split
for( i = 0; i < n1 - 1; i++ )
{
int idx = indices[i];
double w = weights[idx];
double t = responses[idx]*w;
L += w; R -= w;
lsum += t; rsum -= t; if( values[i] + epsilon < values[i+1] )
{
double val = (lsum*lsum*R + rsum*rsum*L)/(L*R);
if( best_val < val )
{
best_val = val;
best_i = i;
}
}
} CvDTreeSplit* split = 0;
if( best_i >= 0 )
{
split = _split ? _split : data->new_split_ord( 0, 0.0f, 0, 0, 0.0f );
split->var_idx = vi;
split->ord.c = (values[best_i] + values[best_i+1])*0.5f;
split->ord.split_point = best_i;
split->inversed = 0;
split->quality = (float)best_val;
}
return split;
}

类似与左右的熵越低越好。特征的计算见函数:

void CvCascadeBoostTrainData::get_ord_var_data( CvDTreeNode* n, int vi, float* ordValuesBuf, int* sortedIndicesBuf,
const float** ordValues, const int** sortedIndices, int* sampleIndicesBuf )

boost强分类器的实现的更多相关文章

  1. 【AdaBoost算法】强分类器训练过程

    一.强分类器训练过程 算法原理如下(参考自VIOLA P, JONES M. Robust real time object detection[A] . 8th IEEE International ...

  2. MATLAB神经网络(5) 基于BP_Adaboost的强分类器设计——公司财务预警建模

    5.1 案例背景 5.1.1 BP_Adaboost模型 Adaboost算法的思想是合并多个“弱”分类器的输出以产生有效分类.其主要步骤为:首先给出弱学习算法和样本空间($X$,$Y$),从样本空间 ...

  3. 使用 AdaBoost 元算法提高分类器性能

    前言 有人认为 AdaBoost 是最好的监督学习的方式. 某种程度上因为它是元算法,也就是说它会是几种分类器的组合.这就好比对于一个问题能够咨询多个 "专家" 的意见了. 组合的 ...

  4. 【Adaboost算法】C++转C, 分类器结构设计

    一.参考OpenCV的CascadeClassifier类LBPEvaluator类 如下,筛选出存放分类器相关信息的成员变量: class CV_EXPORTS_W CascadeClassifie ...

  5. 几种Boost算法的比较(Discrete AdaBoost, Real AdaBoost, LogitBoost, Gentle Adaboost)

    关于boost算法 boost算法是基于PAC学习理论(probably approximately correct)而建立的一套集成学习算法(ensemble learning).其根本思想在于通过 ...

  6. 浅析人脸检测之Haar分类器方法

    一.Haar分类器的前世今生 人脸检测属于计算机视觉的范畴,早期人们的主要研究方向是人脸识别,即根据人脸来识别人物的身份,后来在复杂背景下的人脸检测需求越来越大,人脸检测也逐渐作为一个单独的研究方向发 ...

  7. 分类器是如何做检测的?——CascadeClassifier中的detectMultiScale函数解读

    原地址:http://blog.csdn.net/delltdk/article/details/9186875 在进入detectMultiScal函数之前,首先需要对CascadeClassifi ...

  8. 2、转载一篇,浅析人脸检测之Haar分类器方法

    转载地址http://www.cnblogs.com/ello/archive/2012/04/28/2475419.html 浅析人脸检测之Haar分类器方法  [补充] 这是我时隔差不多两年后, ...

  9. 机器学习-分类器-Adaboost原理

    Adaboost原理 Adaboost(AdaptiveBoosting)是一种迭代算法,通过对训练集不断训练弱分类器,然后把这些弱分类器集合起来,构成强分类器.adaboost算法训练的过程中,初始 ...

随机推荐

  1. Akka.net路径里的user

    因为经常买双色球,嫌每次对彩票号麻烦,于是休息的时候做了个双色球兑奖的小程序,做完了发现业务还挺复杂的,于是改DDD重做设计,拆分服务,各种折腾...,不过这和本随笔没多大关系,等差不多了再总结一下, ...

  2. Android UI体验之全屏沉浸式透明状态栏效果

    前言: Android 4.4之后谷歌提供了沉浸式全屏体验, 在沉浸式全屏模式下, 状态栏. 虚拟按键动态隐藏, 应用可以使用完整的屏幕空间, 按照 Google 的说法, 给用户一种 身临其境 的体 ...

  3. 移动端之Android开发的几种方式的初步体验

    目前越来越多的移动端混合开发方式,下面列举的大多数我都略微的尝试过,就初步的认识写个简单的心得: 开发方式 开发环境 是否需要AndroidSDK 支持跨平台 开发语言&技能 MUI Win+ ...

  4. mysql学习之 sql语句的技巧及优化

    一.sql中使用正则表达式 select name,email from user where email Regexp "@163[.,]com$"; sql语句中使用Regex ...

  5. Python列表去重

    标题有语病,其实是这样的: 假设有两个列表 : L1 = [1,2,3,4] ; L2 = [1,2,5,6] 然后去掉L1中包含的L2的元素 直接这样当然是不行的: def removeExists ...

  6. CSS 特殊属性介绍之 pointer-events

    首先看一下 MDN 上关于 pointer-events 的介绍: CSS属性 pointer-events 允许作者控制特定的图形元素在何时成为鼠标事件的 target.当未指定该属性时,SVG 内 ...

  7. setCapture、releasCapture 浅析

    1. setCapture 简介 setCapture可以将鼠标事件锁定在指定的元素上,当元素捕获了鼠标事件后,该事件只能作用在当前元素上. 以下情况会导致事件锁定失败: 当窗口失去焦点时,锁定的事件 ...

  8. python 3.5 成功安装 scrapy 的步骤

    http://www.cnblogs.com/hhh5460/p/5814275.html

  9. FreeMarker:怎么使用

    第一个FreeMarker程序 1. 建立一个普通的java项目:testFreeMarker 2. 引入freemarker.jar包 3. 在项目目录下建立模板目录:templates 4. 在t ...

  10. 使用github远程仓库

    经过几天对github的研究,终于把自己想完成的给解决了,发现google真的有很多解释,但是很多也会出现一些bug,对于初学者真的很多烦恼,所以整理一份,能给初识github的你有所帮助 一,首先, ...