本文地址:http://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html
本文作者:Francois Chollet
- 按照官方的文章实现过程有一些坑,彻底理解代码细节实现,理解keras的api具体使用方法
- 也有很多人翻译这篇文章,但是有些没有具体实现细节
- 另外keres开发者自己有本书的jupyter:Companion Jupyter notebooks for the book "Deep Learning with Python"
- 另外我自己实验三收敛的准确率并没有0.94+,可以参考前面这本书上的实现
- 文章一共有三个实验:
1. 第一个实验使用自定义的神经网络对数据集进行训练,三层卷积加两层全连接,训练并验证网络的准确率;
2. 第二个实验使用VGG16网络对数据进行训练,为了适应自定义的数据集,将VGG16网络的全连接层去掉,作者称之为 “Feature extraction”, 再在上面添加自己实现的全连接层,然后训练并验证网络准确性;
3. 第三个实验称为 “fine-tune” ,利用第二个实验的实验模型和weight,重新训练VGG16的最后一个卷积层和自定义的全连接层,然后验证网络准确性; - 实验二的代码:
'''This script goes along the blog post "Building powerful image classification models using very little data" from blog.keras.io. It uses data that can be downloaded at: https://www.kaggle.com/c/dogs-vs-cats/data In our setup, we: - created a data/ folder - created train/ and validation/ subfolders inside data/ - created cats/ and dogs/ subfolders inside train/ and validation/ - put the cat pictures index 0-999 in data/train/cats - put the cat pictures index 1000-1400 in data/validation/cats - put the dogs pictures index 12500-13499 in data/train/dogs - put the dog pictures index 13500-13900 in data/validation/dogs So that we have 1000 training examples for each class, and 400 validation examples for each class. In summary, this is our directory structure: ``` data/train/dogs/dog001.jpgdog002.jpg...cats/cat001.jpgcat002.jpg...validation/dogs/dog001.jpgdog002.jpg...cats/cat001.jpgcat002.jpg... ``` ''' import numpy as np from keras.preprocessing.image import ImageDataGenerator from keras.models import Sequential from keras.layers import Dropout, Flatten, Dense from keras import applications# dimensions of our images. img_width, img_height = 150, 150top_model_weights_path = 'bottleneck_fc_model.h5'data_root = 'M:/dataset/dog_cat/' train_data_dir =data_root+ 'data/train' validation_data_dir = data_root+'data/validation' nb_train_samples = 2000 nb_validation_samples = 800 epochs = 50 batch_size = 16def save_bottlebeck_features():datagen = ImageDataGenerator(rescale=1. / 255)# build the VGG16 networkmodel = applications.VGG16(include_top=False, weights='imagenet')generator = datagen.flow_from_directory(train_data_dir,target_size=(img_width, img_height),batch_size=batch_size,class_mode=None,shuffle=False)bottleneck_features_train = model.predict_generator(generator, nb_train_samples // batch_size) #####2000//batch_size!!!!!!!!!!np.save('bottleneck_features_train.npy',bottleneck_features_train)generator = datagen.flow_from_directory(validation_data_dir,target_size=(img_width, img_height),batch_size=batch_size,class_mode=None,shuffle=False)bottleneck_features_validation = model.predict_generator(generator, nb_validation_samples // batch_size)np.save('bottleneck_features_validation.npy',bottleneck_features_validation)def train_top_model():train_data = np.load('bottleneck_features_train.npy')train_labels = np.array([0] * int(nb_train_samples / 2) + [1] * int(nb_train_samples / 2))validation_data = np.load('bottleneck_features_validation.npy')validation_labels = np.array([0] * int(nb_validation_samples / 2) + [1] * int(nb_validation_samples / 2))model = Sequential()model.add(Flatten(input_shape=train_data.shape[1:]))model.add(Dense(256, activation='relu'))model.add(Dropout(0.5))model.add(Dense(1, activation='sigmoid'))model.compile(optimizer='rmsprop',loss='binary_crossentropy', metrics=['accuracy'])model.fit(train_data, train_labels,epochs=epochs,batch_size=batch_size,validation_data=(validation_data, validation_labels))model.save_weights(top_model_weights_path)#save_bottlebeck_features() train_top_model()
- 实验三代码,自己添加了一些api使用方法,也是以后可以参考的:
'''This script goes along the blog post "Building powerful image classification models using very little data" from blog.keras.io. It uses data that can be downloaded at: https://www.kaggle.com/c/dogs-vs-cats/data In our setup, we: - created a data/ folder - created train/ and validation/ subfolders inside data/ - created cats/ and dogs/ subfolders inside train/ and validation/ - put the cat pictures index 0-999 in data/train/cats - put the cat pictures index 1000-1400 in data/validation/cats - put the dogs pictures index 12500-13499 in data/train/dogs - put the dog pictures index 13500-13900 in data/validation/dogs So that we have 1000 training examples for each class, and 400 validation examples for each class. In summary, this is our directory structure: ``` data/train/dogs/dog001.jpgdog002.jpg...cats/cat001.jpgcat002.jpg...validation/dogs/dog001.jpgdog002.jpg...cats/cat001.jpgcat002.jpg... ``` ''' # thanks sove bug @http://blog.csdn.net/aggresss/article/details/78588135from keras import applications from keras.preprocessing.image import ImageDataGenerator from keras import optimizers from keras.models import Sequential from keras.layers import Dropout, Flatten, Dense from keras.models import Model from keras.regularizers import l2# path to the model weights files. weights_path = '../keras/examples/vgg16_weights.h5' top_model_weights_path = 'bottleneck_fc_model.h5' # dimensions of our images. img_width, img_height = 150, 150data_root = 'M:/dataset/dog_cat/' train_data_dir =data_root+ 'data/train' validation_data_dir = data_root+'data/validation'nb_train_samples = 2000 nb_validation_samples = 800 epochs = 50 batch_size = 16# build the VGG16 network base_model = applications.VGG16(weights='imagenet', include_top=False, input_shape=(150,150,3)) # train 指定训练大小 print('Model loaded.')# build a classifier model to put on top of the convolutional model top_model = Sequential() top_model.add(Flatten(input_shape=base_model.output_shape[1:])) # base_model.output_shape[1:]) top_model.add(Dense(256, activation='relu',kernel_regularizer=l2(0.001),)) top_model.add(Dropout(0.8)) top_model.add(Dense(1, activation='sigmoid'))# note that it is necessary to start with a fully-trained # classifier, including the top classifier, # in order to successfully do fine-tuning top_model.load_weights(top_model_weights_path)# add the model on top of the convolutional base # model.add(top_model) # bugmodel = Model(inputs=base_model.input, outputs=top_model(base_model.output))# set the first 25 layers (up to the last conv block) # to non-trainable (weights will not be updated) for layer in model.layers[:15]: # :25 buglayer.trainable = False# compile the model with a SGD/momentum optimizer # and a very slow learning rate. model.compile(loss='binary_crossentropy',optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),metrics=['accuracy'])# prepare data augmentation configuration train_datagen = ImageDataGenerator(rescale=1. / 255,shear_range=0.2,zoom_range=0.2,horizontal_flip=True)test_datagen = ImageDataGenerator(rescale=1. / 255)train_generator = train_datagen.flow_from_directory(train_data_dir,target_size=(img_height, img_width),batch_size=batch_size,class_mode='binary')validation_generator = test_datagen.flow_from_directory(validation_data_dir,target_size=(img_height, img_width),batch_size=batch_size,class_mode='binary')model.summary() # prints a summary representation of your model. # let's visualize layer names and layer indices to see how many layers # we should freeze: for i, layer in enumerate(base_model.layers):print(i, layer.name)from keras.utils import plot_model plot_model(model, to_file='model.png')from keras.callbacks import History from keras.callbacks import ModelCheckpoint import keras history = History() model_checkpoint = ModelCheckpoint('temp_model.hdf5', monitor='loss', save_best_only=True) tb_cb = keras.callbacks.TensorBoard(log_dir='log', write_images=1, histogram_freq=0) # 设置log的存储位置,将网络权值以图片格式保持在tensorboard中显示,设置每一个周期计算一次网络的 # 权值,每层输出值的分布直方图 callbacks = [history,model_checkpoint,tb_cb] # model.fit()# fine-tune the model history=model.fit_generator(train_generator,steps_per_epoch=nb_train_samples // batch_size,epochs=epochs,callbacks=callbacks,validation_data=validation_generator,validation_steps=nb_validation_samples // batch_size,verbose = 2)model.save('fine_tune_model.h5') model.save_weights('fine_tune_model_weight') print(history.history)from matplotlib import pyplot as plt history=history plt.plot() plt.plot(history.history['val_acc']) plt.title('model accuracy') plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show() # summarize history for loss plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('model loss') plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show()import numpy as np accy=history.history['acc'] np_accy=np.array(accy) np.savetxt('save_acc.txt',np_accy)
- result
Model loaded. Found 2000 images belonging to 2 classes. Found 800 images belonging to 2 classes. _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) (None, 150, 150, 3) 0 _________________________________________________________________ block1_conv1 (Conv2D) (None, 150, 150, 64) 1792 _________________________________________________________________ block1_conv2 (Conv2D) (None, 150, 150, 64) 36928 _________________________________________________________________ block1_pool (MaxPooling2D) (None, 75, 75, 64) 0 _________________________________________________________________ block2_conv1 (Conv2D) (None, 75, 75, 128) 73856 _________________________________________________________________ block2_conv2 (Conv2D) (None, 75, 75, 128) 147584 _________________________________________________________________ block2_pool (MaxPooling2D) (None, 37, 37, 128) 0 _________________________________________________________________ block3_conv1 (Conv2D) (None, 37, 37, 256) 295168 _________________________________________________________________ block3_conv2 (Conv2D) (None, 37, 37, 256) 590080 _________________________________________________________________ block3_conv3 (Conv2D) (None, 37, 37, 256) 590080 _________________________________________________________________ block3_pool (MaxPooling2D) (None, 18, 18, 256) 0 _________________________________________________________________ block4_conv1 (Conv2D) (None, 18, 18, 512) 1180160 _________________________________________________________________ block4_conv2 (Conv2D) (None, 18, 18, 512) 2359808 _________________________________________________________________ block4_conv3 (Conv2D) (None, 18, 18, 512) 2359808 _________________________________________________________________ block4_pool (MaxPooling2D) (None, 9, 9, 512) 0 _________________________________________________________________ block5_conv1 (Conv2D) (None, 9, 9, 512) 2359808 _________________________________________________________________ block5_conv2 (Conv2D) (None, 9, 9, 512) 2359808 _________________________________________________________________ block5_conv3 (Conv2D) (None, 9, 9, 512) 2359808 _________________________________________________________________ block5_pool (MaxPooling2D) (None, 4, 4, 512) 0 _________________________________________________________________ sequential_1 (Sequential) (None, 1) 2097665 ================================================================= Total params: 16,812,353 Trainable params: 9,177,089 Non-trainable params: 7,635,264 _________________________________________________________________ 0 input_1 1 block1_conv1 2 block1_conv2 3 block1_pool 4 block2_conv1 5 block2_conv2 6 block2_pool 7 block3_conv1 8 block3_conv2 9 block3_conv3 10 block3_pool 11 block4_conv1 12 block4_conv2 13 block4_conv3 14 block4_pool 15 block5_conv1 16 block5_conv2 17 block5_conv3 18 block5_pool Backend TkAgg is interactive backend. Turning interactive mode on.
- reference: 第八期 使用 Keras 训练神经网络 《显卡就是开发板》