Adaptive basis function models -----Adaboost

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunChao3555/article/details/88943430

Adaptive basis function models

------七月算法*机器学习笔记

核方法:一个函数可以表示为多个基函数的加权求和

           f(x)=w^T\phi (x)  --当\phi (x)=x时,为线性基函数,这会给模型带来巨大的局限性,因此将输⼊变量的固定的⾮线性函数进⾏线性组合来拟合函数

                \phi (x)=[k(x,\mu_1 ),...,k(x,\mu_N)],\mu_i为所有数据或部分数据,k(x,\mu_i )可认为变量x到每一个数据的距离

核函数k(x,x'),可以看作度量两者之间距离的一个函数

                          k(x,x')=exp(-\frac{1}{2}(x-x')^T\Sigma ^{-1}(x-x'))(1),高斯核

                          k(x,x')=\theta _0exp(-\frac{1}{2}\sum_{j=1}^{D}\theta_j(x_j-x_j')^2),当(1)式中\Sigma为对角阵时,可简化为下面的核函数,其中\theta_j表示对角线元素

                         k(x,x')=exp(-\frac{||x-x'||^2}{2\sigma ^2}),当(1)式中\Sigma为球形(对角阵,且对角线各元素相等)时,可简化为该式,即svm中的rbf kernel

                         k(x,x')=\frac{x_i^Tx_{i'}}{||x_i||_2||x_{i'}||_2},余弦相似度,前期的nlp中xi表示一个向量,xij表示wordj在document i中出现的次数。但这样做效果不好:1.stop words是没有区分度的,但将其考虑进来就会影响距离的度量;2.对于有区分度的词,如果在一个document中出现了很多次,相似度就被人为地放大了。所以后来不直接用xij这种方式,而是TF-IDF(term frequency(解决2,针对xij)-inverse document frequency(解决1,针对j))

好的kernel的定义是很难的,因此学者们先后提出:

      1.Maximizing likelihood(最大似然估计),指定核函数,但会设置参数,然后使用最大似然估计去估计参数

      2.MKL(multiple kernel learning)k(x,x')=\sum_jw_jk_j(x,x'),核函数由多个核加权组成的,主要还是学参数

      前面两种方式kernel都是提前定义的,或者说固定不变的,只是学的参数

      3.Adaptive basis function model(ABM):f(x)=w_o+\sum_{m=1}^Mw_m\phi _m(x),\phi _m(x)即basis function,它不是人为定义的,而是learned from data!前面提到的CART(classification and regression tree)就是ABM的一种

Boosting

a greedy algorithm for fitting ABM

成熟应用--人脸检测

weak learner(弱学习机):对一定分布的训练样本给出的假设(仅仅强于随机猜测,用简单的比例表示的话正确率50%-60%)

strong learner(强学习机):根据得到的弱学习机和相应的权重给出假设(最大程度符合实际情况,80%以上)

弱学习机-------------boosting------------>强学习机,目标:最小化损失,min_f\sum_{i=1}^NL(y_i,f(x_i))

boosting算法:

     • 首先给出任意一个弱学习算法和训练集 (x1 , y1 ) , ( x2 , y2 ) , ⋯, ( xn,yn ) , xi ∈X, X 表示某个实例空间,在分类问题中是一个带类别标志的集合, yi∈Y = { + 1, - 1}。
    •初始化时, Adaboost为训练集指定分布为1 /n, 即每个训练例的权重都相同 为1 /n。
    • 接着,调用弱学习算法进行T 次迭代,每次迭代后 按照训练结果更新训练集上的分布,对于训练失败的训练例赋予较大的权重,使得下一次迭代更加关注这些 训练例,从而得到一个预测函数序列h1 , h2 , ⋯, ht ,每个预测函数ht也赋予一个权重, 预测效果好的, 相应的权重越大                     

    • T 次迭代之后,在分类问题中最终的预测函数 H 采用带权重的投票法产生。
    • 单个弱学习器的学习准确率不高,经过运用 Boosting 算法之后,最终结果准确率将得到提高。

下面是多种boosting算法,\pi_i为误差分类率,\tilde{y}\in \left \{ -1,1 \right \},y_i\in \left \{ 0,1 \right \}

Adaboost(指数loss)

               L(\tilde{y},f)=exp(-\tilde{y}f)

f求导并等0得:

                    \begin{align*} \frac{\partial E\left [ e^{-\tilde{y}f(x)}|x \right ]}{\partial x}&=\frac{\partial \left [ p(\tilde{y}=1|x)e^{-f(x)}+p(\tilde{y}=-1|x)e^{f(x)} \right ]}{\partial x}\\ &=-p(\tilde{y}=1|x)e^{-f(x)}+p(\tilde{y}=-1|x)e^{f(x)} \\ &=0\Rightarrow \frac{p(\tilde{y}=1|x)}{p(\tilde{y}=-1|x)}=e^{2f(x)} \\ &\Rightarrow f(x)=\frac{1}{2}log\frac{\tilde{\pi}}{1-\tilde{\pi}}\end{align*}

初始化:

            

迭代求解:(\beta_m,\gamma_m)分别是弱学习机和弱学习机内部元素x的参数

                   

实践中通常添加一个参数\upsilon=0.1,避免得到的弱学习机过于’强势‘,导致之前的弱学习机影响很小

                

Adaboost损失函数

          L_m(\phi )=\sum_{i=1}^Nexp\left [ -\tilde{y_i}(f_{m-1}(x_i)+\beta\phi(x_i)) \right ]=\sum_{i=1}^Nw_{i,m}exp(-\beta\tilde{y_i}\phi(x_i)),其中定义w_{i,m}=exp(-\tilde{y_i}f_{m-1}(x_i))

对于二元分类,\tilde{y_i}\in \left \{-1,1}{ \right \},即\tilde{y_i}\phi(x_i)相等即同号为1,不等异号为-1,

化简,

                 \begin{align*} L_m &=e^{-\beta}\sum_{\tilde{y_i}=\phi(x_i)}w_{i,m}+e^{\beta}\sum_{\tilde{y_i}\neq \phi(x_i)}w_{i,m} \\ &= (e^\beta-e^{-\beta})\sum_{i=1}^Nw_{i,m}\mathbb{I}(\tilde{y}\neq\phi(x_i))+e^{-\beta}\sum_{i=1}^Nw_{i,m} \end{align*},即设定了一个标准,错误分类个数

因此,观察上式L_m,对\phi(x_i)求偏导时求最小值时,仅与w_{i,m}有关,故得

                        参数\phi_m=argmin_\phi w_{i,m}\mathbb{I}(\tilde{y}\neq\phi(x_i))

                       \beta_m=\frac{1}{2}log\frac{1-err_m}{err_m},err_m=\frac{\sum_{i=1}^Nw_{i,m}\mathbb{I}(\tilde{y}\neq\phi(x_i)}{\sum_{i=1}^Nw_{i,m}}

Update:

                 f_m(x)=f_{m-1}(x)+\beta_m\phi_m(x)

                 \phi_m=argmin_\phi w_{i,m}\mathbb{I}(\tilde{y}\neq\phi(x_i))

                 \beta_m=\frac{1}{2}log\frac{1-err_m}{err_m},err_m=\frac{\sum_{i=1}^Nw_{i,m}\mathbb{I}(\tilde{y}\neq\phi(x_i)}{\sum_{i=1}^Nw_{i,m}}

                 w_{i,m}=exp(-\tilde{y_i}f_{m-1}(x_i))

                 \begin{align*} w_{i,m+1}&= exp(-\tilde{y}_i(f_{m-1}(x)+\beta_m\phi_m(x)))\\ &=w_{i,m}e^{-\beta_m\tilde{y}_i\phi_m(x_i)} \\ \end{align*}

实现步骤:

           1. w_i=1/N

           2. for \large m=1:M do

           3.        Fit a classifer \large \phi_m(x) to the trainning set using weights \LARGE w

           4.        Compute err_m=\frac{\sum_{i=1}^Nw_{i,m}\mathbb{I}(\tilde{y}\neq\phi(x_i)}{\sum_{i=1}^Nw_{i,m}}

           5.        Compute\alpha_m=\frac{1}{2}log\frac{1-err_m}{err_m},

           6.         Update  w_{i}&= w_{i}e^{-\alpha_m\mathbb{I}(\tilde{y}_i\neq\phi_m(x_i))}

           7. Return f(x)=sgn\left [ \sum_{m=1}^M\alpha_m\phi_m(x) \right ],sgn=0 or 1

– 样本的权重:

              • 没有先验知识的情况下,初始的分布应为等概分布,也就是训 练集如果有N个样本,每个样本的分布概率为1/N
              • 每次循环后提高错误样本的分布概率,分错样本在训练集中所 占权重增大 使得下一次循环的弱学习机能够集中力量对  这些错误样本进行判断。
– 弱学习机的权重

              • 准确率越高的弱学习机权重越高
– 循环控制:损失函数达到最小
               • 在强学习机的组合中增加一个加权的弱学习机 使准确率提高,损失函数值减小。

缺点:

– 速度慢,在一定程度上依赖于训练数据集合和弱学习器的选择,训练数据不充足或者弱学习器太过“弱”,都将导致其训练精度的下降。
– Boosting易受到噪声的影响,这是因为它在迭代过程中总是给噪声分配较大的权重,使得这些噪声在以后的迭代中受到更多的关注。

from numpy import *
import numpy as np
from matplotlib import pyplot as plt

def weakClassifier(dataMatrix,dimen,threshVal,threshIneq):#just classify the data,,lt:less than
    retArray = ones((shape(dataMatrix)[0],1))
    if threshIneq == 'lt':
        retArray[dataMatrix[:,dimen] <= threshVal] = -1
    else:
        retArray[dataMatrix[:,dimen] > threshVal] = -1
    return retArray
    

def BuildweakClassifier(dataArr,classLabels,weight_):
    dataMatrix = mat(dataArr)
    labelMat = mat(classLabels).T
    m,n = shape(dataMatrix)
    numSteps = 10.0#阈值划分精确度
    bestStump = {}
    bestClasEst = mat(zeros((m,1)))
    minError = inf #init error sum, to +infinity
    for i in range(n):#loop over all dimensions
        rangeMin = dataMatrix[:,i].min()#current feature min value
        rangeMax = dataMatrix[:,i].max()#max value
        stepSize = (rangeMax-rangeMin)/numSteps
        for j in range(int(numSteps)+1):#loop over all range in current dimension
            for inequal in ['lt', 'gt']: #go over less than and greater than
                threshVal = (rangeMin + float(j) * stepSize)#阈值[每个阈值下的错误分类率,取最小error时的那个阈值,作为最终的弱分类器阈值;以及对应的特征作为最佳分类特征,不等式(ineq)阈值左侧还是右侧作为条件存入bestStump字典中]
                predictedVals = weakClassifier(dataMatrix,i,threshVal,inequal)#call stump classify with i, j, lessThan
                errArr = mat(ones((m,1)))#初始化误差分类率
                errArr[predictedVals == labelMat] = 0#分类正确赋值0
                weightedError = weight_.T*errArr/np.sum(weight_)  #calc total error multiplied by weight_
                #print "split: dim %d, thresh %.2f, thresh ineqal: %s, the weighted error is %.3f" % (i, threshVal, inequal, weightedError)
                if weightedError < minError:
                    minError = weightedError
                    bestClasEst = predictedVals.copy()#最小error下的分类结果
                    bestStump['dims'] = i
                    bestStump['thresh'] = threshVal
                    bestStump['ineq'] = inequal
    return bestStump,minError,bestClasEst

def adaBoostTrainDS(dataArr,classLabels,numIt=40):
    weakClassArr = []
    m = shape(dataArr)[0]
    weight_ = mat(ones((m,1))/m)   #init weight_ to all equal
    aggClassEst = mat(zeros((m,1)))
    for i in range(numIt):
        bestStump,error,classEst = BuildweakClassifier(dataArr,classLabels,weight_)#build Stump
        # print ("weight_:",weight_.T)
        beta = 0.5*log((1.0-error)/max(error,1e-16))#calc beta, throw in max(error,eps) to account for error=0
        # print(float(beta),'((((((((')
        bestStump['beta'] = beta
        weakClassArr.append(bestStump)                  #store Stump Params in Array
        # print ("classEst: ",classEst)
        exp_on = multiply(mat(-1*beta*classLabels).T,classEst) #exponent for weight_ calc, getting messy
        weight_ = multiply(weight_,exp(exp_on))                              #Calc New weight_ for next iteration
        weight_ = weight_/weight_.sum()#标准化,并更新
        #calc training error of all classifiers, if this is 0 quit for loop early (use break)
        aggClassEst += float(beta)*classEst#强分类器:弱分类器的组合
        #print ("aggClassEst: ",aggClassEst.T)
        aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T,ones((m,1)))
        errorRate = aggErrors.sum()/m#误差分类率达到某一阈值,结束循环
        print ("total error: ",errorRate)
        if errorRate == 0.0: break
    print ("#######################################################"  )
    print ("Number of Iteration: ",i+1)
    return weakClassArr,aggClassEst

def adaClassify(datToClass,classifierArr):
    dataMatrix = mat(datToClass)#do stuff similar to last aggClassEst in adaBoostTrainDS
    m = shape(dataMatrix)[0]
    aggClassEst = mat(zeros((m,1)))
    for i in range(len(classifierArr)):
        classEst = weakClassifier(dataMatrix,classifierArr[i]['dims'],
                                 classifierArr[i]['thresh'],
                                 classifierArr[i]['ineq'])#call stump classify
        aggClassEst += float(classifierArr[i]['beta'])*classEst
    #print aggClassEst
    return sign(aggClassEst)

if __name__=="__main__":
    from sklearn import svm, datasets

    iris = datasets.load_iris()
    # print ('keys:', iris.keys())
    dat = iris.data[0:100,0:2] #only use the first three features
    print(dat)
    label = iris.target[0:100]
    # print(label)
    label[label==0]=-1
    weakClassArr,aggClassEst = adaBoostTrainDS(dat,label)
    print (weakClassArr)
    # print(dat[:,weakClassArr[0].get('dims')])
    pred = adaClassify(dat,weakClassArr)#
    print(pred)

                

           

猜你喜欢

转载自blog.csdn.net/SunChao3555/article/details/88943430
今日推荐