基於隨機森林演算法進行硬碟故障預測

華為雲開發者聯盟發表於2022-12-24
摘要:本案例將帶大家使用一份開源的S.M.A.R.T.資料集和機器學習中的隨機森林演算法,來訓練一個硬碟故障預測模型,並測試效果。

本文分享自華為雲社群《基於隨機森林演算法進行硬碟故障預測》,作者:HWCloudAI 。

實驗目標

  1. 掌握使用機器學習方法訓練模型的基本流程;
  2. 掌握使用pandas做資料分析的基本方法;
  3. 掌握使用scikit-learn進行隨機森林模型的構建、訓練、儲存、載入、預測、統計準確率指標和檢視混淆矩陣的方法;

案例內容介紹

隨著網際網路、雲端計算的發展,資料的儲存需求與日倍增,大規模海量資料儲存中心是必不可少的基礎性設施。雖然新的儲存介質例如SSD,已經很多方面擁有了比磁碟更好的效能,但就目前來講,其高昂的花費仍然使大部分資料中心難以負擔,因此,大型資料中心依然會採用傳統的機械硬碟作為儲存介質。

機械硬碟生命週期通常為3到5年,在2到3年後故障率明顯升高,導致換盤量陡增。據統計,在伺服器硬體故障中,硬碟故障佔比達到48%+,是影響伺服器執行可靠性的重要因素。早在上個世紀九十年代,人們就意識到資料的寶貴性遠勝於硬碟自身價值,渴望有種技術能對硬碟故障進行預測並實現相對安全的資料保護,因此S.M.A.R.T.技術應運而生。

S.M.A.R.T.,全稱為“Self-Monitoring Analysis and Reporting Technology”,即“自我監測、分析及報告技術”,是一種自動的硬碟狀態檢測與預警系統和規範。透過在硬碟硬體內的檢測指令對硬碟的硬體如磁頭、碟片、馬達、電路的執行情況進行監控、記錄並與廠商所設定的預設安全值進行比較,若監控情況將或已超出預設安全值的安全範圍,就可以透過主機的監控硬體或軟體自動向使用者作出警告並進行輕微的自動修復,以提前保障硬碟資料的安全。除一些出廠時間極早的硬碟外,現在大部分硬碟均配備該項技術。關於該技術的更多介紹,請檢視S.M.A.R.T.-百度百科。

雖然硬碟廠商採用了S.M.A.R.T.技術來監測硬碟的健康狀態,但是大多數廠商都是基於設計規則制定的故障預測手段,預測效果非常差,不能滿足日漸嚴格的提前預測硬碟故障的需求。因此,業界期望使用機器學習技術來構建硬碟故障預測的模型,更準確地提前感知硬碟故障,降低運維成本,提升業務體驗。

本案例將帶大家使用一份開源的S.M.A.R.T.資料集和機器學習中的隨機森林演算法,來訓練一個硬碟故障預測模型,並測試效果。
關於隨機森林演算法的理論知識,可參考此影片

注意事項

  1. 如果你是第一次使用 JupyterLab,請檢視《ModelAtrs JupyterLab使用指導》瞭解使用方法;
  2. 如果你在使用 JupyterLab 過程中碰到報錯,請參考《ModelAtrs JupyterLab常見問題解決辦法》嘗試解決問題。

 

實驗步驟

1. 資料集介紹

本案例使用的資料集是來自於Backblaze公司的開源資料集,它是一家計算機備份和雲端儲存服務提供商。自2013年以來,Backbreze每年都會公開發布他們的資料中心所使用硬碟的S.M.A.R.T.日誌資料,有效地推動了使用機器學習技術進行硬碟故障預測的發展。

由於Backblaze公司釋出的S.M.A.R.T.日誌資料量較大,本案例為快速演示使用機器學習構建硬碟故障預測模型的過程,僅使用了該公司釋出的2020年的資料,相關資料已經準備好,放在OBS中,執行如下程式碼即可下載這部分資料。

import os
import moxing as mox
if not os.path.exists('./dataset_2020'):
    mox.file.copy('obs://modelarts-labs-bj4-v2/course/ai_in_action/2021/machine_learning/hard_drive_disk_fail_prediction/datasets/dataset_2020.zip', './dataset_2020.zip')
    os.system('unzip dataset_2020.zip')

if not os.path.exists('./dataset_2020'):
    raise Exception('錯誤!資料不存在!')

!ls -lh ./dataset_2020
INFO:root:Using MoXing-v1.17.3-

INFO:root:Using OBS-Python-SDK-3.20.7
total 102M

-rw-r--r-- 1 ma-user ma-group  51M Mar 21 11:56 2020-12-08.csv

-rw-r--r-- 1 ma-user ma-group  51M Mar 21 11:56 2020-12-09.csv

-rw-r--r-- 1 ma-user ma-group 1.2M Mar 21 11:55 dataset_2020.csv

-rw-r--r-- 1 ma-user ma-group 3.5K Mar 22 15:59 prepare_data.py

資料解釋:

2020-12-08.csv:從backblaze公司釋出的2020 Q4資料集中抽取出來的2020-12-08這天的S.M.A.R.T.日誌資料
2020-12-09.csv:從backblaze公司釋出的2020 Q4資料集中抽取出來的2020-12-09這天的S.M.A.R.T.日誌資料
dataset_2020.csv:已經處理過的2020年全年S.M.A.R.T.日誌資料,下文中“第2.6節 類別均衡度分析”會解釋如何得到這部分資料
prepare_data.py: 執行該指令碼,會下載2020年全年S.M.A.R.T.日誌資料,並進行處理,得到dataset_2020.csv。執行該指令碼需要20G的本地儲存空間

2. 資料分析

使用機器學習構建任何模型之前,都需要先對資料集進行分析,瞭解資料集的規模、屬性名、屬性值、各類統計指標及空值情況。因為我們要先了解資料,才能用好資料。

2.1 讀取csv檔案

pandas是常用的python資料分析模組,我們先用它來載入資料集中的csv檔案。以2020-12-08.csv為例,我們先載入該檔案來分析S.M.A.R.T.日誌資料的情況

import pandas as pd
df_data = pd.read_csv("./dataset_2020/2020-12-08.csv")
type(df_data)
pandas.core.frame.DataFrame

2.2 檢視單個csv檔案資料的規模

print('單個csv檔案資料的規模,行數:%d, 列數:%d' % (df_data.shape[0], df_data.shape[1]))
單個csv檔案資料的規模,行數:162008, 列數:149

2.3 檢視頭5行資料

使用pandas載入csv後,得到的是一個DataFrame物件,可以理解為一個表格,呼叫該物件的head()函式,可以檢視錶格的頭5行資料

df_data.head()

<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }

.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}

</style>

基於隨機森林演算法進行硬碟故障預測

5 rows × 149 columns

如上所示是表格的頭5行資料,表頭是屬性名,屬性名下面是屬性值,backblaze網站解釋了屬性值的含義,翻譯為如下:

基於隨機森林演算法進行硬碟故障預測

2.4 檢視資料的統計指標

檢視完表格的頭5行資料,我們再呼叫DataFrame物件的describe()函式,計算表格資料的統計指標

df_data.describe()

<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }

.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}

</style>

基於隨機森林演算法進行硬碟故障預測

8 rows × 146 columns

如上所示是表格資料的統計指標,describe()函式預設對數值型別的列進行統計分析,由於表格的前三列’date’、‘serial_number’、'model’是字串型別,所以這三列沒有統計指標。

各行統計指標的含義解釋如下:

count: 該列有多少個非空值
mean: 該列的均值
std: 該列數值的標準差
min: 該列數值的最小值
25%: 該列數值的25%中位值
50%: 該列數值的50%中位值
75%: 該列數值的75%中位值
max: 該列數值的最大值

2.5 檢視資料空值情況

從上面的輸出可以觀察到,某些屬性的count指標比較小,比如smart_2_raw的count數就比df_train的總行數要小很多,因此我們要再進一步看看各列屬性的空值情況,執行如下程式碼可以檢視空值情況

df_data.isnull().sum()
date                         0
serial_number 0
model                        0
capacity_bytes 0
failure                      0
smart_1_normalized         179
smart_1_raw                179
smart_2_normalized      103169
smart_2_raw             103169
smart_3_normalized        1261
smart_3_raw               1261
smart_4_normalized        1261
smart_4_raw               1261
smart_5_normalized        1221
smart_5_raw               1221
smart_7_normalized        1261
smart_7_raw               1261
smart_8_normalized      103169
smart_8_raw             103169
smart_9_normalized         179
smart_9_raw                179
smart_10_normalized       1261
smart_10_raw              1261
smart_11_normalized     161290
smart_11_raw            161290
smart_12_normalized        179
smart_12_raw               179
smart_13_normalized     161968
smart_13_raw            161968
smart_15_normalized     162008
 ... 
smart_232_normalized    160966
smart_232_raw           160966
smart_233_normalized    160926
smart_233_raw           160926
smart_234_normalized    162008
smart_234_raw           162008
smart_235_normalized    160964
smart_235_raw           160964
smart_240_normalized     38968
smart_240_raw            38968
smart_241_normalized     56030
smart_241_raw            56030
smart_242_normalized     56032
smart_242_raw            56032
smart_245_normalized    161968
smart_245_raw           161968
smart_247_normalized    162006
smart_247_raw           162006
smart_248_normalized    162006
smart_248_raw           162006
smart_250_normalized    162008
smart_250_raw           162008
smart_251_normalized    162008
smart_251_raw           162008
smart_252_normalized    162008
smart_252_raw           162008
smart_254_normalized    161725
smart_254_raw           161725
smart_255_normalized    162008
smart_255_raw           162008
Length: 149, dtype: int64

這種顯示方式不太方便檢視,我們把可以空值的數量繪製成曲線圖,看起來更直觀

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
df_data_null_num = df_data.isnull().sum()
x = list(range(len(df_data_null_num)))
y = df_data_null_num.values
plt.plot(x, y)
plt.show()
基於隨機森林演算法進行硬碟故障預測

從上面的結果可以看出,表格中的某些屬性有大量的空值。

在機器學習領域中,資料集中存在空值是很常見的現象,引起空值的原因有很多種,比如一份使用者畫像中有很多個屬性,但又不是所有使用者都有對應的屬性值,這時就產生了空值。或者某些資料因為傳輸超時,導致沒有采集上來,也可能會出現空值。

2.6 類別均衡度分析

我們要實現的任務是“硬碟故障預測”,即預測某個硬碟在某個時間是正常還是損壞,這就是一個故障預測問題或異常檢測問題,這類問題有個特點就是:正常樣本非常多,故障樣本非常少,兩類樣本的數量差異非常大。
比如,執行如下程式碼,可以看到df_data中硬碟正常的樣本有16萬個以上,故障的樣本卻只有8個,類別極度不均衡。

valid = df_data[df_data['failure'] == 0]
failed = df_data[df_data['failure'] == 1]
print("valid hdds:",len(valid))
print("failed hdds:",len(failed))
valid hdds: 162000
failed hdds: 8

由於大多數機器學習方法的學習過程都是基於統計學的思路來進行學習的,如果直接使用上面這樣類別不均衡的資料進行訓練,那麼模型的能力可能會明顯偏向於類別多的樣本,類別少的樣本就會被“淹沒”掉了,在學習過程中發揮不了作用,因此我們需要平衡不同類別的資料。

為了獲得更多的故障樣本資料,我們可以從backblaze公司釋出的2020年全年S.M.A.R.T.日誌資料中將所有的故障樣本都挑選出來,同時也隨機挑出相同數量的正常樣本,可以透過下面的程式碼來實現。

這段程式碼已被註釋掉,如需執行,需要20G的本地儲存空間。您也可以不必執行這段程式碼,因為本案例開頭已經下載了dataset_2020.zip,這個壓縮包中已經提供了dataset_2020.csv,該csv就是執行下面這段程式碼得到的檔案

# if not os.path.exists('./dataset_2020/dataset_2020.csv'):
#     os.system('python ./dataset_2020/prepare_data.py')
import gc
del df_data # 刪除 df_data 物件
gc.collect() # 回收記憶體
2655

2.7 載入類別均衡的資料集

dataset_2020.csv是已經經過類別均衡處理的硬碟S.M.A.R.T.日誌資料,下面我們載入該檔案,再確認一下類別均衡情況

df_data = pd.read_csv("./dataset_2020/dataset_2020.csv")
valid = df_data[df_data['failure'] == 0]
failed = df_data[df_data['failure'] == 1]
print("valid hdds:", len(valid))
print("failed hdds:", len(failed))
valid hdds: 1497
failed hdds: 1497

可以看到,正常樣本和故障樣本都是1497個

3. 特徵工程

準備好可用的訓練集之後,接下來要做特徵工程,通俗地講,特性工程就是要選擇表格中的哪些屬性來構建機器學習模型。人工設計特徵的好壞,很大程度上決定了機器學習模型效果的好壞,所以機器學習領域的研究人員需耗費大量精力在人工設計特徵上,是一項比較耗時、耗力,且需要專家經驗的工程。

3.1 SMART屬性與硬碟故障的相關研究

(1)BackBlaze分析了其HDD故障和SMART屬性之間的相關性,並發現了SMART 5、187、188、197、198與HDD故障的相關率最高,這些SMART屬性還與掃描錯誤,重新分配計數和試用計數有關[1];
(2)El-Shimi等發現在隨機森林模型中除了以上5個特徵外,還有SMART 9、193、194、241、242這5個屬性有最大權重[2];
(3)Pitakrat等人評估了21種用於預測硬碟故障的機器學習演算法,發現在測試的21種機器學習演算法中,隨機森林演算法在ROC曲線下有最大面積,而KNN分類器具有最高的F1值[3];
(4)Hughes等人也研究用於預測硬碟故障的機器學習方法,他們分析了SVM、樸素貝葉斯的表現,SVM實現了最高效能,檢測率為50.6%,誤報率為0%[4];

[1] Klein, Andy. “What SMART Hard Disk Errors Actually Tell Us.” Backblaze Blog Cloud Storage & Cloud Backup,6 Oct. 2016, www.backblaze.com/blog/what-smart-stats-indicate-hard-drive-failures/
[2] El-Shimi, Ahmed. “Predicting Storage Failures.” VAULT-Linux Storage and File Systems Conference.VAULT-Linux Storage and File Systems Conference, 22 Mar. 2017, Cambridge.
[3] Pitakrat, Teerat, André van Hoorn, and Lars Grunske. “A comparison of machine learning algorithms for proactive hard disk drive failure detection.” Proceedings of the 4th international ACM Sigsoft symposium on Architecting critical systems. ACM, 2013.
[4] Hughes, Gordon F., et al. “Improved disk-drive failure warnings.” IEEE Transactions on Reliability 51.3 (2002):350-357.

如上就是前人的一些研究成果,本案例計劃採用隨機森林模型,因此可以根據上面第2條研究成果,選擇SMART 5, 9, 187, 188, 193, 194, 197, 198, 241, 242這些屬性來作為特徵,它們的含義分別是:

SMART 5: 重對映扇區計數
SMART 9: 通電時間累計
SMART 187: 無法校正的錯誤
SMART 188: 指令超時計數
SMART 193: 磁頭載入/解除安裝計數
SMART 194: 溫度
SMART 197: 等待被對映的扇區數
SMART 198: 報告給作業系統的無法透過硬體ECC校正的錯誤
SMART 241: 邏輯塊定址模式寫入總數
SMART 242: 邏輯塊定址模式讀取總數

另外,由於不同硬碟廠商的不同型號硬碟記錄SMART日誌資料的標準可能不一樣,所以我們最好將同一型號的硬碟資料挑出來作為訓練資料,專門訓練一個預測該型號硬碟是否故障的模型。如果需要預測多個不同型號的硬碟是否故障,則可能需要分別訓練多個模型。

3.2 硬碟型號選擇

執行下面的程式碼,看一下每種型號的硬碟資料量有多少

df_data.model.value_counts()
ST12000NM0007 664
ST4000DM000 491
ST8000NM0055 320
ST12000NM0008 293
TOSHIBA MG07ACA14TA 212
ST8000DM002 195
HGST HMS5C4040BLE640 193
HGST HUH721212ALN604 153
TOSHIBA MQ01ABF050 99
ST12000NM001G 53
HGST HMS5C4040ALE640 50
ST500LM012 HN 40
TOSHIBA MQ01ABF050M 35
HGST HUH721212ALE600 34
ST10000NM0086 29
ST14000NM001G 23
HGST HUH721212ALE604 21
ST500LM030 15
HGST HUH728080ALE600 14
Seagate BarraCuda SSD ZA250CM10002 12
WDC WD5000LPVX 11
WDC WUH721414ALE6L4 10
ST6000DX000 9
TOSHIBA MD04ABA400V 3
Seagate SSD 2
ST8000DM004 2
ST18000NM000J 2
ST4000DM005 2
WDC WD5000LPCX 1
ST8000DM005 1
DELLBOSS VD 1
HGST HDS5C4040ALE630 1
TOSHIBA HDWF180 1
HGST HUS726040ALE610 1
ST16000NM001G 1
Name: model, dtype: int64

可以看到 ST12000NM0007 型號的硬碟資料量最多,因此我們把該型號硬碟的資料過濾出來

df_data_model = df_data[df_data['model'] == 'ST12000NM0007']

3.3 特徵選擇

選取上文提到的10個屬性作為特徵

features_specified = []
features = [5, 9, 187, 188, 193, 194, 197, 198, 241, 242]
for feature in features:
 features_specified += ["smart_{0}_raw".format(feature)]
X_data = df_data_model[features_specified]
Y_data = df_data_model['failure']
X_data.isnull().sum()
smart_5_raw      1
smart_9_raw      1
smart_187_raw    1
smart_188_raw    1
smart_193_raw    1
smart_194_raw    1
smart_197_raw    1
smart_198_raw    1
smart_241_raw    1
smart_242_raw    1
dtype: int64

有空值存在,所以先要填充空值

X_data = X_data.fillna(0) 
print("valid hdds:", len(Y_data) - np.sum(Y_data.values))
print("failed hdds:", np.sum(Y_data.values))
valid hdds: 325
failed hdds: 339

3.4 劃分訓練集和測試集

使用sklearn的train_test_split即可劃分訓練集和測試集,test_size表示測試集的比例,一般取值為0.3、0.2或0.1

from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X_data, Y_data, test_size=0.2, random_state=0) 

4. 開始訓練

4.1 構建模型

準備好訓練集和測試集之後,就可以開始構建模型了,構建模型的步驟非常簡單,直接呼叫機器學習框架sklearn中的RandomForestClassifier即可

from sklearn.ensemble import RandomForestClassifier 
rfc = RandomForestClassifier()

隨機森林演算法的超引數有很多個,取不同的引數值構建模型會得到不同的訓練效果,對於初學者,可以直接使用庫中提供的預設引數值,在對隨機森林演算法的原理有一定的瞭解之後,可以嘗試修改模型的引數來調整模型的訓練效果。

4.2 資料擬合

模型訓練的過程,也就是擬合訓練資料的過程,實現也非常簡單,呼叫fit函式即可開始訓練

rfc.fit(X_train, Y_train)
/home/ma-user/anaconda3/envs/XGBoost-Sklearn/lib/python3.6/site-packages/sklearn/ensemble/forest.py:248: FutureWarning: The default value of n_estimators will change from 10 in version 0.20 to 100 in 0.22.
 "10 in version 0.20 to 100 in 0.22.", FutureWarning)
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
 max_depth=None, max_features='auto', max_leaf_nodes=None,
 min_impurity_decrease=0.0, min_impurity_split=None,
 min_samples_leaf=1, min_samples_split=2,
 min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,
 oob_score=False, random_state=None, verbose=0,
 warm_start=False)

5 開始預測

呼叫predict函式即可開始預測

Y_pred = rfc.predict(X_test) 

5.1 統計預測準確率

在機器學習中,分類問題的效能指標,常用的有四種:accuracy(精度)、precision(查準率)、recall(查全率)、F1-Score,四種指標越接近1,表示效果越好。sklearn庫中有這四種指標的函式,直接呼叫即可。

關於四種指標的理論解釋,可參考此影片

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
print("Model used is: Random Forest classifier") 
acc = accuracy_score(Y_test, Y_pred) 
print("The accuracy is {}".format(acc)) 
prec = precision_score(Y_test, Y_pred) 
print("The precision is {}".format(prec)) 
rec = recall_score(Y_test, Y_pred) 
print("The recall is {}".format(rec)) 
f1 = f1_score(Y_test, Y_pred) 
print("The F1-Score is {}".format(f1)) 
Model used is: Random Forest classifier
The accuracy is 0.8270676691729323
The precision is 0.8548387096774194
The recall is 0.7910447761194029
The F1-Score is 0.8217054263565892

每次進行隨機森林模型的訓練,會得到該模型不同的測試準確率指標,這是由於隨機森林演算法的訓練過程具有一定的隨機性導致的,是正常現象。但是同一模型、同一樣本的預測結果是確定不變的。

5.2 模型儲存、載入、再預測

模型儲存

import pickle
with open('hdd_failure_pred.pkl', 'wb') as fw:
 pickle.dump(rfc, fw)

模型載入

with open('hdd_failure_pred.pkl', 'rb') as fr:
 new_rfc = pickle.load(fr)

模型再預測

new_Y_pred = new_rfc.predict(X_test)
new_prec = precision_score(Y_test, new_Y_pred)
print("The precision is {}".format(new_prec))
The precision is 0.8548387096774194

5.3 檢視混淆矩陣

要分析分類模型的效果如何,還可以使用混淆矩陣來檢視,混淆矩陣的橫軸表示預測結果的各個類別,縱軸表示真實標籤的類別,矩陣方格中的值就代表對應橫縱座標重疊的測試樣本數量。

import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix 
LABELS = ['Healthy', 'Failed'] 
conf_matrix = confusion_matrix(Y_test, Y_pred) 
plt.figure(figsize =(6, 6)) 
sns.heatmap(conf_matrix, xticklabels = LABELS, 
 yticklabels = LABELS, annot = True, fmt ="d"); 
plt.title("Confusion matrix") 
plt.ylabel('True class') 
plt.xlabel('Predicted class') 
plt.show() 
基於隨機森林演算法進行硬碟故障預測

6. 改進模型的思路

如上內容是使用隨機森林演算法構建硬碟故障預測模型的過程演示,模型精度並不算高,有如下幾個思路可以提升模型的精度:

(1)本案例只使用了Backblaze公司2020年的資料,您可以嘗試使用更多的訓練資料;
(2)本案例只使用了10個SMART屬性作為特徵,您可以嘗試使用其他方法來構建特徵;
(3)本案例使用了隨機森林演算法來訓練模型,您可以嘗試使用其他的機器學習演算法;

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章