人工智能基础算法的个人理解

人工智能手工实现--Adaboost

  • 什么是Adaboost
    • 如何实现adaboost?
    • 代码
    • 结果

什么是Adaboost

小白(我的)理解:就是一堆一些弱(分类效果没那么好的分类器),把他们组合(怎么组合?线性组合?非线性组合?…etc)在一起,形成一个强一点的分类器,分类的效果更好。

摘抄自Wiki:AdaBoost, short for Adaptive Boosting, is a machine learning meta-algorithm formulated by Yoav Freund and Robert Schapire, who won the 2003 Gödel Prize for their work. It can be used in conjunction with many other types of learning algorithms to improve performance. The output of the other learning algorithms (‘weak learners’) is combined into a weighted sum(解决小白理解中的组合问题,这里看起来就是加权,线性组合) that represents the final output of the boosted classifier.

如何实现adaboost?

wikipedia 版本:
初始值:
样 本 : x 1 … x n 样本: {\displaystyle x_{1}\dots x_{n}} x1xn

真 实 值 : y 1 … y n , y ∈ { − 1 , 1 } 真实值: {\displaystyle y_{1}\dots y_{n},y\in \{-1,1\}} y1yn,y{1,1}

初 始 化 每 个 样 本 的 权 重 : w 1 , 1 … w n , 1 这 里 因 为 一 开 始 我 们 不 知 道 哪 个 样 本 重 要 一 点 , , 所 以 都 设 置 为 1 n 初始化每个样本的权重 :{\displaystyle w_{1,1}\dots w_{n,1}} 这里因为一开始我们不知道哪个样本重要一点,,所以都设置为{\displaystyle {\frac {1}{n}}} w1,1wn,1n1

错 误 率 函 数 : E ( f ( x ) , y , i ) = e − y i f ( x i ) 错误率函数:E(f(x), y, i) = e^{-y_i f(x_i)} E(f(x),y,i)=eyif(xi)

一 些 弱 分 类 器 : h  ⁣ : x → { − 1 , 1 } 一些弱分类器 :{\displaystyle h\colon x\rightarrow \{-1,1\}} h:x{1,1}

接下来就是开始训练
让 t 代表训练的次数 1-T
选择一个 h t ( x ) h_t(x) ht(x)弱分类器,如果有多个怎么办?那就选择 ϵ t \epsilon _{t} ϵt,也就是上面初始值中错误率函数最小的哪一个,这里 ϵ t = ∑ h t ( x i ) ≠ y i i = 1 n w i , t {\displaystyle \epsilon _{t}=\sum _{\stackrel {i=1}{h_{t}(x_{i})\neq y_{i}}}^{n}w_{i,t}} ϵt=ht(xi)=yii=1nwi,t想一想错误率是什么?是不是只有当我们的预测值和真实值不一样的时候。把所有样本中出错的权重相加起来,就代表我们的错误率(这里说错误率可能不太准确,因为我们并没有除以什么。但是之前我们初始化权重的时候,是不是1/n?姑且我先这么人为吧,有不对的望 大神们指出)。

我们已经找到了错误率最小的了,那么接下来该怎么办呢?想一想原文中的话

The output of the other learning algorithms (‘weak learners’) is combined into a weighted sum

那么我们是不是就需要去寻找一个weight,代表一下我们找出来的最小错误率的函数了呢。这时候,问题的关键就在于,如何找到或者如果代表weight呢?原文的作者提出了
α t = 1 2 ln ⁡ ( 1 − ϵ t ϵ t ) \alpha_t = \frac{1}{2} \ln \left(\frac{1-\epsilon_t}{\epsilon_t}\right) αt=21ln(ϵt1ϵt)。这里的 α t \alpha_t αt 就代表了咱们第 t 次循环中找到的某个弱分类器的权重。

那么这时候应该有疑问,为什么权重是这么表示的呢?具体作者是怎么想的我也不知道,我也不敢问,单单从这里分析,如果我们错误率越大的话,那么权重是不是应该越小,因为你这个分类器太垃圾了,我不想让你在整个分类器中占太多比重。你问我为什么这个是错误率越大,权重越小?初中的函数单调性问题,或者你也可以把几个数值带进去算一算,简单的试验一下。``

把这个权重乘以函数加入到我们强分类器当中去了
F t ( x ) = F t − 1 ( x ) + α t h t ( x ) F_t(x) = F_{t-1}(x) + \alpha_t h_t(x) Ft(x)=Ft1(x)+αtht(x)

接下来,我们就是要更新权重了, w i , t + 1 = w i , t e − y i α t h t ( x i ) w_{i,t+1} = w_{i,t} e^{-y_i \alpha_t h_t(x_i)} wi,t+1=wi,teyiαtht(xi) i in 1 … n {\displaystyle 1\dots n} 1n

代码

import  numpy as np
y_test = np.array([1,1,-1,-1,1,-1])
x_test = np.array([0,1,2,3,4,5])
#这里的初始值设置为 1/n
w_test = np.array([0.167,0.167,0.167,0.167,0.167,0.167])
#这里的G呢,我只是想后期验证的时候看看自己有没有出错
G = {}
#f1-f5代表了五个弱分类器
def f1(x):
    result = []
    for i in x:
        if i>0.5:
            result.append(-1)
        else:
            result.append(1)
    return np.array(result)
def f2(x):
    result = []
    for i in x:
        if i>1.5:
            result.append(-1)
        else:
            result.append(1)
    return np.array(result)
def f3(x):
    result = []
    for i in x:
        if i>2.5:
            result.append(1)
        else:
            result.append(-1)
    return np.array(result)
def f4(x):
    result = []
    for i in x:
        if i>3.5:
            result.append(1)
        else:
            result.append(-1)
    return np.array(result)
def f5(x):
    result = []
    for i in x:
        if i>4.5:
            result.append(-1)
        else:
            result.append(1)
    return np.array(result)
    
def find_min_error(weak_classifiers,y,x,w):
    """
    :param weak_classifiers:弱分类器
    :param y:真实值
    :param x:样本
    :param w:权重
    :return:min_error,best_classifier:最小误差和最优优化IQ
    """
    min_error = float('inf')
    best_classifier = None
    for classifier in weak_classifiers:
        y_pred = classifier(x)#这里的x和y_pred都是数组
        result = y_pred!=y
        error = np.sum(np.matmul(result,w))
        if error < min_error:
            min_error = error
            best_classifier = classifier
    return min_error,best_classifier

# min_error,c = find_min_error([f1,f2],y_test,x_test,w_test)
# print(min_error)

def find_alpha(error):
	"""
	找到弱分类器的权重(我起了,找到了,有什么好说的)
	"""
    a = (1-error)/error
    return 0.5*np.log(a)
# alpha = find_alpha(min_error)
# print(alpha)

def update_w(w,y,x,alpha,classifier):
    """
    说明一下之类为什么加了_test后缀,因为我一开始的时候没用numpy,测试一下numpy和for版本的区别
    :param w: 权重
    :param y: ground truth(未充钱版本:真实值)
    :param x: 样本
    :param alpha: 权重
    :param classifier: 最优分类器
    :return: w :更新后的权值
    """
    zm_test = np.sum(np.multiply(w,np.exp(-alpha*np.multiply(y,classifier(x)))))
    w_test = np.multiply(w,np.exp(-alpha*np.multiply(y,classifier(x))))
    w_test = w_test/zm_test
    return w_test

def cal_error_rate(y_pred,y):
	"""
	就是为了测试一下正确率(那么你这函数名有歧义啊!)
	"""
	#这里你想要的deepcopy也可以
    pred = []
    for i in range(len(y_pred)):
    	#讲道理,这里应该有疑问,为什么>0就是1呢?
    	#这个>0的条件是哪里来的呢?
    	#我只是凭感觉觉得,因为adaboost是解决二分类问题,所以我就把这个理解为大于0和小于0,希望有人解答一下。或者后续更新
        if y_pred[i]>0:
            pred.append(1)
        else:
            pred.append(-1)
    rate = np.sum(pred==y)/len(y)
    return rate
G_x = np.zeros(y_test.shape,dtype=np.float32)
weak_classifiers = [f1,f2,f3,f4,f5]
for m in range(3):
    print(G_x)
    min_error,best_classifier = find_min_error(weak_classifiers,y_test,x_test,w_test)
    alpha = find_alpha(min_error)

    w_test = update_w(w_test,y_test,x_test,alpha,best_classifier)

    G[m] = {'classifier': best_classifier, 'alpha': alpha}
    G_x += alpha * best_classifier(x_test)
    rate = cal_error_rate(G_x,y_test)
        print(f'第{m+1}次正确率:{rate*100}%,最优弱分类器{best_classifier.__name__}')


结果

第1次正确率:83.33333333333334%,最优弱分类器f2
第2次正确率:83.33333333333334%,最优弱分类器f5
第3次正确率:100.0%,最优弱分类器f4

你可能感兴趣的:(ML基础算法)