VGG16内置于Keras,可以通过keras.applications模块中导入。
--------------------------------------------------------将VGG16 卷积实例化:-------------------------------------------------------------------------------------------------------------------------------------
1 from keras.applications importVGG162
3 conv_base = VGG16(weights = ‘imagenet‘,#指定模型初始化的权重检查点4 include_top =False,5 input_shape = (150,150,30))
weights:指定模型初始化的权重检查点、
include_top:指定模型最后是否包含密集连接分类器。默认情况下,这个密集连接分类器对应于ImageNet的100个类别。如果打算使用自己的密集连接分类器,可以不适用它,置为False。
input_shape:是输入到网络中的图像张量的形状。这个参数完全是可选的,如果不传入这个参数,那么网络能够处理任意形状的输入。
--------------------------------------------------------查看VGG详细架构:conv_base.summary()----------------------------------------------------------------------------------------------------------
最后一特征图形状为(4,4,512),我们将在这个特征上添加一个密集连接分类器,有两种方式:
在你的数据集上运行卷积基,将输出保存为numpy数组,然后用这个数据做输入,输入到独立的密集连接分类器中。这种方法速度快,计算代价低,因为对于每个输入图像只需运行一次卷积基,而卷积基是日前流程中计算代价最高的。但这种方法不允许使用数据增强。
在顶部添加Dense层来扩展已有模型,并在输入数据上端到端地运行整个模型。这样你可以使用数据增强,因为每个输入图像进入模型时都会经过卷积基。但这种方法的计算代价比第一种要高很多。
#方法一:不使用数据增强的快速特征提取
importosimportnumpy as npfrom keras.preprocessing.image importImageDataGenerator
base_dir= ‘cats_dogs_images‘train_dir= os.path.join(base_dir,‘train‘)
validation_dir= os.path.join(base_dir,‘validation‘)
test_dir= os.path.join(base_dir,‘test‘)
datagen= ImageDataGenerator(rescale = 1./255)#将所有图像乘以1/255缩放
batch_size = 20
defextract_features(directory,sample_count):
features= np.zeros(shape=(sample_count,4,4,512))
labels= np.zeros(shape=(sample_count))#通过.flow或.flow_from_directory(directory)方法实例化一个针对图像batch的生成器,这些生成器#可以被用作keras模型相关方法的输入,如fit_generator,evaluate_generator和predict_generator
generator =datagen.flow_from_directory(‘cats_dogs_images/train‘,
target_size= (150,150),
batch_size=batch_size,
class_mode= ‘binary‘)
i=0for inputs_batch,labels_batch ingenerator:
features_batch=conv_base.predict(inputs_batch)
features[i* batch_size:(i+1) * batch_size] =features_batch
labels[i* batch_size:(i+1)*batch_size] =labels_batch
i+= 1
if i * batch_size >=sample_count:break
returnfeatures,labels
train_features,train_labels= extract_features(train_dir,2000)
validation_features,validation_labels= extract_features(validataion_dir,1000)
test_features,test_labels= extract_features(test_dir,1000)#要减特征(samples,4,4,512)输入密集连接分类器中,首先必须将其形状展平为(samples,8192)
train_features= np.reshape(train_features,(2000,4*4*512))
validation_features= np.reshape(validation_features,(2000,4*4*512))
test_features= np.reshape(test_features,(2000,4*4*512))#定义并训练密集连接分类器
from keras importmodelsfrom keras importlayersfrom keras importoptimizers
model=models.Sequential()
model.add(layers.Dense(256,activation=‘relu‘,input_dim=4*4*512))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1,activation=‘sigmoid‘))
model.compile(optimizers=optimizers.RMSprop(lr=2e-5),
loss=‘binary_crossentropy‘,
metrics= [‘acc‘])
history=model.fit(train_features,train_labels,
epochs=30,batch_size=20,
validation_data= (Validation_features,validation_labels) )
#在卷积基上添加一个密集连接分类器
from keras importmodelsfrom keras importlayers
model=models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256,activation=‘relu‘))
model.add(layers.Dense(1,activation=‘sigmoid‘))
model.summary()
如上图,VGG16的卷积基有14714688个参数,非常多。在其上添加的分类器有200万个参数。
在编译和训练模型之前,一定要“冻结”卷积基。
冻结? 指一个或多个层在训练过程中保持其权重不变
如果不这么做,那么卷积基之前学到的表示将会在训练过程中被修改。因为其上添加的Dense层是随机初始化的,所以非常大的权重更新将会在网络中传播,对之前学到的表示造成很大破坏。
在keras中,冻结网络的方法是将其trainable属性设置为False
eg. conv_base.trainable = False
#使用冻结的卷积基端到端地训练模型
from keras.preprocessing.image importImageDataGeneratorfrom kera importoptimizers
train_datagen=ImageDataGenerator(
rescale= 1./255,
rotation_range= 40,
width_shift_range= 0.2,
height_shift_range= 0.2,
shear_range= 0.2,
zoom_range= 0.2,
horizontal_flip=True,
fill_mode= ‘nearest‘)
test_datagen= ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_dirctory(
train_dir,
target_size= (150,150),
batch_size= 20,
class_mode= ‘binary‘)
validation_generator=test_datagen.flow_from_dirctory(
validation,
target_size= (150,150),
batch_size= 20,
class_mode= ‘binary‘)
model.compile(optimizer=optimizers.RMSprop(lr=2e-5),
loss=‘binary_crossentropy‘,
metrics= [‘acc‘])
history=model.fit_generator(
train_generator,
steps_per_epoch= 100,
epochs= 30,
validation_data=validation_generator,
validation_steps=50)
--------------------------------------------------------微调模型--------------------------------------------------------------------------------------------------------------------------------------------------------------
另外一种广泛使用的模型复用方法是模型微调,与特征提取互为补充。
对于用于特征提取的冻结的模型基,微调是指将其顶部的几层“解冻”,并将这解冻的几层和新增加的部分联合训练。之所以叫作微调,是因为他只是略微调整了所复用模型中更加抽象的表示,
以便让这些表示与手头的问题更加相关。
冻结VGG16的卷积基是为了能够在上面训练一个随机初始化的分类器。同理,只有上面的分类器训练好了,才能微调卷积基的顶部几层。如果分类器没有训练好,那么训练期间通过网络传播的
误差信号会特别大,微调的几层之前学到的表示都会被破坏。因此,微调网络的步骤如下:
(1)在已经训练好的基网络上添加自定义网络
(2)冻结基网络
(3)训练所添加的部分
(4)解冻基网络的一些层
(5)联合训练解冻的这些层和添加的部分
#微调模型
model.compile(loss=‘binary_crossentropy‘,
optimizer= optimizers.RMSprop(lr=1e-5),
metrics= [‘acc‘])
history=model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs= 100,
validation_data=validation_generator,
validation_steps= 50)
test_generator=test_datagen.flow_from_directory(
test_dir,
target_size= (150,150),
batch_size= 20,
class_mode= ‘binary‘)
test_loss,test_acc= model.evaluate_generator(test_generator,steps=50)
为什么不微调更多层?为什么不微调整个卷积基?当然可以这么做,但需要先考虑以下几点:
(1)卷积基中更靠底部的层编码的是更加通用的可复用特征,而更靠顶部的层编码的是更专业化的特征。微调这些更专业化的特征更加有用,因为它们需要在你的新问题上改变用途。
微调更靠底部的层,得到的汇报会更少
(2)训练的参数越多,过拟合的风险越大。卷积基有1500万个参数,所以在你的小型数据集上训练这么多参数是有风险的。
原文:https://www.cnblogs.com/nxf-rabbit75/p/9960277.html