機器學習演算法(八):基於BP神經網路的乳腺癌的分類預測
1.演算法簡介和應用
1.1 演算法簡介
BP(Back Propagation)網路是1986年由Rumelhart和McCelland為首的科學家小組提出,是一種按誤差逆傳播演算法訓練的多層前饋網路,是目前應用最廣泛的神經網路模型之一。BP網路能學習和存貯大量的輸入-輸出模式對映關係,而無需事前揭示描述這種對映關係的數學方程。它的學習規則是使用最速下降法,透過反向傳播來不斷調整網路的權值和閾值,使網路的誤差平方和最小。BP神經網路模型拓撲結構包括輸入層(input)、隱層(hide layer)和輸出層(output layer)。在模擬過程中收集系統所產生的誤差,透過誤差反傳,然後調整權值大小,透過該不斷迭代更新,最後使得模型趨於整體最最佳化(這是一個迴圈,我們在訓練神經網路的時候是要不斷的去重複這個過程的)。
BP神經網路模型要點在於資料的前向傳播和誤差反向傳播,來對引數進行更新,使得損失最小化。 誤差反向傳播演算法簡稱反向傳播演算法(即BP演算法)。使用反向傳播演算法的多層感知器又稱為BP神經網路。BP演算法是一個迭代演算法,它的基本思想為:
(1)先計算每一層的狀態和啟用值,直到最後一層(即訊號是前向傳播的);
(2)計算每一層的誤差,誤差的計算過程是從最後一層向前推進的(這就是反向傳播演算法名字的由來);
(3)更新引數(目標是誤差變小)。迭代前面兩個步驟,直到滿足停止準則(比如相鄰兩次迭代的誤差的差別很小)。
在這個過程,函式的導數鏈式法則求導很重要,需要手動推導BP神經網路模型的梯度反向傳播過程,熟練掌握鏈式法則進行求導,對引數進行更新。
1.2.演算法應用
BP反映了生物神經系統處理外界事物的基本過程,是在模擬人腦神經組織的基礎上發展起來的計算系統,是由大量處理單元透過廣泛互聯而構成的網路體系,它具有生物神經系統的基本特徵,在一定程度上反映了人腦功能的若干反映,是對生物系統的某種模擬,具有大規模並行、分散式處理、自組織、自學習等優點,被廣泛應用於語音分析、影像識別、數字水印、計算機視覺等很多領域,取得了許多突出的成果。最近由於人工神經網路的快速發展,它已經成為模式識別的強有力的工具。神經網路的運用展開了新的領域,解決其它模式識別不能解決的問題,其分類功能特別適合於模式識別與分類的應用。
2.相關流程
- 掌握BP演算法基本原理
- 掌握利用BP進行程式碼實戰
-
Part 1 Demo實踐
- Step1:庫函式匯入
- Step2:模型訓練
- Step3:模型引數檢視
- Step4:資料和模型視覺化
- Step5:模型預測
-
Part 2 基於BP神經網路的乳腺癌分類實踐
- Step1:庫函式匯入
- Step2:資料讀取/載入
- Step3:資料資訊簡單檢視與視覺化
- Step4:利用BP神經網路在乳腺癌資料上進行訓練和預測
3.程式碼實戰
3.1 Part 1 Demo實踐
- Step1:庫函式匯入
# 基礎陣列運算庫匯入
import numpy as np
# 畫相簿匯入
import matplotlib.pyplot as plt
# 匯入三維顯示工具
from mpl_toolkits.mplot3d import Axes3D
# 匯入BP模型
from sklearn.neural_network import MLPClassifier
# 匯入demo資料製作方法
from sklearn.datasets import make_classification
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import warnings
from sklearn.exceptions import ConvergenceWarning
- Step2:模型訓練
# 製作五個類別的資料,每個類別1000個樣本
train_samples, train_labels = make_classification(n_samples=1000, n_features=3, n_redundant=0,
n_classes=5, n_informative=3, n_clusters_per_class=1,
class_sep=3, random_state=10)
# 將五個類別的資料進行三維顯示
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax.scatter(train_samples[:, 0], train_samples[:, 1], train_samples[:, 2], marker='o', c=train_labels)
plt.title('Demo Data Map')
Text(0.5,0.92,'Demo Data Map')
# 建立 BP 模型, 採用sgd最佳化器,relu非線性對映函式
BP = MLPClassifier(solver='sgd',activation = 'relu',max_iter = 500,alpha = 1e-3,hidden_layer_sizes = (32,32),random_state = 1)
# 進行模型訓練
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=ConvergenceWarning,
module="sklearn")
BP.fit(train_samples, train_labels)
- Step3:模型引數檢視
# 檢視 BP 模型的引數
print(BP)
MLPClassifier(alpha=0.001, hidden_layer_sizes=(32, 32), max_iter=500,
random_state=1, solver='sgd')
- Step4:資料和模型視覺化
# 進行模型預測
predict_labels = BP.predict(train_samples)
# 顯示預測的散點圖
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax.scatter(train_samples[:, 0], train_samples[:, 1], train_samples[:, 2], marker='o', c=predict_labels)
plt.title('Demo Data Predict Map with BP Model')
# 顯示預測分數
print("預測準確率: {:.4f}".format(BP.score(train_samples, train_labels)))
# 視覺化預測資料
print("真實類別:", train_labels[:10])
print("預測類別:", predict_labels[:10])
# 準確率等報表
print(classification_report(train_labels, predict_labels))
# 計算混淆矩陣
classes = [0, 1, 2, 3]
cofusion_mat = confusion_matrix(train_labels, predict_labels, classes)
sns.set()
figur, ax = plt.subplots()
# 畫熱力圖
sns.heatmap(cofusion_mat, cmap="YlGnBu_r", annot=True, ax=ax)
ax.set_title('confusion matrix') # 標題
ax.set_xticklabels([''] + classes, minor=True)
ax.set_yticklabels([''] + classes, minor=True)
ax.set_xlabel('predict') # x軸
ax.set_ylabel('true') # y軸
plt.show()
預測準確率: 0.9950
真實類別: [0 4 2 2 3 2 3 0 1 0]
預測類別: [0 4 2 2 3 2 3 0 1 0]
precision recall f1-score support
0 0.98 0.99 0.99 198
1 1.00 0.99 0.99 203
2 1.00 1.00 1.00 200
3 0.99 1.00 1.00 199
4 0.99 0.99 0.99 200
accuracy 0.99 1000
macro avg 0.99 1.00 0.99 1000
weighted avg 1.00 0.99 1.00 1000
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/sklearn/utils/validation.py:72: FutureWarning: Pass labels=[0, 1, 2, 3] as keyword args. From version 1.0 (renaming of 0.25) passing these as positional arguments will result in an error
"will result in an error", FutureWarning)
- Step5:模型預測
# 進行新的測試資料測試
test_sample = np.array([[-1, 0.1, 0.1]])
print(f"{test_sample} 類別是: ", BP.predict(test_sample))
print(f"{test_sample} 類別機率分別是: ", BP.predict_proba(test_sample))
test_sample = np.array([[-1.2, 10, -91]])
print(f"{test_sample} 類別是: ", BP.predict(test_sample))
print(f"{test_sample} 類別機率分別是: ", BP.predict_proba(test_sample))
test_sample = np.array([[-12, -0.1, -0.1]])
print(f"{test_sample} 類別是: ", BP.predict(test_sample))
print(f"{test_sample} 類別機率分別是: ", BP.predict_proba(test_sample))
test_sample = np.array([[100, -90.1, -9.1]])
print(f"{test_sample} 類別是: ", BP.predict(test_sample))
print(f"{test_sample} 類別機率分別是: ", BP.predict_proba(test_sample))
[[-1. 0.1 0.1]] 類別是: [4]
[[-1. 0.1 0.1]] 類別機率分別是: [[0.08380116 0.1912275 0.17608601 0.16488309 0.38400224]]
[[ -1.2 10. -91. ]] 類別是: [1]
[[ -1.2 10. -91. ]] 類別機率分別是: [[3.37231505e-30 1.00000000e+00 4.24566351e-51 1.92771500e-57
5.16916174e-17]]
[[-12. -0.1 -0.1]] 類別是: [4]
[[-12. -0.1 -0.1]] 類別機率分別是: [[1.42696980e-06 5.86057194e-05 2.99819240e-05 3.03896335e-05
9.99879596e-01]]
[[100. -90.1 -9.1]] 類別是: [2]
[[100. -90.1 -9.1]] 類別機率分別是: [[2.45024178e-02 8.44965777e-67 9.75497582e-01 1.41511057e-66
4.23516105e-50]]
3.2 Part 2 基於BP神經網路的乳腺癌分類實踐
- Step1:庫函式匯入
# 匯入乳腺癌資料集
from sklearn.datasets import load_breast_cancer
# 匯入BP模型
from sklearn.neural_network import MLPClassifier
# 匯入訓練集分割方法
from sklearn.model_selection import train_test_split
# 匯入預測指標計算函式和混淆矩陣計算函式
from sklearn.metrics import classification_report, confusion_matrix
# 匯入繪圖包
import seaborn as sns
import matplotlib
- Step2:資料讀取/載入
# 匯入乳腺癌資料集
cancer = load_breast_cancer()
- Step3:資料資訊簡單檢視與視覺化
# 檢視資料集資訊
print('breast_cancer資料集的長度為:',len(cancer))
print('breast_cancer資料集的型別為:',type(cancer))
# 分割資料為訓練集和測試集
cancer_data = cancer['data']
print('cancer_data資料維度為:',cancer_data.shape)
cancer_target = cancer['target']
print('cancer_target標籤維度為:',cancer_target.shape)
cancer_names = cancer['feature_names']
cancer_desc = cancer['DESCR']
#分為訓練集與測試集
cancer_data_train,cancer_data_test = train_test_split(cancer_data,test_size=0.2,random_state=42)#訓練集
cancer_target_train,cancer_target_test = train_test_split(cancer_target,test_size=0.2,random_state=42)#測試集
breast_cancer資料集的長度為: 7
breast_cancer資料集的型別為: <class 'sklearn.utils.Bunch'>
cancer_data資料維度為: (569, 30)
cancer_target標籤維度為: (569,)
- Step4:利用BP在乳腺癌資料上進行訓練和預測
# 建立 BP 模型, 採用Adam最佳化器,relu非線性對映函式
BP = MLPClassifier(solver='adam',activation = 'relu',max_iter = 1000,alpha = 1e-3,hidden_layer_sizes = (64,32, 32),random_state = 1)
# 進行模型訓練
BP.fit(cancer_data_train, cancer_target_train)
MLPClassifier(alpha=0.001, hidden_layer_sizes=(64, 32, 32), max_iter=1000,
random_state=1)
# 進行模型預測
predict_train_labels = BP.predict(cancer_data_train)
# 視覺化真實資料
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax.scatter(cancer_data_train[:, 0], cancer_data_train[:, 1], cancer_data_train[:, 2], marker='o', c=cancer_target_train)
plt.title('True Label Map')
plt.show()
# 視覺化預測資料
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=20, azim=20)
ax.scatter(cancer_data_train[:, 0], cancer_data_train[:, 1], cancer_data_train[:, 2], marker='o', c=predict_train_labels)
plt.title('Cancer with BP Model')
plt.show()
# 顯示預測分數
print("預測準確率: {:.4f}".format(BP.score(cancer_data_test, cancer_target_test)))
# 進行測試集資料的類別預測
predict_test_labels = BP.predict(cancer_data_test)
print("測試集的真實標籤:\n", cancer_target_test)
print("測試集的預測標籤:\n", predict_test_labels)
預測準確率: 0.9474
測試集的真實標籤:
[1 0 0 1 1 0 0 0 1 1 1 0 1 0 1 0 1 1 1 0 0 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0
1 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 0 0 1 1 1 0 0 1 1 0 0 1 0
1 1 1 0 1 1 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0 1 0 0 1 1 1 0 1 1 0
1 1 0]
測試集的預測標籤:
[1 0 0 1 1 0 0 0 1 1 1 0 1 0 1 0 1 1 1 0 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 0
1 0 1 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 1 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1
1 1 1 1 1 1 0 1 1 0 0 1 0 0 1 1 1 1 1 1 1 1 0 0 1 0 0 1 0 0 1 1 1 0 1 1 0
1 1 0]
# 進行預測結果指標統計 統計每一類別的預測準確率、召回率、F1分數
print(classification_report(cancer_target_test, predict_test_labels))
precision recall f1-score support
0 1.00 0.86 0.92 43
1 0.92 1.00 0.96 71
accuracy 0.95 114
macro avg 0.96 0.93 0.94 114
weighted avg 0.95 0.95 0.95 114
# 計算混淆矩陣
confusion_mat = confusion_matrix(cancer_target_test, predict_test_labels)
# 打混淆矩陣
print(confusion_mat)
[[37 6]
[ 0 71]]
# 將混淆矩陣以熱力圖的防線顯示
sns.set()
figure, ax = plt.subplots()
# 畫熱力圖
sns.heatmap(confusion_mat, cmap="YlGnBu_r", annot=True, ax=ax)
# 標題
ax.set_title('confusion matrix')
# x軸為預測類別
ax.set_xlabel('predict')
# y軸實際類別
ax.set_ylabel('true')
plt.show()
4. 總結
BP神經網路具有以下優點:
-
非線性對映能力:BP神經網路實質上實現了一個從輸入到輸出的對映功能,數學理論證明三層的神經網路就能夠以任意精度逼近任何非線性連續函式。這使得其特別適合於求解內部機制複雜的問題,即BP神經網路具有較強的非線性對映能力。
-
自學習和自適應能力:BP神經網路在訓練時,能夠透過學習自動提取輸入、輸出資料間的“合理規則”,並自適應地將學習內容記憶於網路的權值中。即BP神經網路具有高度自學習和自適應的能力。
-
泛化能力:所謂泛化能力是指在設計模式分類器時,即要考慮網路在保證對所需分類物件進行正確分類,還要關心網路在經過訓練後,能否對未見過的模式或有噪聲汙染的模式,進行正確的分類。也即BP神經網路具有將學習成果應用於新知識的能力。
BP神經網路具有以下缺點:
-
區域性極小化問題:從數學角度看,傳統的 BP神經網路為一種區域性搜尋的最佳化方法,它要解決的是一個複雜非線性化問題,網路的權值是透過沿區域性改善的方向逐漸進行調整的,這樣會使演算法陷入區域性極值,權值收斂到區域性極小點,從而導致網路訓練失敗。加上BP神經網路對初始網路權重非常敏感,以不同的權重初始化網路,其往往會收斂於不同的區域性極小,這也是每次訓練得到不同結果的根本原因。
-
BP 神經網路演算法的收斂速度慢:由於BP神經網路演算法本質上為梯度下降法,它所要最佳化的目標函式是非常複雜的,因此,必然會出現“鋸齒形現象”,這使得BP演算法低效;又由於最佳化的目標函式很複雜,它必然會在神經元輸出接近0或1的情況下,出現一些平坦區,在這些區域內,權值誤差改變很小,使訓練過程幾乎停頓;BP神經網路模型中,為了使網路執行BP演算法,不能使用傳統的一維搜尋法求每次迭代的步長,而必須把步長的更新規則預先賦予網路,這種方法也會引起演算法低效。以上種種,導致了BP神經網路演算法收斂速度慢的現象。
-
BP 神經網路結構選擇不一:BP神經網路結構的選擇至今尚無一種統一而完整的理論指導,一般只能由經驗選定。網路結構選擇過大,訓練中效率不高,可能出現過擬合現象,造成網路效能低,容錯性下降,若選擇過小,則又會造成網路可能不收斂。而網路的結構直接影響網路的逼近能力及推廣性質。因此,應用中如何選擇合適的網路結構是一個重要的問題。
本專案連結:https://www.heywhale.com/home/column/64141d6b1c8c8b518ba97dcc