引言
本篇文章希望帶大家完整走一遍機器學習應用流程,我們會講解到基于Python的機器學習算法,應用在結構化數據和非結構化數據(圖像)上,希望通過文章內容幫助大家在案例中重溫機器學習基礎知識,并學習應用機器學習解決問題的基本流程。
文章中會用到下述兩個庫來實現機器學習算法:
- Scikit-Learn:最常用的python機器學習算法工具庫之一。
- Keras:便捷的深度學習神經網絡搭建應用工具庫。
對于上述兩個工具庫的用法,大家也可以通過ShowMeAI的文章 AI建模工具速查 | Scikit-Learn使用指南 和 AI建模工具速查 | Keras使用指南 來快速查詢和使用。
在本篇文章中,我們將講解到以下內容:
- 問題抽象與理解
- 數據準備與處理(預處理、特征提取、特征工程等)
- 各種機器學習算法
- 實驗結果分析與對比
- 模型選擇與調優
我們會覆蓋到的機器學習算法包括:KNN、樸素貝葉斯、邏輯回歸、SVM、決策樹、隨機森林、感知機、前饋神經網絡、卷積神經網絡。
1.環境準備
工欲善其事必先利其器,我們先安裝一下必需的Python庫(當然我們也推薦大家用集成環境anaconda,具體的安裝與設置可以參考ShowMeAI文章 圖解Python | 安裝與環境設置 完成):
- Numpy:用于Python的科學計算。
- 相關重點知識請查看 數據科學工具速查 | Numpy使用指南 或者 圖解數據分析:從入門到精通系列教程 中的Numpy詳解教程。
- PIL:一個簡單的圖像處理庫。
- Scikit-Learn:包含多種機器學習算法。
- 相關重點知識請查看 AI建模工具速查 | Scikit-Learn使用指南
- Kears和TensorFlow:用于深度學習。本教程可以僅采用CPU版本的TensorFlow。
- OpenCV:本教程并不直接使用OpenCV,但imutils庫依賴它。
- 相關重點知識請查看 AI建模工具速查 | OpenCV使用指南
- imutils:圖像處理/計算機視覺庫。
可以采用pip安裝,命令如下:
$ pip install numpy
$ pip install pillow
$ pip install --upgrade scikit-learn
$ pip install tensorflow # or tensorflow-gpu
$ pip install keras
$ pip install opencv-contrib-python
$ pip install --upgrade imutils
2.數據集
因為本篇文章我們介紹結構化數據和非結構化數據的不同建模,我們這里用到兩個數據集。
2.1 iris(鳶尾花)數據集
第一個數據集是iris(鳶尾花)數據集,它是一個入門級數據集。整個數據集都是數值型的數據,是一個結構化的表格數據,每一行代表一個樣本,然后每一列就是不同的屬性。
這個數據集主要是收集了三種不同的鳶尾花的數據,分別為:
- Iris Setosa
- Iris Versicolor
- Iris Virginica
對應圖中最后一列Class label
,然后還有四種屬性,分別是:
- Sepal length:萼片長度
- Sepal width:萼片寬度
- Petal length:花瓣長度
- Petal width:花瓣寬度
對于該數據集,我們的目標就是根據給定的四個屬性,訓練一個機器學習模型來正確分類每個樣本的類別,這是一個典型的分類任務。
2.2 圖像數據集
第二個數據集是一個圖像數據集。它包括海岸線(Coast)、森林(Forest)和高速公路(Highway)三種場景,總共是 948 張圖片,我們需要構建模型完成類別的分類,每個類別的具體圖片數量如下:
- 海岸線(Coast):360
- 森林(Forest):328
- 高速公路(Highway):260
3.機器學習應用步驟
我們在不同場景下應用機器學習算法,都有大致的步驟,比如下面是一個典型的機器學習應用流程:
當然,并不是其中的每一步都是必須的,我們也可能會調整其中某些步驟中的細節。
3.1 問題抽象與理解
針對我們的問題,問一下自己:
- 數據集是哪種類型?數值型,類別型還是圖像?
- 模型的最終目標是什么?
- 如何定義和衡量“準確率”呢?
- 以目前自身的機器學習知識來看,哪些算法在處理這類問題上效果很好?
前序問題比較簡單,最后的問題,隨著大家應用機器學習解決問題的經驗積累,可以更準確快速地回答。
3.2 數據準備與處理
數據準備與處理,包括數據預處理以及特征工程了。一般這一步,包括了加載數據、檢查數據、探索性數據分析(EDA)、數據預處理,進而決定需要做的特征提取或者特征工程。
特征提取是應用某種算法通過某種方式來量化數據的過程。比如,對于圖像數據,我們可以采用計算直方圖的方法來統計圖像中像素強度的分布,通過這種方式,我們就得到描述圖像顏色的特征。
特征工程是將原始輸入數據轉換成一個更好描述潛在問題的特征表示的過程。大家可以查看ShowMeAI的 機器學習專題文章 系統了解特征工程的常見方法。
3.3 多模型應用
下一步可以選擇各種候選機器學習算法,并應用在數據集上。我們安裝的工具包內,包含很多機器學習算法,比如下述模型都可以用作分類:
- 線性模型(邏輯回歸、線性SVM)
- 非線性模型(RBF、SVM、梯度下降分類器)
- 樹和基于集成的模型(決策樹、隨機森林)
- 神經網絡(多層感知機、卷積神經網絡)
對于模型選擇,當然很多需要依據實驗效果來定,但我們也有一些先序的經驗,比如:
- 對于稠密型多特征的數據集,隨機森林算法的效果很不錯;
- 邏輯回歸算法可以很好處理高維度的稀疏數據;
- 對于圖像數據,CNNs的效果非常好。
下圖為 scikit-learn工具庫 官方給的一個模型選擇思路參考:
4.構建機器學習流程并實驗分析
我們構建如下的代碼文件目錄,包含四個代碼文件和一個3scenes
圖像文件夾(內含三場景數據集),iris數據集無需另外存儲,直接采用scikit-learn
庫載入即可。
├── 3scenes
│ ├── coast [360 entries]
│ ├── forest [328 entries]
│ └── highway [260 entries]
├── iris_classifier.py
├── image_classifier.py
├── nn_iris.py
└── basic_cnn.py
4.1 結構化數據建模
首先實現iris_classifier
,我們這里直接使用sklearn的機器學習算法來對iris
數據集進行分類。
# 導入需要的庫
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.datasets import load_iris
import argparse
# 設置參數
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()
}
其中,models從前往后依次包括這些算法:KNN、樸素貝葉斯、邏輯回歸、SVM、決策樹、隨機森林、感知機等。
我們直接調用sklearn
中相應的函數來實現對應的算法即可,這里直接用一個models
的字典來保存不同模型的初始化,然后根據參數--model
來調用對應的模型,比如命令輸入python iris_classifier.py --model knn
就是調用knn
算法模型。
接著就是載入數據部分:
print("加載數據中...")
dataset = load_iris()
trainX, testX, trainY, testY = train_test_split(dataset.data, dataset.target, random_state=3, test_size=0.2)
這里直接調用sklearn.datasets
中的load_iris()
載入數據,然后采用train_test_split
來劃分訓練集和數據集,這里是80%數據作為訓練集,20%作為測試集。
最后就是訓練模型和預測部分:
# 訓練模型
print("應用 '{}' 模型建模...".format(args["model"]))
model = models[args["model"]]
model.fit(trainX, trainY)
# 預測并輸出一份分類結果報告
print("評估模型效果...")
predictions = model.predict(testX)
print(classification_report(testY, predictions, target_names=dataset.target_names))
4.2 圖像數據建模
類似的過程對三場景圖像數據集構建代碼image_classifier.py
:
# 導入工具庫
from sklearn.preprocessing import LabelEncoder
from PIL import Image
from imutils import paths
import numpy as np
import os
其中LabelEncoder
是為了將標簽從字符串編碼為整型,然后其余幾項都是處理圖像相關。
對于圖像數據,如果直接采用原始像素信息輸入模型中,大部分的機器學習算法效果都很不理想,所以這里采用特征提取方法,主要是統計圖像顏色通道的均值和標準差信息,總共是RGB
3個通道,每個通道各計算均值和標準差,然后結合在一起,得到一個六維的特征,函數如下所示:
def extract_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)]
return features
然后同樣會定義一個models
字典,代碼一樣,這里就不貼出來了,然后圖像載入部分的代碼如下:
# 加載數據并提取特征
print("抽取圖像特征中...")
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)
# 進行訓練集和測試集的劃分,80%數據作為訓練集,其余20%作為測試集
trainX, testX, trainY, testY = train_test_split(data, labels, test_size=0.2)
上述代碼就完成加載圖片的路徑信息,然后依次遍歷,讀取圖片,提取特征,提取標簽信息,保存特征和標簽信息,接著編碼標簽,然后就是劃分訓練集和測試集。
接著是相同的訓練模型和預測的代碼,和前面的分類器一樣。完整版代碼如下:
# 導入工具庫
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from PIL import Image
from imutils import paths
import numpy as np
import argparse
import os
# 抽取圖像特征
def extract_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)]
return features
# 設置參數
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("抽取圖像特征中...")
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)
# 進行訓練集和測試集的劃分,80%數據作為訓練集,其余20%作為測試集
trainX, testX, trainY, testY = train_test_split(data, labels, random_state=3, test_size=0.2)
# print('trainX numbers={}, testX numbers={}'.format(len(trainX), len(testX)))
# 訓練模型
print("[應用 '{}' 模型建模".format(args["model"]))
model = models[args["model"]]
model.fit(trainX, trainY)
# 預測并輸出分類結果報告
print("模型評估")
predictions = model.predict(testX)
print(classification_report(testY, predictions, target_names=le.classes_))
完成這兩份代碼后,我們就可以開始運行下代碼,對比不同算法在兩個數據集上的性能。
4.3 不同模型建模對比
(1) KNN
K-Nearest Neighbors分類器最簡單的分類算法之一。該算法依賴于特征向量之間的距離。簡單地說,KNN算法通過在k個最接近的樣本中最多的類別來對未知數據點進行分類。關于KNN的詳細講解可以閱讀ShowMeAI的文章 圖解機器學習 | KNN算法及其應用。
這里我們先運行下image_classifier.py
,調用默認的模型knn
,看下KNN
在iris
數據集上的實驗結果,如下所示:
$ !python iris_classifier.py --model knn
加載數據中...
應用 'knn' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 10
versicolor 0.90 0.90 0.90 10
virginica 0.90 0.90 0.90 10
accuracy 0.93 30
macro avg 0.93 0.93 0.93 30
weighted avg 0.93 0.93 0.93 30
其中主要是給出了對每個類別的精確率、召回率、F1以及該類別測試集數量,即分別對應precision、recall、f1-score、support。根據最后一行第一列,可以看到KNN取得93%的準確率。
接著是在三場景圖片數據集上的實驗結果:
$ !python image_classifier.py --model knn
抽取圖像特征中...
應用 'knn' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.84 0.68 0.75 105
forest 0.78 0.77 0.77 78
highway 0.56 0.78 0.65 54
micro avg 0.73 0.73 0.73 237
macro avg 0.72 0.74 0.72 237
weighted avg 0.75 0.73 0.73 237
這里KNN取得75%的準確率。
ps:實際上,運行這個算法,不同次數會有不同的結果,其主要原因是因為在劃分訓練集和測試集的時候,代碼沒有設置參數random_state
,這導致每次運行劃分的訓練集和測試集的圖片都是不同的,所以運行結果也會不相同!
(2) 樸素貝葉斯
接著是樸素貝葉斯算法,關于樸素貝葉斯算法的詳細講解可以閱讀ShowMeAI的文章 圖解機器學習 | 樸素貝葉斯算法詳解。
分別測試兩個數據集,結果如下:
$ !python iris_classifier.py --model naive_bayes
加載數據中...
應用 'naive_bayes' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 1.00 0.92 0.96 12
virginica 0.92 1.00 0.96 11
micro avg 0.97 0.97 0.97 38
macro avg 0.97 0.97 0.97 38
weighted avg 0.98 0.97 0.97 38
$ !python image_classifier.py --model naive_bayes
抽取圖像特征中...
應用 'naive_bayes' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.69 0.40 0.50 88
forest 0.68 0.82 0.74 84
highway 0.61 0.78 0.68 65
micro avg 0.65 0.65 0.65 237
macro avg 0.66 0.67 0.64 237
weighted avg 0.66 0.65 0.64 237
同樣,樸素貝葉斯在iris上有98%的準確率,但是在圖像數據集上僅有66%的準確率。
那么,我們是否可以說明KNN算法比樸素貝葉斯好呢?當然是不可以的,上述結果只能說明在三場景圖像數據集上,KNN算法優于樸素貝葉斯算法。
實際上,每種算法都有各自的優缺點和適用場景,不能一概而論地說某種算法任何時候都優于另一種算法,這需要具體問題具體分析。
(3) 邏輯回歸
接著是邏輯回歸算法,關于邏輯回歸算法的詳細講解可以閱讀ShowMeAI的文章 圖解機器學習 | 邏輯回歸算法詳解。
分別測試兩個數據集,結果如下:
$ !python iris_classifier.py --model logit
加載數據中...
應用 'logit' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 1.00 0.92 0.96 12
virginica 0.92 1.00 0.96 11
micro avg 0.97 0.97 0.97 38
macro avg 0.97 0.97 0.97 38
weighted avg 0.98 0.97 0.97 38
$ !python image_classifier.py --model logit
抽取圖像特征中...
應用 'logit' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.67 0.67 0.67 92
forest 0.79 0.82 0.80 82
highway 0.61 0.57 0.59 63
micro avg 0.70 0.70 0.70 237
macro avg 0.69 0.69 0.69 237
weighted avg 0.69 0.70 0.69 237
同樣,邏輯回歸在 iris
上有 98% 的準確率,但是在圖像數據集上僅有 69% 的準確率
(4) 支持向量機 SVM
接著是SVM算法,關于SVM算法的詳細講解可以閱讀ShowMeAI的文章 圖解機器學習 | 支持向量機模型詳解。
分別測試兩個數據集,結果如下:
$ !python iris_classifier.py --model svm
加載數據中...
應用 'svm' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 1.00 0.92 0.96 12
virginica 0.92 1.00 0.96 11
micro avg 0.97 0.97 0.97 38
macro avg 0.97 0.97 0.97 38
weighted avg 0.98 0.97 0.97 38
$ !python image_classifier.py --model svm
抽取圖像特征中...
應用 'svm' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.84 0.76 0.80 92
forest 0.86 0.93 0.89 84
highway 0.78 0.80 0.79 61
micro avg 0.83 0.83 0.83 237
macro avg 0.83 0.83 0.83 237
同樣,SVM在iris
上有98%的準確率,但是在圖像數據集上僅有83%的準確率。
(5) 決策樹
接著是決策樹算法,關于決策樹算法的詳細講解可以閱讀ShowMeAI的文章 圖解機器學習 | 決策樹模型詳解。
分別測試兩個數據集,結果如下:
$ !python iris_classifier.py --model decision_tree
加載數據中...
應用 'decision_tree' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 0.92 0.92 0.92 12
virginica 0.91 0.91 0.91 11
micro avg 0.95 0.95 0.95 38
macro avg 0.94 0.94 0.94 38
weighted avg 0.95 0.95 0.95 38
$ !python image_classifier.py --model decision_tree
抽取圖像特征中...
應用 'decision_tree' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.71 0.74 0.72 85
forest 0.76 0.80 0.78 83
highway 0.77 0.68 0.72 69
micro avg 0.74 0.74 0.74 237
macro avg 0.75 0.74 0.74 237
weighted avg 0.74 0.74 0.74 237
同樣,決策樹在iris
上有98%的準確率,但是在圖像數據集上僅有74%的準確率。
(6) 隨機森林
接著是隨機森林算法,關于隨機森林算法的詳細講解可以閱讀ShowMeAI的文章 圖解機器學習 | 隨機森林分類模型詳解。
分別測試兩個數據集,結果如下:
$ !python iris_classifier.py --model random_forest
加載數據中...
應用 'random_forest' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 1.00 0.83 0.91 12
virginica 0.85 1.00 0.92 11
micro avg 0.95 0.95 0.95 38
macro avg 0.95 0.94 0.94 38
weighted avg 0.96 0.95 0.95 38
$ !python image_classifier.py --model random_forest
加載數據中...
應用 'random_forest' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.80 0.83 0.81 84
forest 0.92 0.84 0.88 90
highway 0.77 0.81 0.79 63
micro avg 0.83 0.83 0.83 237
macro avg 0.83 0.83 0.83 237
weighted avg 0.84 0.83 0.83 237
同樣,隨機森林在iris
上有96%的準確率,但是在圖像數據集上僅有84%的準確率。
注意了,一般如果決策樹算法的效果還不錯的話,隨機森林算法應該也會取得不錯甚至更好的結果,這是因為隨機森林實際上就是多棵決策樹通過集成學習方法組合在一起進行分類預測。
(7) 多層感知機
最后是多層感知機算法,分別測試兩個數據集,結果如下:
$ !python iris_classifier.py --model mlp
加載數據中...
應用 'mlp' 模型建模...
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 15
versicolor 1.00 0.92 0.96 12
virginica 0.92 1.00 0.96 11
micro avg 0.97 0.97 0.97 38
macro avg 0.97 0.97 0.97 38
weighted avg 0.98 0.97 0.97 38
$ !python image_classifier.py --model mlp
抽取圖像特征中...
應用 'mlp' 模型建模...
評估模型效果...
precision recall f1-score support
coast 0.72 0.91 0.80 86
forest 0.92 0.89 0.90 79
highway 0.79 0.58 0.67 72
micro avg 0.80 0.80 0.80 237
macro avg 0.81 0.79 0.79 237
weighted avg 0.81 0.80 0.80 237
同樣,多層感知機在 iris
上有 98% 的準確率,但是在圖像數據集上僅有 81% 的準確率.
(8) 神經網絡
最后是實現深度學習的算法,也就是nn_iris.py
和basic_cnn.py
這兩份代碼。
首先是nn_iris.py
的實現,同樣首先是導入庫和數據的處理:
# 導入工具庫
from keras.models import Sequential
from keras.layers.core import Dense
from keras.optimizers import SGD
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.datasets import load_iris
# 載入 Iris 數據集,然后進行訓練集和測試集的劃分,80%數據作為訓練集,其余20%作為測試集
print("加載數據中...")
dataset = load_iris()
(trainX, testX, trainY, testY) = train_test_split(dataset.data,
dataset.target, test_size=0.2)
# 將標簽進行獨熱向量編碼
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('訓練網絡中...')
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('評估模型效果')
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。
完整版代碼如下:
# 加載工具庫
from keras.models import Sequential
from keras.layers.core import Dense
from keras.optimizers import SGD
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from sklearn.datasets import load_iris
# 載入 Iris 數據集,然后進行訓練集和測試集的劃分,80%數據作為訓練集,其余20%作為測試集
print("加載數據中...")
dataset = load_iris()
(trainX, testX, trainY, testY) = train_test_split(dataset.data,
dataset.target, test_size=0.2)
# 將標簽進行獨熱向量編碼
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('訓練網絡中...')
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('評估模型效果...')
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
,輸出的結果如下:
$ python nn_iris.py
Using TensorFlow backend.
加載數據中...
訓練網絡中...
Train on 112 samples, validate on 38 samples
Epoch 1/250
2022-02-08 10:28:19.104933: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 AVX512F FMA
112/112 [==============================] - 0s 2ms/step - loss: 1.1454 - acc: 0.3214 - val_loss: 1.1867 - val_acc: 0.2368
Epoch 2/250
112/112 [==============================] - 0s 48us/step - loss: 1.0828 - acc: 0.3929 - val_loss: 1.2132 - val_acc: 0.5000
Epoch 3/250
112/112 [==============================] - 0s 47us/step - loss: 1.0491 - acc: 0.5268 - val_loss: 1.0593 - val_acc: 0.4737
...
Epoch 248/250
112/112 [==============================] - 0s 46us/step - loss: 0.1319 - acc: 0.9554 - val_loss: 0.0407 - val_acc: 1.0000
Epoch 249/250
112/112 [==============================] - 0s 46us/step - loss: 0.1024 - acc: 0.9643 - val_loss: 0.1595 - val_acc: 0.8947
Epoch 250/250
112/112 [==============================] - 0s 47us/step - loss: 0.0795 - acc: 0.9821 - val_loss: 0.0335 - val_acc: 1.0000
評估模型效果...
precision recall f1-score support
setosa 1.00 1.00 1.00 9
versicolor 1.00 1.00 1.00 10
virginica 1.00 1.00 1.00 19
avg / total 1.00 1.00 1.00 38
這里得到的是100%的準確率。
(9) CNN
最后我們要應用卷積神經網絡,我們實現一下basic_cnn.py
代碼。
同樣首先是導入必須的庫函數:
# 導入工具庫
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dense
from keras.optimizers import Adam
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from PIL import Image
from imutils import paths
import numpy as np
import argparse
import os
# 配置參數
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("抽取圖像特征中...")
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("訓練網絡中...")
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("評估模型效果...")
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
,輸出結果如下:
$ python basic_cnn.py
Using TensorFlow backend.
加載圖像數據...
訓練網絡中...
Train on 711 samples, validate on 237 samples
Epoch 1/50
711/711 [==============================] - 0s 629us/step - loss: 1.0647 - acc: 0.4726 - val_loss: 0.9920 - val_acc: 0.5359
Epoch 2/50
711/711 [==============================] - 0s 313us/step - loss: 0.9200 - acc: 0.6188 - val_loss: 0.7778 - val_acc: 0.6624
Epoch 3/50
711/711 [==============================] - 0s 308us/step - loss: 0.6775 - acc: 0.7229 - val_loss: 0.5310 - val_acc: 0.7553
...
Epoch 48/50
711/711 [==============================] - 0s 307us/step - loss: 0.0627 - acc: 0.9887 - val_loss: 0.2426 - val_acc: 0.9283
Epoch 49/50
711/711 [==============================] - 0s 310us/step - loss: 0.0608 - acc: 0.9873 - val_loss: 0.2236 - val_acc: 0.9325
Epoch 50/50
711/711 [==============================] - 0s 307us/step - loss: 0.0587 - acc: 0.9887 - val_loss: 0.2525 - val_acc: 0.9114
評估模型效果...
precision recall f1-score support
coast 0.85 0.96 0.90 85
forest 0.99 0.94 0.97 88
highway 0.91 0.80 0.85 64
avg / total 0.92 0.91 0.91 237
CNN
的準確率是達到92%,它是優于之前的幾種機器學習算法的結果。
5.小結
這篇簡單的機器學習教程文章中,我們調用現有的庫來應用對應的機器學習算法,解決了2個簡單的場景問題。通過這份簡單的入門教程,希望大家了解到:
(1) 沒有任何一種算法是完美的,可以完全適用所有的場景,即便是目前很熱門的深度學習方法,也存在它的局限性,所以應該具體問題具體分析!
(2) 經典的5步機器學習操作流程:
- 問題抽象與理解
- 數據準備與處理(預處理、特征提取、特征工程等)
- 各種機器學習算法
- 實驗結果分析與對比
- 模型選擇與調優
參考資料
作者:韓信子@ShowMeAI
教程地址:http://www.showmeai.tech/tutorials/41
本文地址:http://www.showmeai.tech/article-detail/201
聲明:版權所有,轉載請聯系平臺與作者并注明出處
收藏ShowMeAI查看更多精彩內容