1. 程式人生 > 其它 >xml檔案 卷積神經網路_CNN卷積神經網路入門個人理解和例項程式碼(註釋詳細,一勞永逸)...

xml檔案 卷積神經網路_CNN卷積神經網路入門個人理解和例項程式碼(註釋詳細,一勞永逸)...

技術標籤:xml檔案 卷積神經網路

不鋪墊啥了,最近看深度學習和神經網路有一點啟發,想寫個文章算是做個記錄,直接開始吧。我看的是b站李巨集毅老師的機器學習視訊。

我比較懶,瞭解完原理,寫完一遍程式碼之後,就像寫一個一勞永逸的程式碼,想著以後有不同的應用場景需要,直接改幾個引數然後呼叫就行了,所以這也是我特別喜歡寫註釋的原因。寫註釋是為了一勞永逸。

當然,做圖片分類,大概分為三個過程。 第一,收集你的資料,把它做成資料集(後面我是把資料集做出.npy格式),然後對資料預處理一下。具體就是把你的資料按類分好(丟到不同類名稱的資料夾裡),然後用程式碼把整體資料分成訓練集、驗證集、測試集和生成對應的訓練集label、驗證集_label、測試集_label。 第二、搭建卷積神經網路,把訓練好的模型儲存為.h5檔案。搭建神經網路主要是要確定你處理資料的卷積層結構是什麼,比如一張圖片進去,要經過的卷積層的filter什麼樣,池化層什麼樣,打算設計幾個,最後把得到的資料flatten拉直成一個向量,把這個向量丟到一個全連線層去跑(這整個第二步就叫卷積 神經網路,卷積就是資料去全連線層訓練前的一種處理方式,沒有卷積處理層只有全連線層的神經網路就叫DNN深度神經網路)。 第三、呼叫儲存的模型對某一張圖片預測它的類別,輸出預測結果。

貼程式碼:

接下來以給花分類為例子,給出詳細的程式碼。

注:花的資料集和.npy檔案的建立程式碼是參考了這篇博文,後面附上博文的轉載版權宣告(版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。本文連結:https://blog.csdn.net/umbrellalalalala/article/details/86516928)

第一、收集資料,放到資料資料夾裡面去分好類,一個類一個資料夾(如圖),然後做成.npy檔案,生成的.npy為6維陣列,分別是訓練集,訓練集標籤,驗證集,驗證集標籤,測試集,測試集標籤。其中訓練集的資料是隨機打亂了的,標籤對應也是;而訓練集、驗證集和測試集的資料都是來自於資料資料夾,按比例確定的,比如隨機拿出10%做驗證集,10%測試集,剩下的當作資料集。注:檔名不能有中文

2e0d6b4b69d4d92432eed7b6a102e6f6.png

資料夾名就是類別名,裡面是同一類的圖片
# -*- coding: utf-8 -*-import globimport os.pathimport numpy as npimport tensorflow as tffrom tensorflow.python.platform import gfile# 將分好類的圖片(一個資料夾一類圖片)製作成npy檔案併為每一個類別定好label。# 其中npy包含6個內容,分別為# training_images = np.array(data[0]) 順序將會打亂# training_labels = np.array(data[1]) 順序會和training_images的順序一樣# validation_images = np.array(data[2])# validation_labels = np.array(data[3])# testing_images = np.array(data[4])# testing_labels = np.array(data[5])# 且資料都是分好格式了的(picture_numbers, pixel-x, pixel_y, channel_number),可以直接代到模型裡面
INPUT_DATA = 'E:\\projects\\manchine_learning\\flower_photos' # 原始輸入資料的目錄,其有五個子目錄,每個目錄下儲存屬於該類別的所有圖片
OUTPUT_DATA = 'E:\\projects\\manchine_learning\\flower_processed_data.npy' # 將整理後的圖片資料通過numpy的格式儲存# 測試資料和驗證資料的比例
VALIDATION_PERCENTAGE = 10
TEST_PERCENTAGE = 10# 讀取資料並將資料分割成訓練資料、驗證資料和測試資料# 建立資料列表def create_image_lists(sess, testing_percentage, validation_percentage):# sub_dirs用於儲存INPUT_DATA下的全部子資料夾目錄名稱,有5種花所以有五個元素# os.walk() 方法用於通過在目錄樹中游走輸出在目錄中的檔名,向上或者向下# os.walk(top, topdown=Ture, οnerrοr=None, followlinks=False)# 該函式可以得到一個三元tupple(dirpath, dirnames, filenames)# dirpath:string,代表目錄的路徑;# dirnames:list,包含了當前dirpath路徑下所有的子目錄名字(不包含目錄路徑);# filenames:list,包含了當前dirpath路徑下所有的非目錄子檔案的名字(不包含目錄路徑)。# 注意,dirnames和filenames均不包含路徑資訊,如需完整路徑,可使用os.path.join(dirpath, dirnames)
sub_dirs = [x[0] for x in os.walk(INPUT_DATA)]
is_root_dir = True# 初始化各個資料集
training_images = []
training_labels = []
testing_images = []
testing_labels = []
validation_images = []
validation_labels = []
current_label = 0 # 在接下來的for迴圈中,第一次迴圈時值為0,每次迴圈結束時加一
count = 1 # 迴圈計數器# 對每個在sub_dirs中的子資料夾進行操作,讀取每一類圖片資料for sub_dir in sub_dirs:# 直觀上感覺這個條件結構是多此一舉,暫時不分析為什麼要加上這個語句if is_root_dir:
is_root_dir = Falsecontinue # 繼續下一輪迴圈,下一輪就無法進入條件分支而是直接執行下列語句print("開始讀取第%d類圖片:" % count)
count += 1# 獲取一個子目錄中所有的圖片檔案
extensions = ['jpg', 'jpeg', 'JPG', 'JPEG'] # 列出所有副檔名
file_list = []# os.path.basename()返回path最後的檔名。若path以/或\結尾,那麼就會返回空值# 如path=‘c:\program\data.csv’,則返回data.csv,path=‘c:\program\files’則返回files
dir_name = os.path.basename(sub_dir) # 返回子資料夾的名稱,待會兒還要讀取資料夾裡面的檔案# 針對不同的副檔名,將其檔名加入檔案列表for extension in extensions:# INPUT_DATA是資料集的根資料夾,其下有五個子資料夾,每個資料夾下是一種花的照片;# dir_name是這次迴圈中存放所要處理的某種花的圖片的資料夾的名稱# file_glob形如"INPUT_DATA/dir_name/*.extension"
file_glob = os.path.join(INPUT_DATA, dir_name, '*.' + extension) # 將檔名稱的正則表示式# extend()的作用是將glob.glob(file_glob)加入file_list# glob.glob()返回所有匹配正則表示式file_glob的檔案路徑列表,此處返回的是所有在INPUT_DATA/dir_name資料夾中,且副檔名是extension的檔案
file_list.extend(glob.glob(file_glob))# 猜想這句話的意思是,如果file_list是空list,則不繼續執行下面的資料處理部分,而是直接進行下一輪迴圈,# 即換一個子資料夾繼續操作,相當於這個類沒有training_data,後面自然也不用輸入了if not file_list: continueprint("檔名列表製作完畢,開始讀取圖片檔案") # 到此處為止第一個資料夾裡的所有圖片名稱都被讀取到file_list裡面了# 將file_list中的圖片檔案一條一條進行資料處理# 注意此時file_list已經變成了一個基本單位為字串的list,list中的每個字串儲存的是一個圖片的完整檔名(含路徑),# 這些圖片所屬的資料夾就是這一輪迴圈的sub_dirfor file_name in file_list:# 以下兩行是讀檔案常用語句,‘rb’表示對非utf-8編碼檔案解碼或者叫讀取
image_raw_data = gfile.FastGFile(file_name, 'rb').read()# 將讀取到的jpeg檔案解碼
image = tf.image.decode_jpeg(image_raw_data)# 如果圖片資料的型別不是float32,則轉換之if image.dtype != tf.float32:
image = tf.image.convert_image_dtype(image, dtype=tf.float32)# 調整圖片的尺寸,將其化為299*299,以便inception-v3模型來處理
image = tf.image.resize(image, [299, 299])
image_value = sess.run(image) # 提示:sess.run(image)返回image的計算結果;# 至此, image_value型別是299*299的float32型矩陣,代表當前迴圈所處理的圖片檔案# 隨機劃分資料集,通過生成一個0-99的隨機數chance來決定當前迴圈中的某一類圖片資料夾種的哪些圖片劃入驗證集、測試集還是訓練集# np.random.randint(100)作用是隨機生成在0-99間的一個數(此函式還可以指定返回的尺寸,比如可以指定返回一個x*y的矩陣,未指定尺寸則返回一個數)
chance = np.random.randint(100)if chance < validation_percentage:
validation_images.append(image_value) # 由於一共有3670張圖片,這樣最終的validation_images的尺寸大致是(3670*validation_percentage%)*229*229*3
validation_labels.append(current_label) # 由於一共有3670張圖片,這樣最終的validation_labels的尺寸大致是(3670*validation_percentage%)*1elif chance < (testing_percentage + validation_percentage):
testing_images.append(image_value)
testing_labels.append(current_label)else:
training_images.append(image_value)
training_labels.append(current_label)
current_label += 1 # 注意這一行在上一個for外面,在最外層for裡面;作用是在進入最外層for的下一輪迴圈之前,將"當前標籤"加一,以表示下一個圖片資料夾print("本類圖片讀取完畢")print("開始打亂訓練資料集")# 將訓練資料隨機打亂以獲得更好的訓練效果# 注意這裡已經跳出了for迴圈,此時的training_image尺寸大致是(3670*(100-validition_percentage-testing_percentage)%)*299*299*3# training_labels尺寸大致是(734*(100-validition_percentage-testing_percentage)%)*1
state = np.random.get_state() # 獲取隨機生成器np.random的狀態
np.random.shuffle(training_images) # 進行打亂操作,如果物件是多維矩陣,只對第一維進行打亂操作
np.random.set_state(state) # 將之前隨機生成器的狀態設定為現在隨機生成器的狀態,目的是讓下面一行對標籤的打亂和上一行圖片的打亂一致
np.random.shuffle(training_labels)print("資料集處理完畢!")return np.asarray([training_images, training_labels,
validation_images, validation_labels,
testing_images, testing_labels])def main():with tf.compat.v1.Session() as sess:
processed_data = create_image_lists(
sess, TEST_PERCENTAGE, VALIDATION_PERCENTAGE)
np.save(OUTPUT_DATA, processed_data)if __name__ == '__main__':
main()