本博文適用於初學者,利用深度學習來進行圖像識別的應用
對於廣大老司機們來說肯定是so easy啦
ON.1
首先准備大量樣本,樣本?從哪找,這個我相信老司機本絕對比我在行,嘻嘻
這個我碰到過一個坑,初學者們准備樣本時,正常照片和非正常照片(非正常照片?我們不是鑒黃嗎?嗯嗯),本來博主准備幾w張圖片一起訓練但是發現太麻煩了,圖片中有很多臟數據,剔除臟數據就花了我很長的時間,太辣(sex)眼(feeling)了
好啦不多說了,看代碼
這里我准備了2000張非正常圖片,和2000張正常圖片(本來抓取了2w張,結果訓練時直接過擬合了,刪到2000張時穩定了下來)
我這里使用的是keras ,有人問我為什么不用tensorflow,keras后段可以選擇tensorflow和theano,這里我使用的是tensorflow,keras的一個好處就是搭建神經網絡簡單快捷,相比tensorflow要節儉很多行代碼,對於初學者來說很方便
ON.2
樣本不夠,沒關系我們可以根據已有的圖片來生成一些
在這里我們使用keras的ImageDataGenerator,這是一個圖片生成器,可以根據已有的圖片來生成一些新的圖片
datagen = ImageDataGenerator(rescale=1./255,horizontal_flip=True,vertical_flip=True,shear_range=.2,width_shift_range=.2,height_shift_range=.2,data_format='channels_last')
ImageDataGenerator我們使用了很多參數,它們都是什么意思呢
- data_format:分為channel_first和channel_last,這里我們可不要選錯了,channel_first是theano所使用的格式,channel_last是tensorflow所使用的格式,以128x128的RGB圖像為例,“channel_first”應將數據組織為(3,128,128),而“channel_last”應將數據組織為(128,128,3)
- rescale:重放縮因子,默認為None,如果為None或0則不進行放縮
- horizontal_flip:布爾值,進行隨機水平翻
- vertical_flip:布爾值,進行隨機豎直翻轉
- shear_range:浮點數,剪切強度(逆時針方向的剪切變換角度)
- width_shift_range:浮點數,圖片寬度的某個比例,數據提升時圖片水平偏移的幅度
- height_shift_range:浮點數,圖片高度的某個比例,數據提升時圖片豎直偏移的幅度
這里我們使用的圖片大小是(150,150)
img_width, img_height = 150, 150 train_data_dir = 'py/Scrapy/classifier/img/abnormal' validation_data_dir = 'py/Scrapy/classifier/img/test' datagen = ImageDataGenerator(rescale=1./255,horizontal_flip=True,vertical_flip=True,shear_range=.2,width_shift_range=.2,height_shift_range=.2,data_format='channels_last') train_generator = datagen.flow_from_directory( train_data_dir, target_size=(img_width, img_height), batch_size=32, class_mode='binary') validation_generator = datagen.flow_from_directory( validation_data_dir, target_size=(img_width, img_height), batch_size=32, class_mode='binary')
batch_size是batch數據的大小,這里我們是32,即一次傳入多上張圖片
class_mode:"categorical", "binary", "sparse"或None之一. 默認為"categorical. 該參數決定了返回的標簽數組的形式, "categorical"會返回2D的one-hot編碼標簽,"binary"返回1D的二值標簽."sparse"返回1D的整數標簽,如果為None則不返回任何標簽, 生成器將僅僅生成batch數據
因為我們是一個二分類的問題,所以我們選擇binary
現在我們的樣本問題解決了,開始搭建我們的神經網絡模型吧
有些人擔心自己的設備內存會爆掉,不用擔心ImageDataGenerator其實是Python的迭代器,把我們的batch_size調小一點一次傳入少量的圖片就可以啦
NO.3
簡單來說我們把數據格式為(150,150,3)的數據傳入到神經網絡中,(150,150,3)這個是什么意思,這個是(img_width,img_height,圖片通道),彩色圖片通道是3,灰色圖片的為1
model=Sequential() model.add(Conv2D(32,3,3,input_shape=(img_width,img_height,3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(32,3,3)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(64,3,3)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Flatten()) model.add(Dense(64)) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(1)) model.add(Activation('sigmoid'))
Activation('relu')即激活層,這里我們添加一個relu的激活函數
MaxPooling2D是池化層,池化層往往跟在卷積層后面,池化層把之前卷基層得到的特征圖做一個聚合統計,100*100的大小選擇一個2*2的區域做不重疊的最大池化,池化層回輸出50*50的那么大的圖來達到降低數據量的目的,這里我們是150*150,經過最大池化后池化層輸出75*75
經過三層卷積層,池化操作后經過Flateen()
Flateen():把多位的輸入變成一維的,通常在卷積層到全lian jie ceng全連接層的過度,Flatten不影響batch的大小
Dense:全連接層
Dropout:在訓練過程中每次更新參數時按一定概率(rate)隨機斷開輸入神經元,Dropout層用於防止過擬合
直接我們的輸出層大小為1,即我們只輸出一個數據Dense(1),輸出層的激活函數為sigmoid,sigmoid一般用於二分類問題
NO.4
這里我們創建一個Callback用於記錄我們的loss值
from keras.callbacks import Callback class LossHistory(Callback): def on_train_begin(self, logs={}): self.losses = [] def on_batch_end(self, batch, logs={}): self.losses.append(logs.get('loss'))
下面進入正題開始訓練
history_loss=LossHistory() model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy']) nb_epoch=10 nb_train_smaple=4668 nb_validation_samples=392 model.fit_generator(train_generator,samples_per_epoch=nb_train_smaple,nb_epoch=nb_epoch,validation_data=validation_generator,nb_val_samples=nb_validation_samples,callbacks=[history_loss])
因為我們是個二分類問題所以損失函數我們選擇binary_crossentropy
激活函數這里我們不再講解大家可以自行百度,這里使用rmsprop或者adam,使用adam則相對好一些
nb_epoch是訓練的次數這里做個演示我們僅僅訓練10輪
validation_data要填寫我們我們驗證的生成器函數
samples_per_epoch即每一個epoch樣本數達到多少時記一個epoch結束
經過訓練后
達到了92%的識別率,這里大家可以在進行一些優化或者增加訓練的次數
博主你出來第三個是什么~
NO.4
放出所有的代碼
from keras.preprocessing.image import ImageDataGenerator,array_to_img,img_to_array,load_img from keras.models import Sequential from keras.layers import Dense,Flatten,Conv2D,MaxPooling2D,Dropout,Activation img_width, img_height = 150, 150 train_data_dir = 'py/Scrapy/classifier/img/abnormal' validation_data_dir = 'py/Scrapy/classifier/img/test' datagen = ImageDataGenerator(rescale=1./255) train_generator = datagen.flow_from_directory( train_data_dir, target_size=(img_width, img_height), batch_size=32, class_mode='binary') validation_generator = datagen.flow_from_directory( validation_data_dir, target_size=(img_width, img_height), batch_size=32, class_mode='binary') model=Sequential() model.add(Conv2D(32,3,3,input_shape=(img_width,img_height,3))) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(32,3,3)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(64,3,3)) model.add(Activation('relu')) model.add(MaxPooling2D(pool_size=(2,2))) model.add(Flatten()) model.add(Dense(64)) model.add(Activation('relu')) model.add(Dropout(0.5)) model.add(Dense(1)) model.add(Activation('sigmoid')) model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy']) nb_epoch=10 nb_train_smaple=4668 nb_validation_samples=392 model.fit_generator(train_generator,samples_per_epoch=nb_train_smaple,nb_epoch=nb_epoch,validation_data=validation_generator,nb_val_samples=nb_validation_samples) model.save_weights('./abnormal.h5') from keras.utils import plot_model plot_model(model,to_file='./model.png')