用keras作CNN卷积网络书本分类(书本、非书本)
本文介紹如何使用keras作圖片分類(2分類與多分類,其實就一個參數的區別。。。呵呵)?
先來看看解決的問題:從一堆圖片中分出是不是書本,也就是最終給圖片標簽上:“書本“、“非書本”,簡單吧。
先來看看網絡模型,用到了卷積和全連接層,最后套上SOFTMAX算出各自概率,輸出ONE-HOT碼,主要部件就是這些,下面的nb_classes就是用來控制分類數的,本文是2分類:
from keras.models import Sequential from keras.layers.core import Dense, Dropout, Activation, Flatten from keras.layers.convolutional import Convolution2D, MaxPooling2D from keras.optimizers import SGD def Net_model(nb_classes, lr=0.001,decay=1e-6,momentum=0.9): model = Sequential() model.add(Convolution2D(filters=10, kernel_size=(5,5),padding='valid', input_shape=(200, 200, 3))) model.add(Activation('tanh')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(filters=20, kernel_size=(10,10)))model.add(Activation('tanh')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(1000))model.add(Activation('tanh')) model.add(Dropout(0.5)) model.add(Dense(nb_classes)) model.add(Activation('softmax')) sgd = SGD(lr=lr, decay=decay, momentum=momentum, nesterov=True) model.compile(loss='categorical_crossentropy', optimizer=sgd) return model上面的input_shape=(200, 200, 3)代表圖片像素大小為寬高為200,200,并且包含RGB 3通道的圖片,不是灰度圖片(只要1個通道)
也就是說送入此網絡的圖片寬高必須200*200*3;如果不是這個shape就需要resize到這個shape
?
下面來看看訓練程序,首先肯定是要收集些照片,書本、非書本的照片,我是分別放在了0文件夾和1文件夾下了,再帶個驗證用途的文件夾validate:
訓練程序涉及到幾個地方:照片文件的讀取、模型加載訓練與保存、可視化訓練過程中的損失函數value
照片文件的讀取
import cv2 import os import numpy as np import kerasdef loadImages():imageList=[]labelList=[]rootdir="d:\\books\\0"list =os.listdir(rootdir)for item in list:path=os.path.join(rootdir,item)if(os.path.isfile(path)):f=cv2.imread(path)f=cv2.resize(f, (200, 200))#resize到網絡input的shapeimageList.append(f)labelList.append(0)#類別0rootdir="d:\\books\\1"list =os.listdir(rootdir)for item in list:path=os.path.join(rootdir,item)if(os.path.isfile(path)):f=cv2.imread(path)f=cv2.resize(f, (200, 200))#resize到網絡input的shapeimageList.append(f)labelList.append(1)#類別1return np.asarray(imageList), keras.utils.to_categorical(labelList, 2)關于(200,200)這個shape怎么得來的,只是幾月前開始玩opencv時隨便寫了個數值,后來想利用那些圖片,就適應到這個shape了
keras.utils.to_categorical函數類似numpy.onehot、tf.one_hot這些,只是one hot的keras封裝
模型加載訓練與保存
nb_classes = 2 nb_epoch = 30 nb_step = 6 batch_size = 3x,y=loadImages()from keras.preprocessing.image import ImageDataGenerator dataGenerator=ImageDataGenerator() dataGenerator.fit(x) data_generator=dataGenerator.flow(x, y, batch_size, True)#generator函數,用來生成批處理數據(從loadImages中)model=NetModule.Net_model(nb_classes=nb_classes, lr=0.0001) #加載網絡模型history=model.fit_generator(data_generator, epochs=nb_epoch, steps_per_epoch=nb_step, shuffle=True)#訓練網絡,并且返回每次epoch的損失valuemodel.save_weights('D:\\Documents\\Visual Studio 2017\\Projects\\ConsoleApp9\\PythonApplication1\\書本識別\\trained_model_weights.h5')#保存權重 print("DONE, model saved in path-->D:\\Documents\\Visual Studio 2017\\Projects\\ConsoleApp9\\PythonApplication1\\書本識別\\trained_model_weights.h5")ImageDataGenerator構造函數有很多參數,主要用來提升數據質量,比如要不要標準化數字
lr=0.001這個參數要看經驗,大了會導致不收斂,訓練的時候經常由于這個參數的問題導致重復訓練,這在沒有GPU的情況下很是痛苦。。痛苦。。。痛苦。。。
model.save_weights是保存權重,但是不保存網絡模型 ,對應的是model.load_weights方法
model.save是保存網絡+權重,只是。。。。此例中用save_weights保存的h5文件是125M,但用save方法保存后,h5文件就增大為280M了。。。
上面2個save方法都能finetune,只是靈活度不一樣。
可視化訓練過程中的損失函數value
import matplotlib.pyplot as pltplt.plot(history.history['loss']) plt.show()
貌似沒啥好補充的。。。
?
AND。。。。看看預測部分吧,這部分加載圖片、加載模型,似乎都和訓練部分雷同:
def loadImages():imageList=[]rootdir="d:\\books\\validate"list =os.listdir(rootdir)for item in list:path=os.path.join(rootdir,item)if(os.path.isfile(path)):f=cv2.imread(path)f=cv2.resize(f, (200, 200))imageList.append(f)return np.asarray(imageList)x=loadImages()x=np.asarray(x)model=NetModule.Net_model(nb_classes=2, lr=0.0001) model.load_weights('D:\\Documents\\Visual Studio 2017\\Projects\\ConsoleApp9\\PythonApplication1\\書本識別\\trained_model_weights.h5')print(model.predict(x)) print(model.predict_classes(x)) y=convert2label(model.predict_classes(x)) print(y)predict的返回其實是softmax層返回的概率數值,是<=1的float
predict_classes返回的是經過one-hot處理后的數值,此時只有0、1兩種數值(最大的value會被返回稱為1,其他都為0)
convert2label:
def convert2label(vector):string_array=[]for v in vector:if v==1:string_array.append('BOOK')else:string_array.append('NOT BOOK')return string_array這個函數是用來把0、1轉換成文本的,小插曲:
本來這里是中文的“書本”、“非書本”,后來和女兒一起調試時發現都顯示成了問號,應該是中文字符問題,就改成了英文顯示,和女兒一起寫代碼是種樂趣啊!
本來只是顯示文本,感覺太無聊了,因此加上了opencv顯示圖片+分類文本的代碼段:
for i in range(len(x)):cv2.putText(x[i], y[i], (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1, 255, 2)cv2.imshow('image'+str(i), x[i])cv2.waitKey(-1)
?OK, 2018年繼續學習,繼續科學信仰。
?
轉載于:https://www.cnblogs.com/aarond/p/CNN.html
總結
以上是生活随笔為你收集整理的用keras作CNN卷积网络书本分类(书本、非书本)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言如何在可变参数函数中使用print
- 下一篇: lodash源码分析之Hash缓存