加载VGG16前13层结构和权重,自己定义最后全连接层,然后冻结前13层,使用小数据集训练模型。
看似简单,中间遇到很多问题,说多了都是泪,就是因为纠结于网上给的例子,太死脑筋了。
csdn里面有一个帖子讲的很详细,我跑里面的例子一直报错:
https://blog.csdn.net/sinat_26917383/article/details/72861152#commentsedit
自定义全连接层:
base_model = VGG16(weights='imagenet', include_top=False)
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(2, activation='sigmoid'))
model = Model(inputs=base_model.input, outputs=top_model.output)
无论怎么改都报错,调用Model()的时候总是报错:
ValueError: Graph disconnected: cannot obtain value for tensor Tensor("flatten_1_input:0", shape=(?, 512, 7, 7), dtype=float32) at layer "flatten_1_input". The followingprevious layers were accessed without issue: []
修改如下:
(1)
base_model = VGG16(weights='imagenet', include_top=False,input_shape=(3, 224, 224))
x = base_model.output
x= Flatten()(x)
#x = GlobalAveragePooling2D()(x)
# let's add a fully-connected layer
x = Dense(4096, actication='relu',name= 'fc1')(x)
x = Dense(4096,activation='relu',name='fc2')(x)
x = Dense(2,actication='sigmoid')(x)
model = Model(inputs=base_model.input, outputs=predictions)
print(model.summary())
注意使用flatten的时候,需要指定输入图片大小,input_shape(3,224,224),否则会报错:
ValueError: The shape of the input to "Flatten" is not fully defined (got (512, None, None). Make sure to pass a complete "input_shape" or "batch_input_shape" argument to the first layer in your model.
打印的网络结构:
block5_pool (MaxPooling2D) (None, 512, 7, 7) 0
_________________________________________________________________
flatten (Flatten) (None, 25088) 0
_________________________________________________________________
fc1 (Dense) (None, 4096) 102764544
_________________________________________________________________
fc2 (Dense) (None, 4096) 16781312
_________________________________________________________________
dense_1 (Dense) (None, 2) 8194
(2)使用GlobalAveragePooling2D,代替Flatten层
base_model = VGG16(weights='imagenet', include_top=False)
x = base_model.output
#x= Flatten()(x)
x = GlobalAveragePooling2D()(x)
# let's add a fully-connected layer
x = Dense(1024, activation='relu')(x)
predictions = Dense(2, activation='sigmoid')(x)
model = Model(inputs=base_model.input, outputs=predictions)
个人理解这里GlobalAveragePooling2D的作用其实相当于flatten层,都是把多维矩阵压平,并且不用指定input_shape()的大小,打印模型的结果如下:
_________________________________________________________________
block5_pool (MaxPooling2D) (None, 512, 7, 7) 0
_________________________________________________________________
global_average_pooling2d_1 ( (None, 512) 0
_________________________________________________________________
fc1 (Dense) (None, 4096) 2101248
_________________________________________________________________
fc2 (Dense) (None, 4096) 16781312
_________________________________________________________________
dense_1 (Dense) (None, 2) 8194
(3)第三种写法最简单粗暴,但是不好理解
base_model = VGG16(weights = 'imagenet', include_top = False, pooling = 'avg')
predictions = Dense(2, activation='sigmoid')(base_model.output)
# 定义整个模型
model = Model(inputs=base_model.input, outputs=predictions)
打印模型结构:
block5_pool (MaxPooling2D) (None, 512, 7, 7) 0
_________________________________________________________________
global_average_pooling2d_1 ( (None, 512) 0
_________________________________________________________________
dense_1 (Dense) (None, 2) 1026
if include_top:
# Classification block
x = layers.Flatten(name='flatten')(x)
x = layers.Dense(4096, activation='relu', name='fc1')(x)
x = layers.Dense(4096, activation='relu', name='fc2')(x)
x = layers.Dense(2, activation='softmax', name='predictions')(x)
else:
if pooling == 'avg':
x = layers.GlobalAveragePooling2D()(x)
elif pooling == 'max':
x = layers.GlobalMaxPooling2D()(x)
’‘’看官方代码,这里添加参数pooling='avg',已经自动的使用GlobalAveragePooling2D,所以不需要压缩层,这里卡了很久,一度以为真的不需要平滑层
base_model = VGG16(weights = 'imagenet', include_top = False, pooling = 'avg')
# 构建网络的最后一层
predictions = Dense(2, activation='sigmoid')(base_model.output)
# 定义整个模型
model = Model(inputs=base_model.input, outputs=predictions)
三种改法殊途同归,折腾了将近一天,有任何问题欢迎交流讨论。
给出完整的代码:
from keras import applications
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.models import Model
from keras.layers import Flatten, Dense,GlobalAveragePooling2D,Convolution2D,MaxPooling2D,ZeroPadding2D
import os
import h5py
from keras.applications.vgg16 import VGG16
from keras.models import load_model
from keras import backend as K
from keras.utils import to_categorical
K.set_image_dim_ordering('th')
img_width, img_height = 224, 224
train_data_dir = 'train1'
validation_data_dir = 'validation'
nb_train_samples = 2000
nb_validation_samples = 800
epochs = 10
batch_size = 16
nb_classes = 2
#model = VGG16(weights='imagenet', include_top=False)
base_model = VGG16(weights='imagenet', include_top=False,input_shape=(3,224, 224))
x = base_model.output
x= Flatten(name='flatten')(x)
#x = GlobalAveragePooling2D()(x)
# let's add a fully-connected layer
x = Dense(4096, activation='relu',name='fc1')(x)
x = Dense(4096, activation='relu',name='fc2')(x)
x = Dense(nb_classes, activation='sigmoid')(x)
# add the model on top of the convolutional base
model = Model(inputs=base_model.inputs, outputs=x)
print(model.summary())
for layer in base_model.layers:
layer.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='categorical')
validation_generator = test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_height, img_width),
batch_size=batch_size,
class_mode='categorical')
image_numbers = train_generator.samples
# fine-tune the model
model.fit_generator(
train_generator,
steps_per_epoch = image_numbers,
epochs=epochs,
validation_data=validation_generator,
validation_steps = batch_size
)
model.save('weights1.h5')