Opencv249源码分析GradientBoostedTrees详解Word文档格式.docx
《Opencv249源码分析GradientBoostedTrees详解Word文档格式.docx》由会员分享,可在线阅读,更多相关《Opencv249源码分析GradientBoostedTrees详解Word文档格式.docx(46页珍藏版)》请在冰豆网上搜索。
SQUARED_LOSS为平方损失函数,CvGBTrees:
ABSOLUTE_LOSS为绝对值损失函数,CvGBTrees:
HUBER_LOSS为Huber损失函数,CvGBTrees:
DEVIANCE_LOSS为偏差损失函数,前三种用于回归问题,后一种用于分类问题
weak_count表示GBT的优化迭代次数,对于回归问题来说,weak_count也就是决策树的数量,对于分类问题来说,weak_count×
K为决策树的数量,K表示类别数量
shrinkage表示收缩因子v
subsample_portion表示训练样本占全部样本的比例,为不大于1的正数
max_depth表示决策树的最大深度
use_surrogates表示是否使用替代分叉节点,为true,表示使用替代分叉节点
CvDTreeParams结构详见我的关于决策树的文章
CvGBTrees类的一个构造函数:
CvGBTrees:
CvGBTrees(constcv:
Mat&
trainData,inttflag,
constcv:
responses,constcv:
varIdx,
sampleIdx,constcv:
varType,
missingDataMask,
CvGBTreesParams_params)
data=0;
//表示样本数据集合
weak=0;
//表示一个弱学习器
default_model_name="
my_boost_tree"
;
//orig_response表示样本的响应值,sum_response表示拟合函数Fm(x),sum_response_tmp表示Fm+1(x)
orig_response=sum_response=sum_response_tmp=0;
//subsample_train和subsample_test分别表示训练样本集和测试样本集
subsample_train=subsample_test=0;
//missing表示缺失的特征属性,sample_idx表示真正用到的样本的索引
missing=sample_idx=0;
class_labels=0;
//表示类别标签
class_count=1;
//表示类别的数量
delta=0.0f;
//表示Huber损失函数中的参数δ
clear();
//清除一些全局变量和已有的所有弱学习器
//GBT算法的学习
train(trainData,tflag,responses,varIdx,sampleIdx,varType,missingDataMask,_params,false);
GBT算法的学习构建函数:
bool
train(constCvMat*_train_data,int_tflag,
constCvMat*_responses,constCvMat*_var_idx,
constCvMat*_sample_idx,constCvMat*_var_type,
constCvMat*_missing_mask,
CvGBTreesParams_params,bool/*_update*/)//updateisnotsupported
//_train_data表示样本数据集合
//_tflag表示样本矩阵的存储格式
//_responses表示样本的响应值
//_var_idx表示要用到的特征属性的索引
//_sample_idx表示要用到的样本的索引
//_var_type表示特征属性的类型,是连续值还是离散值
//_missing_mask表示缺失的特征属性的掩码
//_params表示构建GBT模型的一些必要参数
CvMemStorage*storage=0;
//开辟一块内存空间
params=_params;
//构建GBT模型所需的参数
boolis_regression=problem_type();
//表示该GBT模型是否用于回归问题
//清空一些全局变量和已有的所有弱学习器
/*
n-countofsamples
m-countofvariables
*/
intn=_train_data->
rows;
//n表示训练样本的数量
intm=_train_data->
cols;
//m表示样本的特征属性的数量
//如果参数_tflag为CV_ROW_SAMPLE,则表示训练样本以行的形式储存的,即_train_data矩阵的每一行为一个样本,那么n和m无需交换;
否则如果_tflag为CV_COL_SAMPLE,则表示样本是以列的形式储存的,那么n和m就需要交换。
总之,在后面的程序中,n表示训练样本的数量,m表示样本的特征属性的数量
if(_tflag!
=CV_ROW_SAMPLE)
{
inttmp;
CV_SWAP(n,m,tmp);
}
//new_responses表示每个样本的伪响应值,因为构建GBT决策树使用的是伪响应值
CvMat*new_responses=cvCreateMat(n,1,CV_32F);
cvZero(new_responses);
//伪响应值初始为零
//实例化CvDTreeTrainData类,并通过该类内的set_data函数设置用于决策树的训练样本数据data
data=newCvDTreeTrainData(_train_data,_tflag,new_responses,_var_idx,
_sample_idx,_var_type,_missing_mask,_params,true,true);
if(_missing_mask)//如果给出了缺失特征属性的掩码
missing=cvCreateMat(_missing_mask->
rows,_missing_mask->
cols,
_missing_mask->
type);
//初始化missing
cvCopy(_missing_mask,missing);
//赋值_missing_mask给missing
//初始化orig_response矩阵的大小,该变量表示样本的原始真实响应值
orig_response=cvCreateMat(1,n,CV_32F);
//step表示样本响应值的步长
intstep=(_responses->
cols>
_responses->
rows)?
1:
step/CV_ELEM_SIZE(_responses->
//根据样本响应值_responses的数据类型,为orig_response赋值
switch(CV_MAT_TYPE(_responses->
type))
caseCV_32FC1:
//32位浮点型数据
for(inti=0;
i<
n;
++i)
orig_response->
data.fl[i]=_responses->
data.fl[i*step];
};
break;
caseCV_32SC1:
//32位整型数据
data.fl[i]=(float)_responses->
data.i[i*step];
default:
//其他数据类型报错
CV_Error(CV_StsUnmatchedFormats,"
Responseshouldbea32fC1or32sC1vector."
);
if(!
is_regression)//如果构建的GBT模型是用于分类问题
class_count=0;
//表示样本类别的数量
//为每个样本定义一个掩码,用于判断样本的类别
unsignedchar*mask=newunsignedchar[n];
memset(mask,0,n);
//掩码清零
//computethecountofdifferentoutputclasses
++i)//遍历所有样本,得到类别的数量
//如果当前样本的掩码没有被置1,则说明当前样本属于新的类别
mask[i])
class_count++;
//样本类别数加1
//判断当前样本以后的所有样本的响应值是否与当前样本的响应值相同,即是否属于同一类,如果是同一类,则把样本掩码置1,说明它不再是新的类别
for(intj=i;
j<
++j)
if(int(orig_response->
data.fl[j])==int(orig_response->
data.fl[i]))
mask[j]=1;
delete[]mask;
//删除mask变量
//初始化样本类别标签,并赋首地址指针
class_labels=cvCreateMat(1,class_count,CV_32S);
class_labels->
data.i[0]=int(orig_response->
data.fl[0]);
intj=1;
//表示所有样本类别标签的索引值
for(inti=1;
++i)//遍历所有样本,为样本类别标签赋值
intk=0;
//表示已得到的样本类别标签的索引值
//while循环用于判断是否有新的类别标签出现。
如果orig_response->
data.fl[i]等于class_labels->
data.i[k],说明当前样本的类别存在于已经得到的类别标签中,则退出while循环,继续for循环;
如果k≥j,说明已经遍历完类别标签
while((int(orig_response->
data.fl[i])-class_labels->
data.i[k])&
&
(k<
j))
k++;
//索引值加1
if(k==j)//说明得到了新的类别标签
//赋值新的类别标签
data.i[k]=int(orig_response->
data.fl[i]);
j++;
//insidegbtlearningproccessonlyregressiondecisiontreesarebuilt
//GBT模型用到的是回归树,所以要把data->
is_classifier赋值为false
data->
is_classifier=false;
//preproccessingsampleindices
//如果_sample_idx不为0,需要预处理那些被指定使用的样本数据
if(_sample_idx)
intsample_idx_len=get_len(_sample_idx);
//被指定的要使用的样本数据的数量
switch(CV_MAT_TYPE(_sample_idx->
type))//判断样本的数据类型
//32位整型
sample_idx=cvCreateMat(1,sample_idx_len,CV_32S);
//初始化
//遍历指定的样本数据,赋值
sample_idx_len;
sample_idx->
data.i[i]=_sample_idx->
data.i[i];
}break;
//8位有、无符号位的整型,8位样本数据存储在32位数据中,即每32位数据包括4个8位样本数据,以节省内存空间
caseCV_8S:
caseCV_8U:
//变量active_samples_count表示8位样本数据需要多少个32位数据
intactive_samples_count=0;
++i)//得到active_samples_count值
active_samples_count+=int(_sample_idx->
data.ptr[i]);
sample_idx=cvCreateMat(1,active_samples_count,CV_32S);
active_samples_count=0;
//为sample_idx赋值,赋的不是真正的样本值,而是索引值
if(int(_sample_idx->
data.ptr[i]))
data.i[active_samples_count++]=i;
_sample_idxshouldbea32sC1,8sC1or8uC1vector."
//按从小到大的顺序对样本数据进行排序存放,以便后续处理
icvSortFloat(sample_idx->
data.fl,sample_idx_len,0);
else//全体样本数据都用于构建GBT模型
sample_idx=cvCreateMat(1,n,CV_32S);
data.i[i]=i;
//赋样本的索引值
//初始化矩阵变量sum_response和sum_response_tmp
sum_response=cvCreateMat(class_count,n,CV_32F);
sum_response_tmp=cvCreateMat(class_count,n,CV_32F);
cvZero(sum_response);
//sum_response矩阵清零
//Huber损失函数的参数δ赋值为0
inthecaseofaregressionproblemtheinitialguess(thezeroterm
inthesum)issettothemeanofallthetrainingresponses,thatis
thebestconstantmodel
//base_value表示F0(x)
//如果是回归问题,通过调用find_optimal_value函数得到F0(x),find_optimal_value函数详见后面的介绍
if(is_regression)base_value=find_optimal_value(sample_idx);
inthecaseofaclassificationproblemtheinitialguess(thezeroterm
inthesum)issettozeroforallthetreessequences
//如果是分类问题,F0(x)设置为0
elsebase_value=0.0f;
currentpredicitiononalltrainingsamplesissettobe
equaltothebase_value
cvSet(sum_response,cvScalar(base_value));
//使sum_response等于base_value
//初始化弱学习器weak,如果是回归问题,class_count为1,即一个弱学习器就是一个决策树;
如果是分类问题,class_count为类别的数量,即一个弱学习器是由class_count个决策树构成
weak=newpCvSeq[class_count];
//初始化弱学习器
class_count;
storage=cvCreateMemStorage();
weak[i]=cvCreateSeq(0,sizeof(CvSeq),sizeof(CvDTree*),storage);
storage=0;
//subsampleparamsanddata
rng=&
cv:
theRNG();
//实例化RNG类,用于得到随机数,以便随机选取训练样本数据
intsamples_count=get_len(sample_idx);
//得到样本总数
//如果subsample_portion太接近0或太接近1,则subsample_portion重新赋值为1
params.subsample_portion=params.subsample_portion<
=FLT_EPSILON||
1-params.subsample_portion<
=FLT_EPSILON
?
params.subsample_portion;
//得到训练样本的数量
inttrain_sample_count=cvFloor(params.subsample_portion*samples_count);
//train_sample_count为0,则样本总数就是训练样本数量
if(train_sample_count==0)
train_sample_count=samples_count;
inttest_sample_count=samples_count-train_sample_count;
//得到测试样本数量
//开辟一个大小为samples_count内存空间,idx_data指向该空间的首地址,该空间的前train_sample_count个单位存放着训练样本所对应的全体样本的索引值,后test_sample_count个单位存放着测试样本所对应的全体样本的索引值
int*idx_data=newint[samples_count];
//初始化subsample_train
subsample_train=cvCreateMatHeader(1,train_sample_count,CV_32SC1);
*subsample_train=cvMat(1,train_sample_count,CV_32SC1,idx_data);
//初始化subsample_test
if(test_sample_count)
subsample_test=cvCreateMatHeader(1,test_sam