Haar分類器使用AdaBoost算法,但是把它組織為篩選式的級聯分類器,每個節點是多個樹構成的分類器,且每個節點的正確識別率很高。在任一級計算中,一旦獲得“不在類別中”的結論,則計算終止。只有通過分類器中所有級別,才會認為物體被檢測到。這樣的優點是當目標出現頻率較低的時候(即人臉在圖像中所占比例小時),篩選式的級聯分類器可以顯著地降低計算量,因為大部分被檢測的區域可以很早被篩選掉,迅速判斷該區域沒有要求被檢測的物體。

AdaBoost算法就是建立多個弱分類器,給每個弱分類器一個權重,將弱分類器組合在一起,形成一個強分類器。
弱學習(弱分類器)和強學習(強分類器。),所謂的弱學習,就是指一個學習算法對一組概念的識別率只比隨機識別好一點,所謂強學習,就是指一個學習算法對一組概率的識別率很高。Kearns和Valiant提出了弱學習和強學習等價的問題 ,並證明了只要有足夠的數據,弱學習算法就能通過集成的方式生成任意高精度的強學習方法。
AdaBoost算法的弱分類器不是並行的,是一個弱分類器完成了,下一個才進行,在每個弱分類器進行當中,我們關注的是上一個弱分類器分類錯誤的數據樣本,也就是說用當前分類器來彌補上一個弱分類器分類錯誤的數據樣本;
總的來時,就是后一個彌補前一個分類器的不足。



若第t步樣本分類錯誤,則在第t+1步應該關注上一個分類錯誤的樣本。
α是第t個分類器的權重,Z要讓第t+1步權重
之和為1。

yi是實際值,
是預測值,當實際值和預測值相等時(預測正確),及下一級這個數據權重會變小,否則下一級這個數據權重增加。






下圖 人臉檢測的AdaBoost算法流程圖

下面講一講結構:

一個AdaBoost級聯分類器由若干個強分類器實現,一個強分類器由若干個弱分類器實現,弱分類器又由若干特征構成。

若一個AdaBoost級聯分類器由3個強分類器構成,及X1,X2,X3時強分類器的特征,t1,t2,t3及各個強分類器的閾值,
只有X1,X2,X3都大於對應的閾值,才能輸出對應的結果;

弱分類器是用來計算強分類器的特征,由上圖中x2可得三個弱分類器的特征y1,y2,y3求和得到;
對應的。,弱分類器的特征是由對應的特征節點求出。

一個node節點的harr特征與對應node節點(nodeT1)的閾值判決,z1輸出對應的值;
最后求和得到Z,並與弱分類器的判決門限T對比,y1輸出對應的值;
總結:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.datasets import make_moons, make_circles
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import f1_score
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
class Adaboost_Demonstration:
def __init__(self, X, y, learning_rate=1.):
"""
輸入的X為N*2矩陣, y為一維向量, y的值只能取1或-1
:param X: 數據點
:param y: 數據點標記
"""
self.X = X
self.y = y
# 給每個弱分類器一個衰減, 避免過擬合
self.learning_rate = learning_rate
# 樣本的個數
self.num_samples = len(self.X)
# 初始化數據樣本的權重
self.sample_weight = np.full(self.num_samples, 1 / self.num_samples)
# python list用來存儲所有的弱分類器對象
self.classifiers = []
# 儲存在每一步的錯誤率
self.errors_list = []
# 定義弱分類器, 這里我們直接調用sklearn的決策樹, max_depth=1代表着這是一個一層決策樹, 也就是決策樹樁
self.alphas = []
def predict(self, data=None, labels=None, reduction="sign"):
"""
預測數據點的分類
:param reduction: "sign"對弱分類的線性加權組合取符號, "mean"取平均
"""
if data is None:
data = self.X
labels = self.y
# 計算弱分類器線性加權組合的結果
predictions = np.zeros([len(data)]).astype("float")
for classifier, alpha in zip(self.classifiers, self.alphas):
predictions += alpha * classifier.predict(data)
# 對結果取符號
if reduction == "sign":
predictions = np.sign(predictions)
# 對結果求均值
elif reduction == "mean":
predictions /= len(self.classifiers)
# 如果可以的話獲取f1 score
if labels is not None and reduction == "sign":
f1 = f1_score(predictions, labels)
return predictions, f1
else:
return predictions
def contour_plot(self, data=None, labels=None, interval=0.2, title="adaboost",
mode="3d"):
"""
等高線圖可視化
:param interval: 等高線圖網格的間隔
:param title: 等高線圖的標題
:param mode: 可選3D或2D可視化
"""
if data is None:
data = self.X
labels = self.y
if labels is None:
labels = np.ones([len(data)])
# 獲取網格
x_min, x_max = data[:, 0].min() - .5, data[:, 0].max() + .5
y_min, y_max = data[:, 1].min() - .5, data[:, 1].max() + .5
xx, yy = np.meshgrid(np.arange(x_min, x_max, interval), np.arange(y_min, y_max, interval))
# 將網格的X, Y軸拼接用來進行等高線的計算
X_grid = np.concatenate([np.expand_dims(np.ravel(xx), axis=-1),
np.expand_dims(np.ravel(yy), axis=-1)], axis=-1)
# X_grid的形狀[batch(數據點數量), 2]
# 計算分類邊界(等高線)
Z_grid = self.predict(data=X_grid, reduction="mean")
Z_grid = Z_grid.reshape(xx.shape)
# 可視化
if mode == "3d":
# 數據點畫散點圖
scatter = go.Scatter3d(x=data[:, 0], y=data[:, 1], z=self.predict(data=data, reduction="mean"),
mode='markers',
marker=dict(color=labels, size=5, symbol='circle',
line=dict(color='rgb(204, 204, 204)', width=1),
opacity=0.9))
# 等高線3D輪廓圖
surface = go.Surface(x=xx, y=yy, z=Z_grid, opacity=0.9)
plot_data = [scatter, surface]
layout = go.Layout(title=title)
# 設置視角
camera = dict(up=dict(x=0, y=0, z=1),
center=dict(x=0, y=0, z=0),
eye=dict(x=1, y=1, z=0.8))
fig = go.Figure(data=plot_data, layout=layout)
fig['layout'].update(scene=dict(camera=camera))
iplot(fig, image="png", filename=title)
if mode == "2d":
# 等高線
plt.contourf(xx, yy, Z_grid, cmap=plt.cm.RdBu, alpha=.8)
# 散點
plt.scatter(data[:, 0], data[:, 1], c=labels,
cmap=ListedColormap(['#FF0000', '#0000FF']), edgecolors='k')
plt.title(title)
plt.show()
def __next__(self, reduction="mean", plot=True, plot_mode="2d"):
# 定義弱分類器(決策樹樁)
# classifier = DecisionTreeClassifier(
# max_depth=2,min_samples_split=20,
# min_samples_leaf=5)
classifier = DecisionTreeClassifier(max_depth=1)
# 用弱分類器擬合數據
classifier.fit(self.X, self.y, sample_weight=self.sample_weight)
# 得到弱分類器對數據的推斷, 也就是h(x)
predictions = classifier.predict(self.X)
# 計算錯誤率
error_rate = np.mean(np.average((predictions != self.y), weights=self.sample_weight))
# 計算alpha
alpha = self.learning_rate * (np.log((1 - error_rate) / error_rate)) / 2
# 計算t+1的權重
self.sample_weight *= np.exp(-alpha * self.y * predictions)
# 歸一化, 歸一化因子為Z: sum(self.sample_weight)
self.sample_weight /= np.sum(self.sample_weight)
# 記錄當前弱分類器對象
self.classifiers.append(classifier)
# 記錄當前弱分類器權重
self.alphas.append(alpha)
# 計算f1 score
_, f1 = self.predict()
# 畫圖
if plot:
return self.contour_plot(
title="adaboost step " + str(len(self.classifiers)) + " f1 score: {:.2f}".format(f1), mode=plot_mode)
else:
return f1
if __name__ == '__main__':
# 測試
X, y = make_moons(n_samples=300, noise=0.2, random_state=3)
y[np.where(y == 0)] = -1
model = Adaboost_Demonstration(X, y)
for i in range(100):
model.__next__(plot=False)
model.contour_plot(mode="2d")
參考:https://blog.csdn.net/jasonding1354/article/details/37558287
機器學習之數學之旅-從零推導adaboost與3D可視化-特征選擇-集體智能-集成學習-boosting
代碼:https://github.com/aespresso/a_journey_into_math_of_ml
