十.Tensorflow+Opencv實現CNN自定義圖像分類案例及與KNN對比
前一篇文章詳細講解了卷積神經網絡CNN原理,并通過TensorFlow編寫CNN實現了MNIST分類學習案例。本篇文章將通過Tensorflow和Opencv實現CNN自定義圖像分類案例,它能解決我們現實論文或實踐中的圖像分類問題,并與機器學習的圖像分類算法進行對比實驗。
本專欄主要結合作者之前的博客、AI經驗和相關文章及論文介紹,后面隨著深入會講解更多的Python人工智能案例及應用。基礎性文章,希望對您有所幫助,如果文章中存在錯誤或不足之處,還請海涵。作者作為人工智能的菜鳥,希望大家能與我在這一筆一劃的博客中成長起來。寫了這么多年博客,嘗試第一個付費專欄,但更多博客尤其基礎性文章,還是會繼續免費分享,但該專欄也會用心撰寫,望對得起讀者,共勉!
文章目錄:
- 一.圖像分類
- 二.基于KNN算法的圖像分類
- 1.KNN算法
- 2.數據集
- 3.KNN圖像分類
- 三.Tensorflow+Opencv實現CNN圖像分類
- 1.OpenCV庫安裝
- 2.讀取文件夾圖像
- 3.搭建CNN
- 4.定義損失函數和優化器
- 5.模型訓練和預測
- 6.完整代碼及實驗結果
- 四.總結
代碼下載地址(歡迎大家關注點贊):
- https://github.com/eastmountyxz/
- AI-for-TensorFlow
- https://github.com/eastmountyxz/
- AI-for-Keras
學Python近八年,認識了很多大佬和朋友,感恩。作者的本意是幫助更多初學者入門,因此在github開源了所有代碼,也在公眾號同步更新。深知自己很菜,得拼命努力前行,編程也沒有什么捷徑,干就對了。希望未來能更透徹學習和撰寫文章,也能在讀博幾年里學會真正的獨立科研。同時非常感謝參考文獻中的大佬們的文章和分享。
- https://blog.csdn.net/eastmount
一.圖像分類
圖像分類(Image Classification)是對圖像內容進行分類的問題,它利用計算機對圖像進行定量分析,把圖像或圖像中的區域劃分為若干個類別,以代替人的視覺判斷。圖像分類的傳統方法是特征描述及檢測,這類傳統方法可能對于一些簡單的圖像分類是有效的,但由于實際情況非常復雜,傳統的分類方法不堪重負。現在,廣泛使用機器學習和深度學習的方法來處理圖像分類問題,其主要任務是給定一堆輸入圖片,將其指派到一個已知的混合類別中的某個標簽。
在下圖中,圖像分類模型將獲取單個圖像,并將為4個標簽{cat,dog,hat,mug},分別對應概率{0.6, 0.3, 0.05, 0.05},其中0.6表示圖像標簽為貓的概率,其余類比。該圖像被表示為一個三維數組。在這個例子中,貓的圖像寬度為248像素,高度為400像素,并具有紅綠藍三個顏色通道(通常稱為RGB)。因此,圖像由248×400×3個數字組成或總共297600個數字,每個數字是一個從0(黑色)到255(白色)的整數。圖像分類的任務是將這接近30萬個數字變成一個單一的標簽,如“貓(cat)”。

那么,如何編寫一個圖像分類的算法呢?
又怎么從眾多圖像中識別出貓呢?這里所采取的方法和教育小孩看圖識物類似,給出很多圖像數據,讓模型不斷去學習每個類的特征。在訓練之前,首先需要對訓練集的圖像進行分類標注,如圖所示,包括cat、dog、mug和hat四類。在實際工程中,可能有成千上萬類別的物體,每個類別都會有上百萬張圖像。

圖像分類是輸入一堆圖像的像素值數組,然后給它分配一個分類標簽,通過訓練學習來建立算法模型,接著使用該模型進行圖像分類預測,具體流程如下:
- 輸入: 輸入包含N個圖像的集合,每個圖像的標簽是K種分類標簽中的一種,這個集合稱為訓練集。
- 學習: 第二步任務是使用訓練集來學習每個類的特征,構建訓練分類器或者分類模型。
- 評價: 通過分類器來預測新輸入圖像的分類標簽,并以此來評價分類器的質量。通過分類器預測的標簽和圖像真正的分類標簽對比,從而評價分類算法的好壞。如果分類器預測的分類標簽和圖像真正的分類標簽一致,表示預測正確,否則預測錯誤。
常見的分類算法包括樸素貝葉斯分類器、決策樹、K最近鄰分類算法、支持向量機、神經網絡和基于規則的分類算法等,同時還有用于組合單一類方法的集成學習算法,如Bagging和Boosting等。
二.基于KNN算法的圖像分類
1.KNN算法
K最近鄰分類(K-Nearest Neighbor Classifier)算法是一種基于實例的分類方法,是數據挖掘分類技術中最簡單常用的方法之一。該算法的核心思想是從訓練樣本中尋找所有訓練樣本X中與測試樣本距離(歐氏距離)最近的前K個樣本(作為相似度),再選擇與待分類樣本距離最小的K個樣本作為X的K個最鄰近,并檢測這K個樣本大部分屬于哪一類樣本,則認為這個測試樣本類別屬于這一類樣本。
假設現在需要判斷下圖中的圓形圖案屬于三角形還是正方形類別,采用KNN算法分析如下:

- 當K=3時,圖中第一個圈包含了三個圖形,其中三角形2個,正方形一個,該圓的則分類結果為三角形。
- 當K=5時,第二個圈中包含了5個圖形,三角形2個,正方形3個,則以3:2的投票結果預測圓為正方形類標。設置不同的K值,可能預測得到不同的結果。
簡而言之,一個樣本與數據集中的k個最相鄰樣本中的大多數的類別相同。由其思想可以看出,KNN是通過測量不同特征值之間的距離進行分類,而且在決策樣本類別時,只參考樣本周圍k個“鄰居”樣本的所屬類別。因此比較適合處理樣本集存在較多重疊的場景,主要用于預測分析、文本分類、降維等處理。
KNN在Sklearn機器學習包中,實現的類如下,簡稱KNN算法。構造方法為:
- neighbors.KNeighborsClassifier
KNeighborsClassifier(algorithm='ball_tree',
leaf_size=30,
metric='minkowski',
metric_params=None,
n_jobs=1,
n_neighbors=3,
p=2,
weights='uniform')
KNeighborsClassifier可以設置3種算法:brute、kd_tree、ball_tree,設置K值參數為n_neighbors=3。調用方法如下:
- from sklearn.neighbors import KNeighborsClassifier
- knn = KNeighborsClassifier(n_neighbors=3, algorithm=“ball_tree”)
它包括兩個步驟:
- 訓練:nbrs.fit(data, target)
- 預測:pre = clf.predict(data)
2.數據集
該部分主要使用Scikit-Learn包進行Python圖像分類處理。Scikit-Learn擴展包是用于Python數據挖掘和數據分析的經典、實用擴展包,通常縮寫為Sklearn。Scikit-Learn中的機器學習模型是非常豐富的,包括線性回歸、決策樹、SVM、KMeans、KNN、PCA等等,用戶可以根據具體分析問題的類型選擇該擴展包的合適模型,從而進行數據分析,其安裝過程主要通過“pip install scikit-learn”實現。
實驗所采用的數據集為Sort_1000pics數據集,該數據集包含了1000張圖片,總共分為10大類,分別是人(第0類)、沙灘(第1類)、建筑(第2類)、大卡車(第3類)、恐龍(第4類)、大象(第5類)、花朵(第6類)、馬(第7類)、山峰(第8類)和食品(第9類),每類100張。如圖所示。

接著將所有各類圖像按照對應的類標劃分至“0”至“9”命名的文件夾中,如圖所示,每個文件夾中均包含了100張圖像,對應同一類別。

比如,文件夾名稱為“6”中包含了100張花的圖像,如下圖所示。

3.KNN圖像分類
下面是調用KNN算法進行圖像分類的完整代碼,它將1000張圖像按照訓練集為70%,測試集為30%的比例隨機劃分,再獲取每張圖像的像素直方圖,根據像素的特征分布情況進行圖像分類分析。
KNeighborsClassifier()核心代碼如下:
- from sklearn.neighbors import KNeighborsClassifier
- clf = KNeighborsClassifier(n_neighbors=11).fit(XX_train, y_train)
- predictions_labels = clf.predict(XX_test)
完整代碼及注釋如下:
# -*- coding: utf-8 -*-
import os
import cv2
import numpy as np
from sklearn.cross_validation import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
#----------------------------------------------------------------------------------
# 第一步 切分訓練集和測試集
#----------------------------------------------------------------------------------
X = [] #定義圖像名稱
Y = [] #定義圖像分類類標
Z = [] #定義圖像像素
for i in range(0, 10):
#遍歷文件夾,讀取圖片
for f in os.listdir("photo/%s" % i):
#獲取圖像名稱
X.append("photo//" +str(i) + "http://" + str(f))
#獲取圖像類標即為文件夾名稱
Y.append(i)
X = np.array(X)
Y = np.array(Y)
#隨機率為100% 選取其中的30%作為測試集
X_train, X_test, y_train, y_test = train_test_split(X, Y,
test_size=0.3, random_state=1)
print len(X_train), len(X_test), len(y_train), len(y_test)
#----------------------------------------------------------------------------------
# 第二步 圖像讀取及轉換為像素直方圖
#----------------------------------------------------------------------------------
#訓練集
XX_train = []
for i in X_train:
#讀取圖像
#print i
image = cv2.imread(i)
#圖像像素大小一致
img = cv2.resize(image, (256,256),
interpolation=cv2.INTER_CUBIC)
#計算圖像直方圖并存儲至X數組
hist = cv2.calcHist([img], [0,1], None,
[256,256], [0.0,255.0,0.0,255.0])
XX_train.append(((hist/255).flatten()))
#測試集
XX_test = []
for i in X_test:
#讀取圖像
#print i
image = cv2.imread(i)
#圖像像素大小一致
img = cv2.resize(image, (256,256),
interpolation=cv2.INTER_CUBIC)
#計算圖像直方圖并存儲至X數組
hist = cv2.calcHist([img], [0,1], None,
[256,256], [0.0,255.0,0.0,255.0])
XX_test.append(((hist/255).flatten()))
#----------------------------------------------------------------------------------
# 第三步 基于KNN的圖像分類處理
#----------------------------------------------------------------------------------
from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(n_neighbors=11).fit(XX_train, y_train)
predictions_labels = clf.predict(XX_test)
print u'預測結果:'
print predictions_labels
print u'算法評價:'
print (classification_report(y_test, predictions_labels))
#輸出前10張圖片及預測結果
k = 0
while k<10:
#讀取圖像
print X_test[k]
image = cv2.imread(X_test[k])
print predictions_labels[k]
#顯示圖像
cv2.imshow("img", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
k = k + 1
代碼中對預測集的前十張圖像進行了顯示,其中“818.jpg”圖像如圖所示,其分類預測的類標結果為“8”,表示第8類山峰,預測結果正確。

下圖展示了“452.jpg”圖像,其分類預測的類標結果為“4”,表示第4類恐龍,預測結果正確。

下圖展示了“507.jpg”圖像,其分類預測的類標結果為“7”,錯誤地預測為第7類恐龍,其真實結果應該是第5類大象。

使用KNN算法進行圖像分類實驗,最后算法評價的準確率(Precision)、召回率(Recall)和F值(F1-score)如圖所示,其中平均準確率為0.64,平均召回率為0.55,平均F值為0.50,其結果不是非常理想。
那么,如果采用CNN卷積神經網絡進行分類,通過不斷學習細節是否能提高準確度呢?

三.Tensorflow實現CNN圖像分類
首先,我們需要在TensorFlow環境下安裝OpenCV擴展包;其次需要通過TensorFlow環境搭建CNN神經網絡;最后通過不斷學實現圖像分類實驗。
1.OpenCV庫安裝
第一步,打開Anaconda程序,并選擇已經安裝好的“TensorFlow”環境,運行Spyder。

第二步,我們需要在TensorFlow環境中安裝opencv-python擴展包,否則會提示錯誤“ModuleNotFoundError: No module named ‘cv2’”。調用Anaconda Prompt安裝即可,如下圖所示:
activate tensorflow pip install opencv-python

安裝成功如下圖所示。

但是,由于anaconda的.org服務器在國外,下載速度很慢,提示錯誤“Anaconda An HTTP error occurred when trying to retrieve this URL.HTTP errors are often intermittent”。
- 解決方法一:從國內清華的鏡像下載
- 解決方法二:從PYPI網站下載對應版本的opencv-python,在再安裝本地下載的.whl文件。下載地址:
- https://www.lfd.uci.edu/~gohlke/pythonlibs/#OpenCV
由于第一種方法一直失敗,這里推薦讀者嘗試第二種方法,同時作者會將“opencv_python-4.1.2-cp36-cp36m-win_amd64.whl”文件上傳供大家直接使用。(4.1.2代表opencv的版本,cp36代表用的python3.6,并且是64位)。
第三步,調用PIP安裝本地opencv擴展包。
activate tensorflow pip install C:\Users\xiuzhang\Desktop\TensorFlow\opencv_python-4.1.2-cp36-cp36m-win_amd64.whl

這種方法非常迅速,推薦大家使用。安裝成功之后,開始編寫我們的代碼吧!
2.讀取文件夾圖像
該部分具體步驟如下:
- 定義函數read_img(),讀取文件夾“photo”中“0”到“9”的圖像
- 調用cv2.imread()函數循環獲取每張圖片的所有像素值,并通過
- cv2.resize()統一修改為32*32大小
- 依次獲取圖像像素、圖像類標和圖像路徑名稱:fpaths, data, label = read_img(path)
- 將圖像的順序隨機調整,并按照2-8比例劃分數據集,其中80%的數據用于訓練,20%的數據用于測試

#---------------------------------第一步 讀取圖像-----------------------------------
def read_img(path):
cate = [path + x for x in os.listdir(path) if os.path.isdir(path + x)]
imgs = []
labels = []
fpath = []
for idx, folder in enumerate(cate):
# 遍歷整個目錄判斷每個文件是不是符合
for im in glob.glob(folder + '/*.jpg'):
#print('reading the images:%s' % (im))
img = cv2.imread(im) #調用opencv庫讀取像素點
img = cv2.resize(img, (32, 32)) #圖像像素大小一致
imgs.append(img) #圖像數據
labels.append(idx) #圖像類標
fpath.append(path+im) #圖像路徑名
#print(path+im, idx)
return np.asarray(fpath, np.string_), np.asarray(imgs, np.float32), np.asarray(labels, np.int32)
# 讀取圖像
fpaths, data, label = read_img(path)
print(data.shape) # (1000, 256, 256, 3)
# 計算有多少類圖片
num_classes = len(set(label))
print(num_classes)
# 生成等差數列隨機調整圖像順序
num_example = data.shape[0]
arr = np.arange(num_example)
np.random.shuffle(arr)
data = data[arr]
label = label[arr]
fpaths = fpaths[arr]
# 拆分訓練集和測試集 80%訓練集 20%測試集
ratio = 0.8
s = np.int(num_example * ratio)
x_train = data[:s]
y_train = label[:s]
fpaths_train = fpaths[:s]
x_val = data[s:]
y_val = label[s:]
fpaths_test = fpaths[s:]
print(len(x_train),len(y_train),len(x_val),len(y_val)) #800 800 200 200
print(y_val)
3.搭建CNN
該部分具體步驟如下:
- 首先定義Placeholder,用于傳入輸入值,xs表示圖片32*32像素點,并且包含RGB三個圖層,故大小設置為32 * 32 * 3;ys表示每張圖片最終預測的類標值。
- 調用tf.layers.conv2d()函數定義卷積層,包括20個卷積核,卷積核大小為5,激勵函數為Relu;調用tf.layers.max_pooling2d()函數定義池化處理,步長為2,縮小一倍。
- 接著定義第二個卷積層和池化層,現共有conv0, pool0和conv1, pool1。
- 通過tf.layers.dense()函數定義全連接層,轉換為長度為400的特征向量,加上DropOut防止過擬合。
- 輸出層為logits,包括10個數字,最終預測結果為predicted_labels,即為tf.arg_max(logits, 1)。
#---------------------------------第二步 建立神經網絡-----------------------------------
# 定義Placeholder
xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) #每張圖片32*32*3個點
ys = tf.placeholder(tf.int32, [None]) #每個樣本有1個輸出
# 存放DropOut參數的容器
drop = tf.placeholder(tf.float32) #訓練時為0.25 測試時為0
# 定義卷積層 conv0
conv0 = tf.layers.conv2d(xs, 20, 5, activation=tf.nn.relu) #20個卷積核 卷積核大小為5 Relu激活
# 定義max-pooling層 pool0
pool0 = tf.layers.max_pooling2d(conv0, [2, 2], [2, 2]) #pooling窗口為2x2 步長為2x2
print("Layer0:", conv0, pool0)
# 定義卷積層 conv1
conv1 = tf.layers.conv2d(pool0, 40, 4, activation=tf.nn.relu) #40個卷積核 卷積核大小為4 Relu激活
# 定義max-pooling層 pool1
pool1 = tf.layers.max_pooling2d(conv1, [2, 2], [2, 2]) #pooling窗口為2x2 步長為2x2
print("Layer1:", conv1, pool1)
# 將3維特征轉換為1維向量
flatten = tf.layers.flatten(pool1)
# 全連接層 轉換為長度為400的特征向量
fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu)
print("Layer2:", fc)
# 加上DropOut防止過擬合
dropout_fc = tf.layers.dropout(fc, drop)
# 未激活的輸出層
logits = tf.layers.dense(dropout_fc, num_classes)
print("Output:", logits)
# 定義輸出結果
predicted_labels = tf.arg_max(logits, 1)
4.定義損失函數和優化器
利用交叉熵定義損失,同時用AdamOptimizer優化器進行深度學習,核心代碼如下。
one-hot類型數據又稱為一位有效編碼,主要是采用N位狀態寄存器來對N個狀態進行編碼,每個狀態都由他獨立的寄存器位,并且在任意時候只有一位有效。例如[0 0 0 1 0 0 0 0 0 0…] 表示為“動物”。
# 利用交叉熵定義損失
losses = tf.nn.softmax_cross_entropy_with_logits(
labels = tf.one_hot(ys, num_classes), #將input轉化為one-hot類型數據輸出
logits = logits)
# 平均損失
mean_loss = tf.reduce_mean(losses)
# 定義優化器 學習效率設置為0.0001
optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(losses)
5.模型訓練和預測
定義標記變量train,當它為True時進行訓練操作并保存訓練模型;當其為False時進行預測,20%預測集進行圖像分類預測實驗。
#------------------------------------第四步 模型訓練和預測-----------------------------------
# 用于保存和載入模型
saver = tf.train.Saver()
# 訓練或預測
train = False
# 模型文件路徑
model_path = "model/image_model"
with tf.Session() as sess:
if train:
print("訓練模式")
# 訓練初始化參數
sess.run(tf.global_variables_initializer())
# 定義輸入和Label以填充容器 訓練時dropout為0.25
train_feed_dict = {
xs: x_train,
ys: y_train,
drop: 0.25
}
# 訓練學習1000次
for step in range(1000):
_, mean_loss_val = sess.run([optimizer, mean_loss], feed_dict=train_feed_dict)
if step % 50 == 0: #每隔50次輸出一次結果
print("step = {}\t mean loss = {}".format(step, mean_loss_val))
# 保存模型
saver.save(sess, model_path)
print("訓練結束,保存模型到{}".format(model_path))
else:
print("測試模式")
# 測試載入參數
saver.restore(sess, model_path)
print("從{}載入模型".format(model_path))
# label和名稱的對照關系
label_name_dict = {
0: "人類",
1: "沙灘",
2: "建筑",
3: "公交",
4: "恐龍",
5: "大象",
6: "花朵",
7: "野馬",
8: "雪山",
9: "美食"
}
# 定義輸入和Label以填充容器 測試時dropout為0
test_feed_dict = {
xs: x_val,
ys: y_val,
drop: 0
}
# 真實label與模型預測label
predicted_labels_val = sess.run(predicted_labels, feed_dict=test_feed_dict)
for fpath, real_label, predicted_label in zip(fpaths_test, y_val, predicted_labels_val):
# 將label id轉換為label名
real_label_name = label_name_dict[real_label]
predicted_label_name = label_name_dict[predicted_label]
print("{}\t{} => {}".format(fpath, real_label_name, predicted_label_name))
# 評價結果
print("正確預測個數:", sum(y_val==predicted_labels_val))
print("準確度為:", 1.0*sum(y_val==predicted_labels_val) / len(y_val))
6.完整代碼及實驗結果
完整代碼如下所示,這里參考了王詩爺老師的部分代碼,強烈推薦大家學習他的博客。地址:https://blog.csdn.net/wills798
"""
Created on Sun Dec 29 19:21:08 2019
@author: xiuzhang Eastmount CSDN
"""
import os
import glob
import cv2
import numpy as np
import tensorflow as tf
# 定義圖片路徑
path = 'photo/'
#---------------------------------第一步 讀取圖像-----------------------------------
def read_img(path):
cate = [path + x for x in os.listdir(path) if os.path.isdir(path + x)]
imgs = []
labels = []
fpath = []
for idx, folder in enumerate(cate):
# 遍歷整個目錄判斷每個文件是不是符合
for im in glob.glob(folder + '/*.jpg'):
#print('reading the images:%s' % (im))
img = cv2.imread(im) #調用opencv庫讀取像素點
img = cv2.resize(img, (32, 32)) #圖像像素大小一致
imgs.append(img) #圖像數據
labels.append(idx) #圖像類標
fpath.append(path+im) #圖像路徑名
#print(path+im, idx)
return np.asarray(fpath, np.string_), np.asarray(imgs, np.float32), np.asarray(labels, np.int32)
# 讀取圖像
fpaths, data, label = read_img(path)
print(data.shape) # (1000, 256, 256, 3)
# 計算有多少類圖片
num_classes = len(set(label))
print(num_classes)
# 生成等差數列隨機調整圖像順序
num_example = data.shape[0]
arr = np.arange(num_example)
np.random.shuffle(arr)
data = data[arr]
label = label[arr]
fpaths = fpaths[arr]
# 拆分訓練集和測試集 80%訓練集 20%測試集
ratio = 0.8
s = np.int(num_example * ratio)
x_train = data[:s]
y_train = label[:s]
fpaths_train = fpaths[:s]
x_val = data[s:]
y_val = label[s:]
fpaths_test = fpaths[s:]
print(len(x_train),len(y_train),len(x_val),len(y_val)) #800 800 200 200
print(y_val)
#---------------------------------第二步 建立神經網絡-----------------------------------
# 定義Placeholder
xs = tf.placeholder(tf.float32, [None, 32, 32, 3]) #每張圖片32*32*3個點
ys = tf.placeholder(tf.int32, [None]) #每個樣本有1個輸出
# 存放DropOut參數的容器
drop = tf.placeholder(tf.float32) #訓練時為0.25 測試時為0
# 定義卷積層 conv0
conv0 = tf.layers.conv2d(xs, 20, 5, activation=tf.nn.relu) #20個卷積核 卷積核大小為5 Relu激活
# 定義max-pooling層 pool0
pool0 = tf.layers.max_pooling2d(conv0, [2, 2], [2, 2]) #pooling窗口為2x2 步長為2x2
print("Layer0:", conv0, pool0)
# 定義卷積層 conv1
conv1 = tf.layers.conv2d(pool0, 40, 4, activation=tf.nn.relu) #40個卷積核 卷積核大小為4 Relu激活
# 定義max-pooling層 pool1
pool1 = tf.layers.max_pooling2d(conv1, [2, 2], [2, 2]) #pooling窗口為2x2 步長為2x2
print("Layer1:", conv1, pool1)
# 將3維特征轉換為1維向量
flatten = tf.layers.flatten(pool1)
# 全連接層 轉換為長度為400的特征向量
fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu)
print("Layer2:", fc)
# 加上DropOut防止過擬合
dropout_fc = tf.layers.dropout(fc, drop)
# 未激活的輸出層
logits = tf.layers.dense(dropout_fc, num_classes)
print("Output:", logits)
# 定義輸出結果
predicted_labels = tf.arg_max(logits, 1)
#---------------------------------第三步 定義損失函數和優化器---------------------------------
# 利用交叉熵定義損失
losses = tf.nn.softmax_cross_entropy_with_logits(
labels = tf.one_hot(ys, num_classes), #將input轉化為one-hot類型數據輸出
logits = logits)
# 平均損失
mean_loss = tf.reduce_mean(losses)
# 定義優化器 學習效率設置為0.0001
optimizer = tf.train.AdamOptimizer(learning_rate=1e-4).minimize(losses)
#------------------------------------第四步 模型訓練和預測-----------------------------------
# 用于保存和載入模型
saver = tf.train.Saver()
# 訓練或預測
train = False
# 模型文件路徑
model_path = "model/image_model"
with tf.Session() as sess:
if train:
print("訓練模式")
# 訓練初始化參數
sess.run(tf.global_variables_initializer())
# 定義輸入和Label以填充容器 訓練時dropout為0.25
train_feed_dict = {
xs: x_train,
ys: y_train,
drop: 0.25
}
# 訓練學習1000次
for step in range(1000):
_, mean_loss_val = sess.run([optimizer, mean_loss], feed_dict=train_feed_dict)
if step % 50 == 0: #每隔50次輸出一次結果
print("step = {}\t mean loss = {}".format(step, mean_loss_val))
# 保存模型
saver.save(sess, model_path)
print("訓練結束,保存模型到{}".format(model_path))
else:
print("測試模式")
# 測試載入參數
saver.restore(sess, model_path)
print("從{}載入模型".format(model_path))
# label和名稱的對照關系
label_name_dict = {
0: "人類",
1: "沙灘",
2: "建筑",
3: "公交",
4: "恐龍",
5: "大象",
6: "花朵",
7: "野馬",
8: "雪山",
9: "美食"
}
# 定義輸入和Label以填充容器 測試時dropout為0
test_feed_dict = {
xs: x_val,
ys: y_val,
drop: 0
}
# 真實label與模型預測label
predicted_labels_val = sess.run(predicted_labels, feed_dict=test_feed_dict)
for fpath, real_label, predicted_label in zip(fpaths_test, y_val, predicted_labels_val):
# 將label id轉換為label名
real_label_name = label_name_dict[real_label]
predicted_label_name = label_name_dict[predicted_label]
print("{}\t{} => {}".format(fpath, real_label_name, predicted_label_name))
# 評價結果
print("正確預測個數:", sum(y_val==predicted_labels_val))
print("準確度為:", 1.0*sum(y_val==predicted_labels_val) / len(y_val))
訓練輸出結果如下所示:
(1000, 32, 32, 3)
10
800 800 200 200
[2 8 6 9 9 5 2 2 9 3 7 0 6 0 0 1 3 2 7 3 4 6 9 5 8 6 4 1 1 4 4 8 6 2 6 1 2
5 0 7 9 5 2 4 6 8 7 5 8 1 6 5 1 4 8 1 9 1 8 8 6 1 0 5 3 3 1 2 9 1 8 7 6 0
8 1 8 0 2 1 3 5 3 6 9 8 7 5 2 5 2 8 8 8 4 2 2 4 3 5 3 3 9 1 1 5 2 6 7 6 7
0 7 4 1 7 2 9 4 0 3 8 7 5 3 8 1 9 3 6 8 0 0 1 7 7 9 5 4 0 3 0 4 5 7 2 2 3
0 8 2 0 2 3 5 1 7 2 1 6 5 8 1 4 6 6 8 6 5 5 1 7 2 8 7 1 3 9 7 1 3 6 0 8 7
5 8 0 1 2 7 9 6 2 4 7 7 2 8 0]
Layer0:
Tensor("conv2d_1/Relu:0", shape=(?, 28, 28, 20), dtype=float32)
Tensor("max_pooling2d_1/MaxPool:0", shape=(?, 14, 14, 20), dtype=float32)
Layer1:
Tensor("conv2d_2/Relu:0", shape=(?, 11, 11, 40), dtype=float32)
Tensor("max_pooling2d_2/MaxPool:0", shape=(?, 5, 5, 40), dtype=float32)
Layer2:
Tensor("dense_1/Relu:0", shape=(?, 400), dtype=float32)
Output:
Tensor("dense_2/BiasAdd:0", shape=(?, 10), dtype=float32)
訓練模式
step = 0 mean loss = 66.93688201904297
step = 50 mean loss = 3.376957654953003
step = 100 mean loss = 0.5910811424255371
step = 150 mean loss = 0.061084795743227005
step = 200 mean loss = 0.013018212281167507
step = 250 mean loss = 0.006795921362936497
step = 300 mean loss = 0.004505819175392389
step = 350 mean loss = 0.0032660639844834805
step = 400 mean loss = 0.0024683878291398287
step = 450 mean loss = 0.0019308131886646152
step = 500 mean loss = 0.001541870180517435
step = 550 mean loss = 0.0012695763725787401
step = 600 mean loss = 0.0010685999877750874
step = 650 mean loss = 0.0009132082923315465
step = 700 mean loss = 0.0007910516578704119
step = 750 mean loss = 0.0006900889566168189
step = 800 mean loss = 0.0006068988586775959
step = 850 mean loss = 0.0005381597438827157
step = 900 mean loss = 0.0004809059901162982
step = 950 mean loss = 0.0004320790758356452
訓練結束,保存模型到model/image_model
預測輸出結果如下圖所示,最終預測正確181張圖片,準確度為0.905。相比之前機器學習KNN的0.500有非常高的提升。
測試模式 INFO:tensorflow:Restoring parameters from model/image_model 從model/image_model載入模型 b'photo/photo/3\\335.jpg' 公交 => 公交 b'photo/photo/1\\129.jpg' 沙灘 => 沙灘 b'photo/photo/7\\740.jpg' 野馬 => 野馬 b'photo/photo/5\\564.jpg' 大象 => 大象 ... b'photo/photo/9\\974.jpg' 美食 => 美食 b'photo/photo/2\\220.jpg' 建筑 => 公交 b'photo/photo/9\\912.jpg' 美食 => 美食 b'photo/photo/4\\459.jpg' 恐龍 => 恐龍 b'photo/photo/5\\525.jpg' 大象 => 大象 b'photo/photo/0\\44.jpg' 人類 => 人類 正確預測個數: 181 準確度為: 0.905
四.總結
寫到這里,這篇文章就講解完畢,更多TensorFlow深度學習文章會繼續分享,同時實驗評價、RNN、LSTM、各專業的案例都會進行深入講解。
最后,希望這篇基礎性文章對您有所幫助,如果文章中存在錯誤或不足之處,還請海涵~作為人工智能的菜鳥,我希望自己能不斷進步并深入,后續將它應用于圖像識別、網絡安全、對抗樣本等領域,指導大家撰寫簡單的學術論文,一起加油!
感恩有你,一路同行。