本博文适用于初学者,利用深度学习来进行图像识别的应用
对于广大老司机们来说肯定是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')