Keras 系列(六) CNN 分类及fit_generator函数

2019-07-24 16:40:57 浏览数 (2)

在实际项目中,训练数据会很大,以前简单地使用model.fit将整个训练数据读入内存将不再适用,所以需要改用model.fit_generator分批次读取。

Keras中的model.fit_generator参数

该函数的主要参数有:

1. generator:生成器函数,输出应该是形为(inputs,target)或者(inputs,targets,sample_weight)的元组,生成器会在数据集上无限循环

2 steps_per_epoch: 顾名思义,每轮的步数,整数,当生成器返回 stesp_per_epoch次数据时,进入下一轮。

3 epochs :整数,数据的迭代次数

4 verbose:日志显示开关。0代表不输出日志,1代表输出进度条记录,2代表每轮输出一行记录

5 validation_data:验证集数据,有三种形式:

代码语言:javascript复制
 验证集生成器一个形如(x_var,y_val)的元组
一个形如(x_val, y_val,sample_weights)的元组

6 max_queue_size: 整数. 迭代骑最大队列数,默认为10

代码语言:javascript复制
7 workers: 最大进程数。在使用多线程时,启动进程最大数量(process-based threading)。未特别指定时,默认为1。如果指定为0,则执行主线程.8 use_multiprocessing: 布尔值。True:使用基于过程的线程

CNN花朵分类实战

第一步 下载数据,加载相关库

代码语言:javascript复制
#数据下载地址:http://download.tensorflow.org/example_images/flower_photos.tgz
#加载相关模块
from skimage import io,transform
from pandas import Series, DataFrame 
import glob
import os
import numpy as np
from keras.models import Sequential
from keras.layers.core import Flatten,Dense,Dropout
from keras.layers.convolutional import Convolution2D,MaxPooling2D,ZeroPadding2D
from keras.optimizers import SGD,Adadelta,Adagrad
from keras.utils import np_utils,generic_utils
from keras.layers.advanced_activations import PReLU
from keras.layers.core import Flatten, Dense, Dropout 
from keras.layers.core import Dense, Dropout, Activation, Flatten 
from six.moves import range

第二步 设置路径和图片的形状大小

代码语言:javascript复制
path='/home/CNN_Classification/flower_photos' #自己修改路径
w=182
h=182
c=3

第三步 读取所有样本

代码语言:javascript复制
#读取图片
def read_img(path):
    cate=[path '/' x for x in os.listdir(path) if os.path.isdir(path '/' x)]
    print(cate)
    imgs=[]
    labels=[]
    n=
    for idx,folder in enumerate(cate):
        for im in glob.glob(folder '/*.jpg'):
            print('reading the images:%s'%(im))
            img=io.imread(im)
            print('before resize:',img.shape)  # 
            img=transform.resize(img,(w,h))
            print('after:',img.shape)
            imgs.append(img)
            labels.append(idx)
            n=n 
           
    return np.asarray(imgs,np.float32),np.asarray(labels,np.int32)
#调用函数
data,label=read_img(path)
print('叠加之后的形状:',data.shape) #
代码语言:javascript复制
reading the images:/home/CNN_Classification/flower_photos/daisy/517054467_d82d323c33_m.jpg
before resize: (240, 172, 3)
after: (182, 182, 3)
reading the images:/home/CNN_Classification/flower_photos/daisy/7454630692_ab2d67dd18_m.jpg
before resize: (240, 159, 3)
after: (182, 182, 3)
reading the images:/home/CNN_Classification/flower_photos/daisy/5684911529_88a7ae32ba_n.jpg
before resize: (213, 320, 3)
after: (182, 182, 3)
reading the images:/home/CNN_Classification/flower_photos/daisy/4268817944_cdbdb226ae.jpg

第四步 打乱样本,转化标签,编写迭代器

代码语言:javascript复制
#打乱顺序,将标签转为二进制独热形式(0和1组成)
num_example=data.shape[0]
arr=np.arange(num_example)
np.random.shuffle(arr)
data=data[arr]
label=label[arr]
from keras.utils.np_utils import to_categorical
labels_5= to_categorical(label,num_classes=5)
print(label_5)
代码语言:javascript复制
array([[0., 1., 0., 0., 0.],
       [0., 1., 0., 0., 0.],
       [1., 0., 0., 0., 0.],
       ...,
       [0., 0., 0., 0., 1.],
       [1., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.]], dtype=float32)
代码语言:javascript复制
代码语言:javascript复制
def minibatches(inputs=None, targets=None, batch_size=None, shuffle=False):
    while 1:  # 要无限循环
        assert len(inputs) == len(targets)
        if shuffle:
            indices = np.arange(len(inputs))
            np.random.shuffle(indices)
        for start_idx in range(, len(inputs) - batch_size   , batch_size):
            if shuffle:
                excerpt = indices[start_idx:start_idx   batch_size]
            else:
                excerpt = slice(start_idx, start_idx   batch_size)
            yield inputs[excerpt], targets[excerpt]

for x,y  in minibatches(inputs=data, targets=labels_5, batch_size=6, shuffle=False):
    
    print('y的一个批次:',y)
    print('x批次:',x)
代码语言:javascript复制
#注意函数内部是一个while 1死循环,单独测试该函数时要手动停止
y的一个批次:
 [0. 0. 0. 0. 1.]
 [1. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0.]
 [0. 0. 0. 1. 0.]
 [0. 0. 0. 1. 0.]]
x批次: [[[[8.31834912e-01 3.92123640e-01 5.50473154e-01]
   [8.52876544e-01 4.23938811e-01 5.76879978e-01]
   [8.67920816e-01 4.76173371e-01 6.31592453e-01]
   ...
   [9.12868023e-01 5.83456278e-01 7.16789603e-01]
   [8.96439314e-01 5.55262804e-01 6.91900969e-01]
   [8.46583009e-01 5.25663435e-01 6.52079284e-01]]

  [[8.17657828e-01 3.77946556e-01 5.36296070e-01]
   [8.52876544e-01 4.23938811e-01 5.76879978e-01]
   [8.67076039e-01 4.75328594e-01 6.30747676e-01]
   ...
   [9.27464306e-01 5.98052561e-01 7.30427027e-01]
   [9.08384621e-01 5.67208111e-01 7.02976286e-01]
   [8.69190335e-01 5.41265309e-01 6.70181513e-01]]

  [[8.14695120e-01 3.74983847e-01 5.33333361e-01]
   [8.50441694e-01 4.21503991e-01 5.74445188e-01]
   [8.67076039e-01 4.75328594e-01 6.30747676e-01]
   ...
   [9.42060530e-01 6.08727217e-01 7.38138974e-01]
   [9.19397473e-01 5.77890158e-01 7.11333752e-01]
   [8.89581978e-01 5.56199253e-01 6.85865104e-01]]

  ...
第五步  建模、预测
代码语言:javascript复制
model = Sequential() #第一个卷积层,4个卷积核,每个卷积核大小5*5。 
#激活函数用tanh #你还可以在model.add(Activation('tanh'))后加上dropout的技巧: model.add(Dropout(0.5)) 
model.add(Convolution2D(4, 5, 5,input_shape=(w, h,3))) 
model.add(Activation('relu')) 
model.add(MaxPooling2D(pool_size=(2, 2))) #第二个卷积层,8个卷积核,每个卷积核大小3*3。
#激活函数用tanh #采用maxpooling,poolsize为(2,2) 
model.add(Convolution2D(8, 3, 3)) 
model.add(Activation('relu')) 
model.add(MaxPooling2D(pool_size=(2, 2))) 
#第三个卷积层,16个卷积核,每个卷积核大小3*3 #激活函数用tanh 
#采用maxpooling,poolsize为(2,2) 
model.add(Convolution2D(16, 3, 3)) 
model.add(Activation('relu')) 
model.add(MaxPooling2D(pool_size=(2, 2)))
#全连接层,先将前一层输出的二维特征图flatten为一维的。
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.5))
#多分类  
model.add(Dense(5)) # 共有5个类别
model.add(Activation('softmax'))
#print(model.summary())
model.compile(loss='categorical_crossentropy',optimizer='adam')
#model.fit(data,labels_5,epochs=6,batch_size=2,verbose=2)#旧方法不再适用
history=model.fit_generator(minibatches(data,labels_5,batch_size=6,shuffle=False),
                            steps_per_epoch=len(data)//6,
                            epochs=6)
#model.train_on_batch(minibatches(data, labels_5, batch_size=6, shuffle=False))
pyplot.plot(history.history['loss'],label='train')
#这里只是简单地预测训练集中的目标值,想要预测验证集换一下数据即可。
print('预测结果为:',model.predict_classes(data[-3:]))
代码语言:javascript复制
Epoch 1/6
611/611 [==============================] - 70s 115ms/step - loss: 1.2815
Epoch 2/6
611/611 [==============================] - 69s 113ms/step - loss: 1.0301
Epoch 3/6
611/611 [==============================] - 70s 114ms/step - loss: 0.8700
Epoch 4/6
611/611 [==============================] - 70s 114ms/step - loss: 0.7510

预测结果为:

[0 1 3]

..............................................................


0 人点赞