初學者的機器學習入門實戰教程!
「2019 Python開發者日」,購票請掃碼諮詢
作者 | Adrian Rosebrock
譯者 | kbsc13,京東演算法工程師,研究領域計算機視覺
來源 | 機器學習與計算機視覺(ID:AI_Developer)
這是一篇手把手教你使用 Python 實現機器學習演算法,並在數值型數據和圖像數據集上運行模型的入門教程,當你看完本文後,你應當可以開始你的機器學習之旅了!
本教程會採用下述兩個庫來實現機器學習演算法:
scikit-learn
Keras
此外,你還將學習到:
評估你的問題
準備數據(原始數據、特徵提取、特徵工程等等)
檢查各種機器學習演算法
檢驗實驗結果
深入了解性能最好的演算法
在本文會用到的機器學習演算法包括:
KNN
樸素貝葉斯
邏輯回歸
SVM
決策樹
隨機森林
感知機
多層前向網路
CNNs
安裝必備的 Python 機器學習庫
開始本教程前,需要先確保安裝了一下的 Python 庫:
Numpy:用於 Python 的數值處理
PIL:一個簡單的圖像處理庫
scikit-learn:包含多種機器學習演算法(注意需要採用 0.2 的版本,所以下方安裝命令需要加上 --upgrade )
Kears 和 TensorFlow:用於深度學習。本教程可以僅採用 CPU 版本的 TensorFlow
OpenCV:本教程並不會採用到 OpenCV,但 imutils 庫依賴它;
imutils :作者的圖像處理/計算機視覺庫
安裝命令如下,推薦採用虛擬環境(比如利用 anaconda 創建一個新的環境):
$ pipinstallnumpy
$ pipinstallpillow
$ pipinstall--upgrade scikit-learn
$ pipinstalltensorflow# or tensorflow-gpu
$ pipinstallkeras
$ pipinstallopencv-contrib-python
$ pipinstall--upgrade imutils
數據集
本教程會用到兩個數據集來幫助更好的了解每個機器學習演算法的性能。
第一個數據集是 Iris(鳶尾花) 數據集。這個數據集的地位,相當於你剛開始學習一門編程語言時,敲下的 「Hello,World!」
這個數據集是一個數值型的數據,如下圖所示,其實就是一個表格數據,每一行代表一個樣本,然後每一列就是不同的屬性。這個數據集主要是收集了三種不同的鳶尾花的數據,分別為:
Iris Setosa
Iris Versicolor
Iris Virginica
對應圖中最後一列 Class label,然後還有四種屬性,分別是:
Sepal length--萼片長度
Sepal width--萼片寬度
Petal length--花瓣長度
Petal width--花瓣寬度
這個數據集可能是最簡單的機器學習數據集之一了,通常是用於教導程序員和工程師的機器學習和模式識別基礎的數據集。
對於該數據集,我們的目標就是根據給定的四個屬性,訓練一個機器學習模型來正確分類每個樣本的類別。
需要注意的是,其中有一個類別和另外兩個類別是線性可分的,但這兩個類別之間卻並非線性可分,所以我們需要採用一個非線性模型來對它們進行分類。當然了,在現實生活中,採用非線性模型的機器學習演算法是非常常見的。
第二個數據集是一個三場景的圖像數據集。這是幫助初學者學習如何處理圖像數據,並且哪種演算法在這兩種數據集上性能最優。
下圖是這個三場景數據集的部分圖片例子,它包括森林、高速公路和海岸線三種場景,總共是 948 張圖片,每個類別的具體圖片數量如下:
Coast: 360
Forest: 328
Highway: 260
這個三場景數據集是採樣於一個八場景數據集中,作者是 Oliva 和 Torralba 的 2001 年的一篇論文,Modeling the shape of the scene: a holistic representation of the spatial envelope
利用 Python 實現機器學習的步驟
無論什麼時候實現機器學習演算法,推薦採用如下流程來開始:
評估你的問題
準備數據(原始數據、特徵提取、特徵工程等等)
檢查各種機器學習演算法
檢驗實驗結果
深入了解性能最好的演算法
這個流程會隨著你機器學習方面的經驗的積累而改善和優化,但對於初學者,這是我建議入門機器學習時採用的流程。
所以,現在開始吧!第一步,就是評估我們的問題,問一下自己:
數據集是哪種類型?數值型,類別型還是圖像?
模型的最終目標是什麼?
如何定義和衡量「準確率」呢?
以目前自身的機器學習知識來看,哪些演算法在處理這類問題上效果很好?
最後一個問題非常重要,隨著你使用 Python 實現機器學習的次數的增加,你也會隨之獲得更多的經驗。根據之前的經驗,你可能知道有一種演算法的性能還不錯。
因此,接著就是準備數據,也就是數據預處理以及特徵工程了。
一般來說,這一步,包括了從硬碟中載入數據,檢查數據,然後決定是否需要做特徵提取或者特徵工程。
特徵提取就是應用某種演算法通過某種方式來量化數據的過程。比如,對於圖像數據,我們可以採用計算直方圖的方法來統計圖像中像素強度的分布,通過這種方式,我們就得到描述圖像顏色的特徵。
而特徵工程則是將原始輸入數據轉換成一個更好描述潛在問題的特徵表示的過程。當然特徵工程是一項更先進的技術,這裡建議在對機器學習有了一定經驗後再採用這種方法處理數據。
第三步,就是檢查各種機器學習演算法,也就是實現一系列機器學習演算法,並應用在數據集上。
這裡,你的工具箱應當包含以下幾種不同類型的機器學習演算法:
線性模型(比如,邏輯回歸,線性 SVM)
非線性模型(比如 RBF SVM,梯度下降分類器)
樹和基於集成的模型(比如 決策樹和隨機森林)
神經網路(比如 多層感知機,卷積神經網路)
應當選擇比較魯棒(穩定)的一系列機器學習模型來評估問題,因為我們的目標就是判斷哪種演算法在當前問題的性能很好,而哪些演算法很糟糕。
決定好要採用的模型後,接下來就是訓練模型並在數據集上測試,觀察每個模型在數據集上的性能結果。
在多次實驗後,你可能就是有一種「第六感」,知道哪種演算法更適用於哪種數據集。比如,你會發現:
對於有很多特徵的數據集,隨機森林演算法的效果很不錯;
而邏輯回歸演算法可以很好處理高維度的稀疏數據;
對於圖像數據,CNNs 的效果非常好。
而以上的經驗獲得,當然就需要你多動手,多進行實戰來深入了解不同的機器學習演算法了!
開始動手吧!
接下來就開始敲代碼來實現機器學習演算法,並在上述兩個數據集上進行測試。本教程的代碼文件目錄如下,包含四份代碼文件和一個 3scenes文件夾,該文件夾就是三場景數據集,而 Iris 數據集直接採用 scikit-learn 庫載入即可。
├── 3scenes
│ ├──coast[360 entries]
│ ├──forest[328 entries]
│ └──highway[260 entries]
├──classify_iris.py
├──classify_images.py
├──nn_iris.py
└──basic_cnn.py
首先是實現 classify_iris.py,這份代碼是採用機器學習演算法來對 Iris 數據集進行分類。
首先導入需要的庫:
fromsklearn.neighborsimportKNeighborsClassifier
fromsklearn.naive_bayesimportGaussianNB
fromsklearn.linear_modelimportLogisticRegression
fromsklearn.svmimportSVC
fromsklearn.treeimportDecisionTreeClassifier
fromsklearn.ensembleimportRandomForestClassifier
fromsklearn.neural_networkimportMLPClassifier
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromsklearn.datasetsimportload_iris
importargparse
# 設置參數
ap = argparse.ArgumentParser()
ap.add_argument("-m","--model", type=str,default="knn", help="type of python machine learning model to use")
args = vars(ap.parse_args())
# 定義一個保存模型的字典,根據 key 來選擇載入哪個模型
models = {
"knn": KNeighborsClassifier(n_neighbors=1),
"naive_bayes": GaussianNB(),
"logit": LogisticRegression(solver="lbfgs", multi_class="auto"),
"svm": SVC(kernel="rbf", gamma="auto"),
"decision_tree": DecisionTreeClassifier(),
"random_forest": RandomForestClassifier(n_estimators=100),
"mlp": MLPClassifier()
}
可以看到在 sklearn 庫中就集成了我們將要實現的幾種機器學習演算法的代碼,包括:
KNN
樸素貝葉斯
邏輯回歸
SVM
決策樹
隨機森林
感知機
我們直接調用 sklearn 中相應的函數來實現對應的演算法即可,比如對於 knn演算法,直接調用 sklearn.neighbors 中的 KNeighborsClassifier() 即可,只需要設置參數 n_neighbors ,即最近鄰的個數。
這裡直接用一個 models 的字典來保存不同模型的初始化,然後根據參數 --model 來調用對應的模型,比如命令輸入 python classify_irs.py --model knn 就是調用 knn 演算法模型。
接著就是載入數據部分:
print("[INFO] loading data...")
dataset = load_iris()
(trainX, testX, trainY, testY) = train_test_split(dataset.data,
dataset.target, random_state=3, test_size=0.25)
這裡直接調用 sklearn.datasets 中的 load_iris() 載入數據,然後採用 train_test_split 來劃分訓練集和數據集,這裡是 75% 數據作為訓練集,25% 作為測試集。
最後就是訓練模型和預測部分:
# 訓練模型
print("[INFO] using "{}" model".format(args["model"]))
model = models[args["model"]]
model.fit(trainX, trainY)
# 預測並輸出一份分類結果報告
print("[INFO] evaluating")
predictions = model.predict(testX)
print(classification_report(testY, predictions, target_names=dataset.target_names))
完整版代碼代碼如下:
fromsklearn.neighborsimportKNeighborsClassifier
fromsklearn.naive_bayesimportGaussianNB
fromsklearn.linear_modelimportLogisticRegression
fromsklearn.svmimportSVC
fromsklearn.treeimportDecisionTreeClassifier
fromsklearn.ensembleimportRandomForestClassifier
fromsklearn.neural_networkimportMLPClassifier
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromsklearn.datasetsimportload_iris
importargparse
# 設置參數
ap = argparse.ArgumentParser()
ap.add_argument("-m","--model", type=str,default="knn", help="type of python machine learning model to use")
args = vars(ap.parse_args())
# 定義一個保存模型的字典,根據 key 來選擇載入哪個模型
models = {
"knn": KNeighborsClassifier(n_neighbors=1),
"naive_bayes": GaussianNB(),
"logit": LogisticRegression(solver="lbfgs", multi_class="auto"),
"svm": SVC(kernel="rbf", gamma="auto"),
"decision_tree": DecisionTreeClassifier(),
"random_forest": RandomForestClassifier(n_estimators=100),
"mlp": MLPClassifier()
}
# 載入 Iris 數據集,然後進行訓練集和測試集的劃分,75%數據作為訓練集,其餘25%作為測試集
print("[INFO] loading data...")
dataset = load_iris()
(trainX, testX, trainY, testY) = train_test_split(dataset.data, dataset.target, random_state=3, test_size=0.25)
# 訓練模型
print("[INFO] using "{}" model".format(args["model"]))
model = models[args["model"]]
model.fit(trainX, trainY)
# 預測並輸出一份分類結果報告
print("[INFO] evaluating")
predictions = model.predict(testX)
print(classification_report(testY, predictions, target_names=dataset.target_names))
接著就是採用三場景圖像數據集的分類預測代碼 classify_images.py ,跟 classify_iris.py 的代碼其實是比較相似的,首先導入庫部分,增加以下幾行代碼:
fromsklearn.preprocessingimportLabelEncoder
fromPILimportImage
fromimutilsimportpaths
importnumpyasnp
importos
其中 LabelEncoder 是為了將標籤從字元串編碼為整型,然後其餘幾項都是處理圖像相關。
對於圖像數據,如果直接採用原始像素信息輸入模型中,大部分的機器學習演算法效果都很不理想,所以這裡採用特徵提取方法,主要是統計圖像顏色通道的均值和標準差信息,總共是 RGB 3個通道,每個通道各計算均值和標準差,然後結合在一起,得到一個六維的特徵,函數如下所示:
defextract_color_stats(image):
"""
將圖片分成 RGB 三通道,然後分別計算每個通道的均值和標準差,然後返回
:param image:
:return:
"""
(R, G, B) = image.split()
features = [np.mean(R), np.mean(G), np.mean(B), np.std(R), np.std(G), np.std(B)]
returnfeatures
然後同樣會定義一個 models 字典,代碼一樣,這裡就不貼出來了,然後圖像載入部分的代碼如下:
# 載入數據並提取特徵
print("[INFO] extracting image features...")
imagePaths = paths.list_images(args["dataset"])
data = []
labels = []
# 循環遍歷所有的圖片數據
for imagePath in imagePaths:
# 載入圖片,然後計算圖片的顏色通道統計信息
image = Image.open(imagePath)
features = extract_color_stats(image)
data.append(features)
# 保存圖片的標籤信息
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
# 對標籤進行編碼,從字元串變為整數類型
le = LabelEncoder()
labels = le.fit_transform(labels)
# 進行訓練集和測試集的劃分,75%數據作為訓練集,其餘25%作為測試集
(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.25)
上述代碼就完成從硬碟中載入圖片的路徑信息,然後依次遍歷,讀取圖片,提取特徵,提取標籤信息,保存特徵和標籤信息,接著編碼標籤,然後就是劃分訓練集和測試集。
接著是相同的訓練模型和預測的代碼,同樣沒有任何改變,這裡就不列舉出來了。
完整版如下:
fromsklearn.neighborsimportKNeighborsClassifier
fromsklearn.naive_bayesimportGaussianNB
fromsklearn.linear_modelimportLogisticRegression
fromsklearn.svmimportSVC
fromsklearn.treeimportDecisionTreeClassifier
fromsklearn.ensembleimportRandomForestClassifier
fromsklearn.neural_networkimportMLPClassifier
fromsklearn.preprocessingimportLabelEncoder
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromPILimportImage
fromimutilsimportpaths
importnumpyasnp
importargparse
importos
defextract_color_stats(image):
"""
將圖片分成 RGB 三通道,然後分別計算每個通道的均值和標準差,然後返回
:param image:
:return:
"""
(R, G, B) = image.split()
features = [np.mean(R), np.mean(G), np.mean(B), np.std(R), np.std(G), np.std(B)]
returnfeatures
# 設置參數
ap = argparse.ArgumentParser()
ap.add_argument("-d","--dataset", type=str, default="3scenes",
help="path to directory containing the "3scenes" dataset")
ap.add_argument("-m","--model", type=str, default="knn",
help="type of python machine learning model to use")
args = vars(ap.parse_args())
# 定義一個保存模型的字典,根據 key 來選擇載入哪個模型
models = {
"knn": KNeighborsClassifier(n_neighbors=1),
"naive_bayes": GaussianNB(),
"logit": LogisticRegression(solver="lbfgs", multi_class="auto"),
"svm": SVC(kernel="rbf", gamma="auto"),
"decision_tree": DecisionTreeClassifier(),
"random_forest": RandomForestClassifier(n_estimators=100),
"mlp": MLPClassifier()
}
# 載入數據並提取特徵
print("[INFO] extracting image features...")
imagePaths = paths.list_images(args["dataset"])
data = []
labels = []
# 循環遍歷所有的圖片數據
forimagePathinimagePaths:
# 載入圖片,然後計算圖片的顏色通道統計信息
image = Image.open(imagePath)
features = extract_color_stats(image)
data.append(features)
# 保存圖片的標籤信息
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
# 對標籤進行編碼,從字元串變為整數類型
le = LabelEncoder()
labels = le.fit_transform(labels)
# 進行訓練集和測試集的劃分,75%數據作為訓練集,其餘25%作為測試集
(trainX, testX, trainY, testY) = train_test_split(data, labels, random_state=3, test_size=0.25)
# print("trainX numbers={}, testX numbers={}".format(len(trainX), len(testX)))
# 訓練模型
print("[INFO] using "{}" model".format(args["model"]))
model = models[args["model"]]
model.fit(trainX, trainY)
# 預測並輸出分類結果報告
print("[INFO] evaluating...")
predictions = model.predict(testX)
print(classification_report(testY, predictions, target_names=le.classes_))
完成這兩份代碼後,我們就可以開始運行下代碼,對比不同演算法在兩個數據集上的性能。
因為篇幅的原因,這裡我會省略原文對每個演算法的介紹,具體的可以查看之前我寫的對機器學習演算法的介紹:
KNN
這裡我們先運行下 classify_irs.py,調用默認的模型 knn ,看下 KNN 在 Iris 數據集上的實驗結果,如下所示:
其中主要是給出了對每個類別的精確率、召回率、F1 以及該類別測試集數量,即分別對應 precision, recall, f1-score, support 。根據最後一行第一列,可以看到 KNN 取得 95% 的準確率。
接著是在三場景圖片數據集上的實驗結果:
這裡 KNN 取得 72% 的準確率。
(ps:實際上,運行這個演算法,不同次數會有不同的結果,原文作者給出的是 75%,其主要原因是因為在劃分訓練集和測試集的時候,代碼沒有設置參數 random_state,這導致每次運行劃分的訓練集和測試集的圖片都是不同的,所以運行結果也會不相同!)
樸素貝葉斯
接著是樸素貝葉斯演算法,分別測試兩個數據集,結果如下:
同樣,樸素貝葉斯在 Iris 上有 98% 的準確率,但是在圖像數據集上僅有 63% 的準確率。
那麼,我們是否可以說明 KNN 演算法比樸素貝葉斯好呢?
當然是不可以的,上述結果只能說明在三場景圖像數據集上,KNN 演算法優於樸素貝葉斯演算法。
實際上,每種演算法都有各自的優缺點和適用場景,不能一概而論地說某種演算法任何時候都優於另一種演算法,這需要具體問題具體分析。
邏輯回歸
接著是邏輯回歸演算法,分別測試兩個數據集,結果如下:
同樣,邏輯回歸在 Iris 上有 98% 的準確率,但是在圖像數據集上僅有 77%的準確率(對比原文作者的邏輯回歸準確率是 69%)
支持向量機 SVM
接著是 SVM 演算法,分別測試兩個數據集,結果如下:
同樣,SVM 在 Iris 上有 98% 的準確率,但是在圖像數據集上僅有 76% 的準確率(對比原文作者的準確率是 83%,主要是發現類別 coast 差別有些大)
決策樹
接著是決策樹演算法,分別測試兩個數據集,結果如下:
同樣,決策樹在 Iris 上有 98% 的準確率,但是在圖像數據集上僅有 71% 的準確率(對比原文作者的決策樹準確率是 74%)
隨機森林
接著是隨機森林演算法,分別測試兩個數據集,結果如下:
同樣,隨機森林在 Iris 上有 96% 的準確率,但是在圖像數據集上僅有 77%的準確率(對比原文作者的決策樹準確率是 84%)
注意了,一般如果決策樹演算法的效果還不錯的話,隨機森林演算法應該也會取得不錯甚至更好的結果,這是因為隨機森林實際上就是多棵決策樹通過集成學習方法組合在一起進行分類預測。
多層感知機
最後是多層感知機演算法,分別測試兩個數據集,結果如下:
同樣,多層感知機在 Iris 上有 98% 的準確率,但是在圖像數據集上僅有 79% 的準確率(對比原文作者的決策樹準確率是 81%).
深度學習以及深度神經網路
神經網路
最後是實現深度學習的演算法,也就是 nn_iris.py 和 basic_cnn.py 這兩份代碼。
(這裡需要注意 TensorFlow 和 Keras 的版本問題,我採用的是 TF=1.2 和 Keras=2.1.5)
首先是 nn_iris.py 的實現,同樣首先是導入庫和數據的處理:
fromkeras.modelsimportSequential
fromkeras.layers.coreimportDense
fromkeras.optimizersimportSGD
fromsklearn.preprocessingimportLabelBinarizer
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromsklearn.datasetsimportload_iris
# 載入 Iris 數據集,然後進行訓練集和測試集的劃分,75%數據作為訓練集,其餘25%作為測試集
print("[INFO] loading data...")
dataset = load_iris()
(trainX, testX, trainY, testY) = train_test_split(dataset.data,
dataset.target, test_size=0.25)
# 將標籤進行 one-hot 編碼
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
這裡我們將採用 Keras 來實現神經網路,然後這裡需要將標籤進行 one-hot編碼,即獨熱編碼。
接著就是搭建網路模型的結構和訓練、預測代碼:
# 利用 Keras 定義網路模型
model = Sequential()
model.add(Dense(3, input_shape=(4,), activation="sigmoid"))
model.add(Dense(3, activation="sigmoid"))
model.add(Dense(3, activation="softmax"))
# 採用梯度下降訓練模型
print("[INFO] training network...")
opt = SGD(lr=0.1, momentum=0.9, decay=0.1 / 250)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
H = model.fit(trainX, trainY, validation_data=(testX, testY), epochs=250, batch_size=16)
# 預測
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=16)
print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1), target_names=dataset.target_names))
這裡是定義了 3 層全連接層的神經網路,前兩層採用 Sigmoid 激活函數,然後最後一層是輸出層,所以採用 softmax 將輸出變成概率值。接著就是定義了使用 SGD 的優化演算法,損失函數是 categorical_crossentropy,迭代次數是 250 次,batch_size 是 16。
完整版如下:
fromkeras.modelsimportSequential
fromkeras.layers.coreimportDense
fromkeras.optimizersimportSGD
fromsklearn.preprocessingimportLabelBinarizer
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromsklearn.datasetsimportload_iris
# 載入 Iris 數據集,然後進行訓練集和測試集的劃分,75%數據作為訓練集,其餘25%作為測試集
print("[INFO] loading data...")
dataset = load_iris()
(trainX, testX, trainY, testY) = train_test_split(dataset.data,
dataset.target, test_size=0.25)
# 將標籤進行 one-hot 編碼
lb = LabelBinarizer()
trainY = lb.fit_transform(trainY)
testY = lb.transform(testY)
# 利用 Keras 定義網路模型
model = Sequential()
model.add(Dense(3, input_shape=(4,), activation="sigmoid"))
model.add(Dense(3, activation="sigmoid"))
model.add(Dense(3, activation="softmax"))
# 採用梯度下降訓練模型
print("[INFO] training network...")
opt = SGD(lr=0.1, momentum=0.9, decay=0.1/250)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
H = model.fit(trainX, trainY, validation_data=(testX, testY), epochs=250, batch_size=16)
# 預測
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=16)
print(classification_report(testY.argmax(axis=1),
predictions.argmax(axis=1), target_names=dataset.target_names))
直接運行命令 python nn_iris.py, 輸出的結果如下:
這裡得到的是 100% 的準確率,和原文的一樣。當然實際上原文給出的結果如下圖所示,可以看到其實類別數量上是不相同的。
CNN
最後就是實現 basic_cnn.py 這份代碼了。
同樣首先是導入必須的庫函數:
fromkeras.modelsimportSequential
fromkeras.layers.convolutionalimportConv2D
fromkeras.layers.convolutionalimportMaxPooling2D
fromkeras.layers.coreimportActivation
fromkeras.layers.coreimportFlatten
fromkeras.layers.coreimportDense
fromkeras.optimizersimportAdam
fromsklearn.preprocessingimportLabelBinarizer
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromPILimportImage
fromimutilsimportpaths
importnumpyasnp
importargparse
importos
# 配置參數
ap = argparse.ArgumentParser()
ap.add_argument("-d","--dataset", type=str,default="3scenes",
help="path to directory containing the "3scenes" dataset")
args = vars(ap.parse_args())
同樣是要導入 Keras 來建立 CNN 的網路模型,另外因為是處理圖像數據,所以 PIL、imutils 也是要導入的。
然後是載入數據和劃分訓練集和測試集,對於載入數據,這裡直接採用原始圖像像素數據,只需要對圖像數據做統一尺寸的調整,這裡是統一調整為 32×32,並做歸一化到 [0,1] 的範圍。
# 載入數據並提取特徵
print("[INFO] extracting image features...")
imagePaths = paths.list_images(args["dataset"])
data = []
labels = []
# 循環遍歷所有的圖片數據
for imagePath in imagePaths:
# 載入圖片,然後調整成 32×32 大小,並做歸一化到 [0,1]
image = Image.open(imagePath)
image = np.array(image.resize((32, 32))) / 255.0
data.append(image)
# 保存圖片的標籤信息
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
# 對標籤編碼,從字元串變為整型
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
# 劃分訓練集和測試集
(trainX, testX, trainY, testY) = train_test_split(np.array(data), np.array(labels), test_size=0.25)
接著定義了一個 4 層的 CNN 網路結構,包含 3 層卷積層和最後一層輸出層,優化演算法採用的是 Adam 而不是 SGD 。代碼如下所示:
# 定義 CNN 網路模型結構
model = Sequential()
model.add(Conv2D(8, (3,3), padding="same", input_shape=(32,32,3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(16, (3,3), padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(32, (3,3), padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Flatten())
model.add(Dense(3))
model.add(Activation("softmax"))
# 訓練模型
print("[INFO] training network...")
opt = Adam(lr=1e-3, decay=1e-3/50)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
H = model.fit(trainX, trainY, validation_data=(testX, testY),
epochs=50, batch_size=32)
# 預測
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
predictions.argmax(axis=1), target_names=lb.classes_))
完整版如下:
fromkeras.modelsimportSequential
fromkeras.layers.convolutionalimportConv2D
fromkeras.layers.convolutionalimportMaxPooling2D
fromkeras.layers.coreimportActivation
fromkeras.layers.coreimportFlatten
fromkeras.layers.coreimportDense
fromkeras.optimizersimportAdam
fromsklearn.preprocessingimportLabelBinarizer
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.metricsimportclassification_report
fromPILimportImage
fromimutilsimportpaths
importnumpyasnp
importargparse
importos
# 配置參數
ap = argparse.ArgumentParser()
ap.add_argument("-d","--dataset", type=str,default="3scenes",
help="path to directory containing the "3scenes" dataset")
args = vars(ap.parse_args())
# 載入數據並提取特徵
print("[INFO] extracting image features...")
imagePaths = paths.list_images(args["dataset"])
data = []
labels = []
# 循環遍歷所有的圖片數據
forimagePathinimagePaths:
# 載入圖片,然後調整成 32×32 大小,並做歸一化到 [0,1]
image = Image.open(imagePath)
image = np.array(image.resize((32,32))) /255.0
data.append(image)
# 保存圖片的標籤信息
label = imagePath.split(os.path.sep)[-2]
labels.append(label)
# 對標籤編碼,從字元串變為整型
lb = LabelBinarizer()
labels = lb.fit_transform(labels)
# 劃分訓練集和測試集
(trainX, testX, trainY, testY) = train_test_split(np.array(data), np.array(labels), test_size=0.25)
# 定義 CNN 網路模型結構
model = Sequential()
model.add(Conv2D(8, (3,3), padding="same", input_shape=(32,32,3)))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(16, (3,3), padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Conv2D(32, (3,3), padding="same"))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Flatten())
model.add(Dense(3))
model.add(Activation("softmax"))
# 訓練模型
print("[INFO] training network...")
opt = Adam(lr=1e-3, decay=1e-3/50)
model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])
H = model.fit(trainX, trainY, validation_data=(testX, testY),
epochs=50, batch_size=32)
# 預測
print("[INFO] evaluating network...")
predictions = model.predict(testX, batch_size=32)
print(classification_report(testY.argmax(axis=1),
predictions.argmax(axis=1), target_names=lb.classes_))
運行命令 python basic_cnn.py, 輸出結果如下:
CNN 的準確率是達到 90%,它是優於之前的幾種機器學習演算法的結果。
小結
最後,這僅僅是一份對機器學習完全是初學者的教程,其實就是簡單調用現有的庫來實現對應的機器學習演算法,讓初學者簡單感受下如何使用機器學習演算法,正如同在學習編程語言的時候,對著書本的代碼例子敲起來,然後運行代碼,看看自己寫出來的程序的運行結果。
通過這份簡單的入門教程,你應該明白的是:
沒有任何一種演算法是完美的,可以完全適用所有的場景,即便是目前很熱門的深度學習方法,也存在它的局限性,所以應該具體問題具體分析!
記住開頭推薦的 5 步機器學習操作流程,這裡再次複習一遍:
評估你的問題
準備數據(原始數據、特徵提取、特徵工程等等)
檢查各種機器學習演算法
檢驗實驗結果
深入了解性能最好的演算法
最後一點,是我運行演算法結果,和原文作者的結果會不相同,這實際上就是每次採樣數據,劃分訓練集和測試集不相同的原因!這其實也說明了數據非常重要,對於機器學習來說,好的數據很重要!
接著,根據這份教程,你可以繼續進一步了解每種機器學習演算法,了解每種演算法的基本原理和實現,嘗試自己手動實現,而不是簡單調用現有的庫,這樣更加能加深印象,這裡推薦《機器學習實戰》,經典的機器學習演算法都有介紹,並且都會帶你一步步實現演算法!
最後,極力推薦大家去閱讀下原文作者的博客,原文作者也是一個大神,他的博客地址如下:https://www.pyimagesearch.com/
他的博客包含了 Opencv、Python、機器學習和深度學習方面的教程和文章,而且作者喜歡通過實戰學習,所以很多文章都是通過一些實戰練習來學習某個知識點或者某個演算法,正如同本文通過實現這幾種常見的機器學習演算法在兩個不同類型數據集上的實戰來帶領初學者入門機器學習。
原文地址:
https://www.pyimagesearch.com/2019/01/14/machine-learning-in-python/
(*本文僅代表作者觀點,轉載請聯繫原作者)
※Pig變飛機?AI為什麼這麼蠢
※扎心!「我學了半年Python,還是找不到工作」
TAG:AI科技大本營 |