42

利用神经网络来鉴黄 - 寂夜云

 6 years ago
source link: https://www.cnblogs.com/lonenysky/p/8376843.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

利用神经网络来鉴黄

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

对于广大老司机们来说肯定是so easy啦

首先准备大量样本,样本?从哪找,这个我相信老司机本绝对比我在行,嘻嘻

这个我碰到过一个坑,初学者们准备样本时,正常照片和非正常照片(非正常照片?我们不是鉴黄吗?嗯嗯),本来博主准备几w张图片一起训练但是发现太麻烦了,图片中有很多脏数据,剔除脏数据就花了我很长的时间,太辣(sex)眼(feeling)了

好啦不多说了,看代码

这里我准备了2000张非正常图片,和2000张正常图片(本来抓取了2w张,结果训练时直接过拟合了,删到2000张时稳定了下来)

我这里使用的是keras ,有人问我为什么不用tensorflow,keras后段可以选择tensorflow和theano,这里我使用的是tensorflow,keras的一个好处就是搭建神经网络简单快捷,相比tensorflow要节俭很多行代码,对于初学者来说很方便

样本不够,没关系我们可以根据已有的图片来生成一些

在这里我们使用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调小一点一次传入少量的图片就可以啦

简单来说我们把数据格式为(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一般用于二分类问题

 

784993-20180129133252171-152020002.png

这里我们创建一个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结束

经过训练后

784993-20180129130855531-1420375614.png

达到了92%的识别率,这里大家可以在进行一些优化或者增加训练的次数

784993-20180129132600468-1543723074.png

 博主你出来第三个是什么~

放出所有的代码

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')

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK