我的Github:   Github

利用神经网络来鉴黄

本博文适用于初学者,利用深度学习来进行图像识别的应用

对于广大老司机们来说肯定是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')

 

净化网络环境,自觉拒绝诱惑,拥抱美丽青春,^_^

posted @ 2018-01-29 13:33  寂夜云  阅读(4724)  评论(24编辑  收藏  举报