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. EntityFramework Core Raw SQL

    前言 本节我们来讲讲EF Core中的原始查询,目前在项目中对于简单的查询直接通过EF就可以解决,但是涉及到多表查询时为了一步到位就采用了原始查询的方式进行.下面我们一起来看看. EntityFram ...

  2. POCO Controller 你这么厉害,ASP.NET vNext 知道吗?

    写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...

  3. 07. Web大前端时代之:HTML5+CSS3入门系列~H5 地理位置

    Web大前端时代之:HTML5+CSS3入门系列:http://www.cnblogs.com/dunitian/p/5121725.html 源码:https://github.com/duniti ...

  4. 初步了解nodejs

    什么是Node.js? 很多初学者并没有真正地理解Node.js到底是什么.nodejs.org网站中的描述也没有多大帮助. 首先要清楚Node不是一个Web服务器,这十分重要.它本身并不能做任何事情 ...

  5. UWP开发必备:常用数据列表控件汇总比较

    今天是想通过实例将UWP开发常用的数据列表做汇总比较,作为以后项目开发参考.UWP开发必备知识点总结请参照[UWP开发必备以及常用知识点总结]. 本次主要讨论以下控件: GridView:用于显示数据 ...

  6. GPG终极指南(加密/签名)

    我们平时都听过非对称加密,公钥和私钥,签名验证,但这些证书都是怎么得到的呢?本篇文章会解答这些问题. 背景介绍 加密的一个简单但又实用的任务就是发送加密电子邮件.多年来,为电子邮件进行加密的标准一直是 ...

  7. ZKWeb网页框架1.3正式发布

    本次更新的内容有 更新引用包版本 Microsoft.AspNetCore.Hosting.Abstractions 1.1.0 Microsoft.AspNetCore.Http.Abstracti ...

  8. Java中用得比较顺手的事件监听

    第一次听说监听是三年前,做一个webGIS的项目,当时对Listener的印象就是个"监视器",监视着界面的一举一动,一有动静就触发对应的响应. 一.概述 通过对界面的某一或某些操 ...

  9. SharePoint 2013: A feature with ID has already been installed in this farm

    使用Visual Studio 2013创建一个可视web 部件,当右击项目选择"部署"时报错: "Error occurred in deployment step ' ...

  10. Android Retrofit 2.0 使用-补充篇

    推荐阅读,猛戳: 1.Android MVP 实例 2.Android Retrofit 2.0使用 3.RxJava 4.RxBus 5.Android MVP+Retrofit+RxJava实践小 ...