基於Tensorflow + Opencv 實現CNN自定義圖像分類

摘要:本篇文章主要通過Tensorflow+Opencv實現CNN自定義圖像分類案例,它能解決我們現實論文或實踐中的圖像分類問題,並與機器學習的圖像分類算法進行對比實驗。

本文分享自華爲雲社區《Tensorflow+Opencv實現CNN自定義圖像分類及與KNN圖像分類對比》,作者: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機器學習包中,實現的類是neighbors.KNeighborsClassifier,簡稱KNN算法。構造方法爲:

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) + "//" + 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+Opencv實現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”。

由於第一種方法一直失敗,這裏推薦讀者嘗試第二種方法,同時作者會將“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:\n", 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:\n", conv1, pool1)

# 將3維特徵轉換爲1維向量
flatten = tf.layers.flatten(pool1)

# 全連接層 轉換爲長度爲400的特徵向量
fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu)
print("Layer2:\n", fc)

# 加上DropOut防止過擬合
dropout_fc = tf.layers.dropout(fc, drop)

# 未激活的輸出層
logits = tf.layers.dense(dropout_fc, num_classes)
print("Output:\n", 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.完整代碼及實驗結果

完整代碼如下所示,這裏參考了王詩爺老師的部分代碼,強烈推薦大家學習他的博客。地址:

"""
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:\n", 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:\n", conv1, pool1)

# 將3維特徵轉換爲1維向量
flatten = tf.layers.flatten(pool1)

# 全連接層 轉換爲長度爲400的特徵向量
fc = tf.layers.dense(flatten, 400, activation=tf.nn.relu)
print("Layer2:\n", fc)

# 加上DropOut防止過擬合
dropout_fc = tf.layers.dropout(fc, drop)

# 未激活的輸出層
logits = tf.layers.dense(dropout_fc, num_classes)
print("Output:\n", 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、各專業的案例都會進行深入講解。最後,希望這篇基礎性文章對您有所幫助,如果文章中存在錯誤或不足之處,還請海涵~作爲人工智能的菜鳥,我希望自己能不斷進步並深入,後續將它應用於圖像識別、網絡安全、對抗樣本等領域,指導大家撰寫簡單的學術論文,一起加油!

參考文獻:

[1] 岡薩雷斯著. 數字圖像處理(第3版)[M]. 北京:電子工業出版社,2013.
[2] 楊秀璋, 顏娜. Python網絡數據爬取及分析從入門到精通(分析篇)[M]. 北京:北京航天航空大學出版社, 2018.
[3] 羅子江等. Python中的圖像處理[M]. 科學出版社, 2020.
[4] [python數據挖掘課程] 二十.KNN最近鄰分類算法分析詳解及平衡秤TXT數據集讀取
[5] TensorFlow【極簡】CNN - Yellow_python大神
[6] 基於深度神經網絡的定向激活功能開發相位信息的聲源定位 - 章子雎Kevin
[7] TensorFlow實戰:Chapter-5(CNN-3-經典卷積神經網絡(GoogleNet)) - DFann
[8] https://github.com/siucaan/CNN_MNIST
[9] 圖像處理講解-以CNN對圖像進行分類爲例 - 冰機靈
[10] 基於CNN的圖像缺陷分類 - BellaVita1
[12] tensorflow(六)訓練分類自己的圖片(CNN超詳細入門版)- Missayaa
[13] 詳解tensorflow訓練自己的數據集實現CNN圖像分類 - 王詩爺 (強推)
[14] https://github.com/hujunxianligong/Tensorflow-CNN-Tutorial
[15] tensorflow(三):用CNN進行圖像分類 - flowrush
[16] TensorFlow圖像識別(物體分類)入門教程 - cococok2
[17] https://github.com/calssion/Fun_AI
[18] CNN圖片分類 - 火舞_流沙
[19] CNN圖片單標籤分類(基於TensorFlow實現基礎VGG16網絡)
[20] https://github.com/siucaan/CNN_MNIST/blob/master/cnn_mnist_TF.py
[21] Tensorflow實現CNN用於MNIST識別 - siucaan (強推)
[22] 使用Anaconda3安裝tensorflow,opencv,使其可以在spyder中運行

 

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章