機器學習-計算機視覺和卷積網路CNN
- 概述
對於計算機視覺的應用現在是非常廣泛的,但是它背後的原理其實非常簡單,就是將每一個畫素的值pixel輸入到一個DNN中,然後讓這個神經網路去學習這個模型,最後去應用這個模型就可以了。聽起來是不是很簡單,其實如果大家深入研究的話,這裡面還是有很多內容去學習的,例如:咱們的圖片大小可能不一樣,同一張圖片不同的旋轉角度可到的結果可能不一樣,如何給咱們的本地圖片來label(實際中並不是所有的資料都想mnist那樣,谷歌都給咱們label好了,拿來用就行),等等這些問題咱們在實際中肯定都是要用到的。這一節首先會先介紹一下如何直接將圖片的塞進網路訓練;第二部分會介紹一下卷積網路的結構原理和應用(用谷歌自己提供的mnist資料集);第三部分我會介紹一下如何用卷及網路CNN來訓練咱們自己的圖片資料。其中的核心重點是咱們的第二部分。
- 傳統DNN之圖片識別
傳統的DNN肯定大家都是知道的,就是通過構建Sequential layers, 然後將咱們的圖片的pixel值作為資料傳遞給這個DNN的input layer, 只有這個input layer後面的dense layers是根據使用者自己的需求進行建立架構的。那麼通過什麼流程來訓練呢?首先第一步咱們得載入資料,如下所示
mnist = tf.keras.datasets.fashion_mnist (training_images, training_labels), (test_images, test_labels) = mnist.load_data() training_images=training_images/255.0 test_images=test_images/255.0
上面的資料是咱們TensorFlow自帶的,它都幫助咱們這裡好了,也幫助咱們把圖片的labels都設定好了,幫助咱們省了很多的功夫,但是很遺憾,這些資料只能在學習的時候用,在實際的工業環境中,咱們是不可能這麼幸運的,嘿嘿。那麼咱們這裡就先用這個demo 資料來學習吧。接下來第二步,咱們來構建咱們的DNN,咱們接著往下看
model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(512, activation=tf.nn.relu), tf.keras.layers.Dense(10, activation=tf.nn.softmax) ])
這裡跟咱們前面說的普通DNN稍微有點不同,那就是咱們在dense layers之前加了一個tf.keras.layers.Flatten()函式,因為咱們的圖片不像咱們之前dataframe資料那樣每一行資料都是將features排列好的,每一張圖片都是一個二維(或者三維)的pixel值,這些pixel就是咱們這個model的features,所以咱們必須得將這個圖片的畫素全部轉化成一列資料,而咱們的Flatten()函式就是做這個工作的。在這個classification的場景中,咱們一共有的classes是10個,所以咱們最後的output layer的units的數量是10個,這個數量必須要匹配,否則會有error。第三部就是configure這個模型,如下
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
當然啦,在這裡咱們可以加一個callbacks,當咱們的loss小於0.4的時候,咱們就停止咱們模型的訓練
class myCallback(tf.keras.callbacks.Callback): def on_epoch_end(self, epoch, logs={}): if(logs.get('loss')<0.4): print(logs) print("\nReached 0.4 loss so cancelling training!") self.model.stop_training = True callbacks = myCallback()
最後當然就是咱們的訓練的過程啦,
model.fit(training_images, training_labels, epochs=5, callbacks=[callbacks])
至於後面的predict和evaluate的過程,更前面章節講的都是一模一樣的,這裡就不在展示啦。上面展示的是一個用傳統的DNN來訓練label好了的圖片來建立一個神經網路,可惜的是在實際中我們幾乎不會用這種方式來做圖片的classification,因為在實際中每一個圖片的大小都是不一樣的,所以每一個input layer都是不一樣,很顯然這不符合咱們的實際情況;另外實際中圖片不可能都是給你label好了,並且放在dataset裡面,這些都需要咱們額外去做的工作,那麼咱們這裡就要來看看咱們如何來解決這些問題。
- 計算機視覺之圖片資料準備
咱們都知道在實際中,咱們沒有準備好的mnist dataset,所有的圖片都需要咱們自己去label,那麼如何給不同的本地圖片分配不同的labels, 並且最後怎麼組織這是圖片和label資料來訓練呢?這裡咱們就要用到一個TensorFlow裡面專門用於處理圖片的一個庫了,那就是ImageDataGenerator,它會給咱們的圖片根據資料夾的名稱來label,並且將這些圖片和labels組織起來變成一個類似於dataset的資料集,我們稱之於generator,咱們在這裡就將它看成一個類似於dataset的資料集就行了,並且可以直接傳遞給model.fit()來訓練,就跟dataset一樣。那咱們就來看一下這個具體的流程吧,咱們這裡就以一個本地的壓縮檔案為例來展示一下,如何將一個本地的圖片來label並且生成一個generator。
第一步:解壓資料夾
import os import zipfile local_zip = "C:\\Users\\tangx\\OneDrive\\Desktop\\DATA\\cats_and_dogs_filtered.zip" zip_ref = zipfile.ZipFile(local_zip,'r') zip_ref.extractall("C:\\Users\\tangx\\OneDrive\\Desktop\\DATA")#where we extract our zip file to zip_ref.close
上面將一個壓縮的資料夾cats_and_dogs_filtered.zip解壓到C:\\Users\\tangx\\OneDrive\\Desktop\\DATA這個資料夾中,並且解壓後的檔名就是cats_and_dogs_filtered。
第二步:define all subdirectories
base_dir = "C:\\Users\\tangx\\OneDrive\\Desktop\\DATA\\cats_and_dogs_filtered"
train_dir = os.path.join(base_dir, "train") val_dir = os.path.join(base_dir,"validation") train_cats_dir = os.path.join(train_dir,"cats") train_dogs_dir = os.path.join(train_dir,"dogs") val_cats_dir = os.path.join(val_dir,"cats") val_dogs_dir = os.path.join(val_dir,"dogs")
這一步咱們定義了咱們所有圖片的子資料夾,這些子資料夾中裝著的正是咱們的圖片。
第三步:生成ImageDataGenerator
from tensorflow.keras.preprocessing.image import ImageDataGenerator #rescale train_imagegen = ImageDataGenerator(rescale=1/255.0) val_imagegen = ImageDataGenerator(rescale=1/255.0) #flow image data """ train_dir: which directory our image data are embeded in batch_size:the number of images our image generator yields each time target_size: our oringial images are various shape, so here we set all the image to a fixed size, wich is (150,150) """ #the labels will be based on the directories's name, wwhich is sorted alphanumeric; for example: cats:0; dogs:1 train_imagegen = train_imagegen.flow_from_directory(train_dir,batch_size=20,class_mode="binary",target_size=(150,150)) val_imagegen = val_imagegen.flow_from_directory(val_dir,batch_size=20,class_mode="binary",target_size=(150,150))
這裡首先咱們例項化一個ImageDatagenerator並且對咱們後面要匯入的照片進行一個rescale, 然後通過這個generator呼叫它的物件方法flow_from_directory()來給咱們的圖片label並且生成咱們的最終的資料對generator。這裡有幾個引數需要了解一下,一個batch_size是指到時候在訓練資料的時候每一個gradient選擇多少個數據來計算, class_mode是指你的classification是什麼型別,這裡有這幾種可能是 “binary”,“sparse”, "categorical", "input"和None這幾種情況,根據咱們的實際情況來選擇。還有一個很重要的引數,那就是target_size, 這個引數能把咱們的圖片全部轉化成相同的大小,這給咱們後面建立神經網路的時候帶來了極大的方便,在建立神經網路的時候咱們可以固定咱們input layer中node的數量了。還有一個很小的細節容易忽視,那就是imagegenerator給咱們圖片label的時候是根據裝咱們圖片的資料夾的名稱的字母順序來得,例如cats,label是0;dogs, label是1。至此,咱們已經完成了所有的圖片的準備工作的了,包括圖片的label,圖片的大小統一等工作。下面咱們就要來說說咱們在計算機視覺中應用的最廣泛的一種網路結構了,那就是卷積網路CNN。
- 卷積網路CNN
對於Convolutional Neuro Network (CNN), 咱們第一步得了解他的結構是什麼樣的,然後才能理解它的一些概念,例如:filter, pooling等概念。那麼下面我自己花了一張簡易的CNN的網路結構圖,如果大家理解了下面的這個網路結構,那麼大家肯定也就立即了CNN的一下概念,咱們直接看下面的圖片
上面的圖片展示的就是一個含有一個convolution layer, 一個pooling layer的一個卷積網路。首先咱們的原始圖片是一張28*28畫素的圖片,之後咱們讓TensorFlow隨機生成9個filter,每一個filter都是一個3*3結構的filter,這裡就是咱們整個CNN的核心了。然後讓每一個filter都去cover一下咱們的原始圖片都會生成一個26*26的圖片,所以咱們一共生成了9個26*26的圖片;注意實際上這裡每一個filter都是根據不同的角度來提取咱們原始圖片的特徵,這就是這些filter的本質。之後所有的這些經過過濾後的26*26size 的圖片再經過一個Maxpooling(2*2)層來壓縮咱們的26*26的圖片,結果就是生成了9個13*13的圖片。為了將這個資料載入在咱們後面的DNN中進行計算,很顯然咱們還是得將這9個13*13的圖片經過flatten操作後才能將它作為咱們的input layer。後面的步驟就跟咱們傳統的DNN是一模一樣的了。那麼這裡的核心就是filter的過程,它是用來提取不同角度的圖片的特徵的。如果上面的CNN的結構理解了,那麼我們就接著上面的imagegenerator的例子,看看如何用TensorFlow來應用CNN吧。首先搭建CNN結構
model = tf.keras.Sequential([ # Note the input shape is the desired size of the image 150x150 with 3 bytes color tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Conv2D(16, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), tf.keras.layers.Conv2D(64, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), # Flatten the results to feed into a DNN tf.keras.layers.Flatten(), tf.keras.layers.Dense(1024, activation='relu'), tf.keras.layers.Dense(128, activation='relu'), # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('cats') and 1 for the other ('dogs') tf.keras.layers.Dense(1, activation='sigmoid') ]) model.compile( optimizer = tf.optimizers.Adam(0.0001), loss = "binary_crossentropy", metrics = ["acc"] )
首先咱們看出這個網路結構中,咱們構建了3個convolutional layers, 第一個卷積層的filter數量四32,第二個卷積層的filter數量是16,第三個卷積層數量是64。並且在第一個卷積層咱們聲明瞭咱們每一個圖片的size和dimension,例如咱們的圖片是彩色的圖片,長寬都是150,然後彩色圖片有3個channel,所以咱們的input_shape=(150, 150, 3)。接下來就是咱們的training的過程了。
model.fit(train_imagegen, epochs=15, validation_data=val_imagegen, shuffle=True)
這裡的fit函式咱們可以看出來,咱們就是直接傳遞的generator當做資料傳遞給它當做咱們的資料來源了。至於後面的predict,evaluate等方式,跟前面章節講的DNN的過程完全一樣,這裡我就不在贅述了。好了這就是CNN在計算機視覺中的應用。
&n