1. 为什么要使用 fit_generator
- 我们都知道我们在进行神经网络训练的时候如果使用
model.fit
的方式训练,
那么我们需要把整个x_train
加载到内存中,而 keras 自带的一些 datasets 又很小,在训练的时候完全可以这么做,所以如果是 keras 的小白,可能觉得 fit 是一个很好用的训练方法,而且也习惯了这种方式。 - 但是,如果我现在想用
ImageNet
数据集(1000000张图片,1000个类别)来进行训练,直接加载到内存,内存会爆掉,所以我们要批量地把他们放到内存里。那么这就产生了一个问题,我们使用fit
来训练的时候,在接口中封装了batch_size
的参数,我们只需要输入一个数字,他就能够按照我们输入的尺寸对数据集进行分割,方便又快捷,那么如果我们手动地让他们一批批地送入内存中进行训练,该如何实现呢?接下来进入第二部分,创建一个generator
来替你完成原来fit
中batch_size
所做的工作
2. 如何创建 generator
- 这里拿最简单的数据集 mnist 来做个展示
from keras.datasets import mnist
from keras.layers import Conv2D,MaxPool2D,Dropout,Flatten,Dense
from keras.models import Sequential
from keras.utils import to_categorical
import numpy as np
import keras
#### 分导入数据集 #####
(x_train,y_train),(x_test,y_test)= mnist.load_data()
#### 对数据维度进行调整 ####
x_train_ = np.expand_dims(x_train,3) # (60000,28,28,1)
y_train_ = to_categorical(y_train) # (60000,10)
x_test_ = np.expand_dims(x_test,3) # (10000,28,28,1)
y_test_ = to_categorical(y_test) # (10000,10)
##### 定义 cnn 网络 #####
def cnn():
model = Sequential()
model.add(Conv2D(input_shape=(28,28,1),filters=25,kernel_size=(3,3),padding='same',activation='relu'))
model.add(MaxPool2D())
model.add(Dropout(rate=0.3))
model.add(Flatten())
model.add(Dense(32,activation='relu'))
model.add((Dense(10,activation='softmax')))
return model
#### 规定 generator 每一次产生的数据量 64 个
#### 数据从 x_train_ 数据集中产生,x_train_数据集的尺寸是 dataset_size=60000
batchsize = 64
dataset_size = x_train_.shape[0]
def generator(x_train_,y_train_,batchsize=batchsize,shuffle=True):
dataset_size = x_train_.shape[0]
while True:
i = 0
if shuffle: # 对数据集洗牌的话,就每次随机抽取 batchsize 个数作为抽取的索引
img_index = np.random.randint(0,dataset_size,batchsize)
img = x_train_[img_index]
label = y_train_[img_index]
else: # 不对数据集洗牌的话,就每次顺序抽取 batchsize 个数作为抽取的索引
img = x_train_[i:((i+batchsize)% dataset_size)] # (i+batchsize % dataset_size) 是为了防止索引数超出数据集的最大索引,以便于可以循环训练
label = y_train_[i:((i+batchsize)% dataset_size)]
i = (i+batchsize)% dataset_size
yield (img,label)
3. 如何使用 fit_generator
- 首先让我们先测试一下我们的 generator 是否能够按照要求来产生我们想要的数据格式:
gen = generator(x_train_,y_train_,shuffle=True)
data_batch = x.__next__()
print(data_batch[0].shape)
print(data_batch[0])
-
可以看见产生的数据格式是非常标准啦~
-
接下来,把
generator
加载到fit_generator
接口中:
net = cnn() ## 创建 cnn 网络
net.compile(loss=keras.losses.categorical_crossentropy,optimizer=keras.optimizers.Adam(0.001),metrics=['accuracy'])
net.fit_generator(generator=gen,steps_per_epoch=dataset_size/batchsize,epochs=5,validation_data=(x_test_,y_test_))
- 这里的
gen
就是我们刚才的generator
, steps_per_epoch
顾名思义,就是每一个epoch
进行多少步:steps * steps_per_epoch = epoch
比如我们generator
中定义了每一批产生64
个数据,这对于fit_generator
来说就是一个step
的数据,所以每个epoch=60000
个数据的话:steps_per_epoch = 60000 / 64
\- 为什么要用
step_per_epoch
呢, 因为fit_generator
由于生成器generator
的缘故,会一直进行循环数据的产生,从而一直不停下来,这时候我们需要人为设定每个epoch
中有多少个step
,否则训练永远不会停止。想试验一下的小伙伴可以在训练的时候不写step_per_epoch
的参数试一下。
4. 完整代码
from keras.datasets import mnist
from keras.layers import Conv2D,MaxPool2D,Dropout,Flatten,Dense
from keras.models import Sequential
from keras.utils import to_categorical
import numpy as np
import keras
(x_train,y_train),(x_test,y_test)= mnist.load_data()
x_train_ = np.expand_dims(x_train,3)
y_train_ = to_categorical(y_train)
x_test_ = np.expand_dims(x_test,3)
y_test_ = to_categorical(y_test)
def cnn():
model = Sequential()
model.add(Conv2D(input_shape=(28,28,1),filters=25,kernel_size=(3,3),padding='same',activation='relu'))
model.add(MaxPool2D())
model.add(Dropout(rate=0.3))
model.add(Flatten())
model.add(Dense(32,activation='relu'))
model.add((Dense(10,activation='softmax')))
return model
batchsize = 64
dataset_size = x_train_.shape[0]
def generator(x_train_,y_train_,batchsize=batchsize,shuffle=True):
dataset_size = x_train_.shape[0]
while True:
i = 0
if shuffle:
img_index = np.random.randint(0,dataset_size,batchsize)
img = x_train_[img_index]
label = y_train_[img_index]
else:
img = x_train_[i:((i+batchsize)% dataset_size)]
label = y_train_[i:((i+batchsize)% dataset_size)]
i = (i+batchsize)% dataset_size
yield (img,label)
net = cnn()
net.compile(loss=keras.losses.categorical_crossentropy,optimizer=keras.optimizers.Adam(0.001),metrics=['accuracy'])
net.fit_generator(generator=x,steps_per_epoch=dataset_size/batchsize,epochs=5,validation_data=(x_test_,y_test_))
代码不复杂,希望大家深刻理解,也希望这篇文章能够帮助到你~~