boost强分类器的实现
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强分类器的实现的更多相关文章
- 【AdaBoost算法】强分类器训练过程
一.强分类器训练过程 算法原理如下(参考自VIOLA P, JONES M. Robust real time object detection[A] . 8th IEEE International ...
- MATLAB神经网络(5) 基于BP_Adaboost的强分类器设计——公司财务预警建模
5.1 案例背景 5.1.1 BP_Adaboost模型 Adaboost算法的思想是合并多个“弱”分类器的输出以产生有效分类.其主要步骤为:首先给出弱学习算法和样本空间($X$,$Y$),从样本空间 ...
- 使用 AdaBoost 元算法提高分类器性能
前言 有人认为 AdaBoost 是最好的监督学习的方式. 某种程度上因为它是元算法,也就是说它会是几种分类器的组合.这就好比对于一个问题能够咨询多个 "专家" 的意见了. 组合的 ...
- 【Adaboost算法】C++转C, 分类器结构设计
一.参考OpenCV的CascadeClassifier类LBPEvaluator类 如下,筛选出存放分类器相关信息的成员变量: class CV_EXPORTS_W CascadeClassifie ...
- 几种Boost算法的比较(Discrete AdaBoost, Real AdaBoost, LogitBoost, Gentle Adaboost)
关于boost算法 boost算法是基于PAC学习理论(probably approximately correct)而建立的一套集成学习算法(ensemble learning).其根本思想在于通过 ...
- 浅析人脸检测之Haar分类器方法
一.Haar分类器的前世今生 人脸检测属于计算机视觉的范畴,早期人们的主要研究方向是人脸识别,即根据人脸来识别人物的身份,后来在复杂背景下的人脸检测需求越来越大,人脸检测也逐渐作为一个单独的研究方向发 ...
- 分类器是如何做检测的?——CascadeClassifier中的detectMultiScale函数解读
原地址:http://blog.csdn.net/delltdk/article/details/9186875 在进入detectMultiScal函数之前,首先需要对CascadeClassifi ...
- 2、转载一篇,浅析人脸检测之Haar分类器方法
转载地址http://www.cnblogs.com/ello/archive/2012/04/28/2475419.html 浅析人脸检测之Haar分类器方法 [补充] 这是我时隔差不多两年后, ...
- 机器学习-分类器-Adaboost原理
Adaboost原理 Adaboost(AdaptiveBoosting)是一种迭代算法,通过对训练集不断训练弱分类器,然后把这些弱分类器集合起来,构成强分类器.adaboost算法训练的过程中,初始 ...
随机推荐
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- JS调用Android、Ios原生控件
在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...
- vue2.0实践的一些细节
最近用vue2.0做了个活动.做完了回头发现,好像并没有太多的技术难点,而自己好像又做了比较久...只能说效率有待提升啊...简单总结了一些比较细节的点. 1.对于一些已知肯定会有数据的模块,先用一个 ...
- FragmentTabHost的基本用法
开通博客以来已经约莫1个月了.几次想提笔写写东西,但总是由于各种各样的原因并没有开始.现在,年假刚结束,项目也还没有开始,但最终促使我写这篇博客的是,看了一篇博友写的新年计划,说是要在新的一年中写50 ...
- 设置line-height:1.5和line-height:150%或者line-height:150px的区别
直接正题: 看一下line-height可能的值: 其实可以分为两类: (1)不带单位的(如line-height:1.5),这种是推荐使用的: (2)带单位的(如line-heigth:30px/1 ...
- 界面设计技法之css布局
css布局之于页面就如同ECMAScript之于JS一般,细想一番,html就如同语文,css就如同数学,js呢,就是物理,有些扯远,这里就先不展开了. 回到主题,从最开始的css到如今的sass(l ...
- bzoj1079--记忆化搜索
题目大意:有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得 ...
- [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法
二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...
- 【JQ基础】DOM操作
内部插入:append() //向每个匹配的元素内部追加内容,可包含 HTML 标签 $(selector).append(function(index,html)) /*•index - 可选.接收 ...
- Linux网卡驱动安装、防火墙原理
安装网卡驱动程序: 需要检查是否安装kernel依赖包: rpm –q kernel-devel #检查kernel依赖包是否安装 yum –y install kernel-devel 检查gcc和 ...