赞
踩
参考链接:https://www.cnblogs.com/hutao722/p/10008581.html
全局平均池化(GAP)通过池化操作把多维矩阵转化为特征向量,以顶替全连接(FC)。
优点:
① 减少了FC中的大量参数,使得模型更加健壮,抗过拟合,当然,可能也会欠拟合。
② GAP在特征图与最终的分类间转换更加自然。
GAP工作原理如下图所示:
假设卷积层的最后输出是h × w × d 的三维特征图,具体大小为6 × 6 × 3,经过GAP转换后,变成了大小为 1 × 1 × 3 的输出值,也就是每一层 h × w 会被平均化成一个值。
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x) #卷积层最后一层
x = layers.GlobalAveragePooling2D()(x) #GAP层
prediction = Dense(10, activation='softmax')(x) #输出层
再看看GAP的代码具体实现:
@tf_export('keras.layers.GlobalAveragePooling2D', 'keras.layers.GlobalAvgPool2D') class GlobalAveragePooling2D(GlobalPooling2D): """Global average pooling operation for spatial data. Arguments: data_format: A string, one of `channels_last` (default) or `channels_first`. The ordering of the dimensions in the inputs. `channels_last` corresponds to inputs with shape `(batch, height, width, channels)` while `channels_first` corresponds to inputs with shape `(batch, channels, height, width)`. It defaults to the `image_data_format` value found in your Keras config file at `~/.keras/keras.json`. If you never set it, then it will be "channels_last". Input shape: - If `data_format='channels_last'`: 4D tensor with shape: `(batch_size, rows, cols, channels)` - If `data_format='channels_first'`: 4D tensor with shape: `(batch_size, channels, rows, cols)` Output shape: 2D tensor with shape: `(batch_size, channels)` """ def call(self, inputs): if self.data_format == 'channels_last': return backend.mean(inputs, axis=[1, 2]) else: return backend.mean(inputs, axis=[2, 3])
实现很简单,对宽度和高度两个维度的特征数据进行平均化求值。如果是NHWC结构(数量、宽度、高度、通道数),则axis=[1, 2];反之如果是CNHW,则axis=[2, 3]。
在验证GAP技术可行性前,我们需要准备训练和测试数据集。我在牛津大学网站上找到了17种不同花类的数据集,地址为:http://www.robots.ox.ac.uk/~vgg/data/flowers/17/index.html 。该数据集每种花有80张图片,共计1360张图片,我对花进行了分类处理,抽取了部分数据作为测试数据,这样最终训练和测试数据的数量比为7:1。
我将数据集上传到我的百度网盘: https://pan.baidu.com/s/1YDA_VOBlJSQEijcCoGC60w ,大家可以下载使用。
在Keras经典模型中,若支持迁移学习,不但有GAP,还有GMP,而默认是自己组建FC层,一个典型的实现为:
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(classes, activation='softmax', name='predictions')(x)
else:
if pooling == 'avg':
x = layers.GlobalAveragePooling2D()(x)
elif pooling == 'max':
x = layers.GlobalMaxPooling2D()(x)
本文将在同一数据集条件下,比较GAP、GMP和FC层的优劣,选取测试模型为VGG19和InceptionV3两种模型的迁移学习版本。
先看看在VGG19模型下,GAP、GMP和FC层在各自迭代50次后,验证准确度和损失度的比对。代码如下:
import keras from keras.preprocessing.image import ImageDataGenerator from keras.models import Model from keras.applications.vgg19 import VGG19from keras.layers import Dense, Flatten from matplotlib import pyplot as plt import numpy as np # 为保证公平起见,使用相同的随机种子 np.random.seed(7) batch_size = 32 # 迭代50次 epochs = 50 # 依照模型规定,图片大小被设定为224 IMAGE_SIZE = 224 # 17种花的分类 NUM_CLASSES = 17 TRAIN_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/train' TEST_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/test' FLOWER_CLASSES = ['Bluebell', 'ButterCup', 'ColtsFoot', 'Cowslip', 'Crocus', 'Daffodil', 'Daisy', 'Dandelion', 'Fritillary', 'Iris', 'LilyValley', 'Pansy', 'Snowdrop', 'Sunflower', 'Tigerlily', 'tulip', 'WindFlower'] def model(mode='fc'): if mode == 'fc': # FC层设定为含有512个参数的隐藏层 base_model = VGG19(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, pooling='none') x = base_model.output x = Flatten()(x) x = Dense(512, activation='relu')(x) prediction = Dense(NUM_CLASSES, activation='softmax')(x) elif mode == 'avg': # GAP层通过指定pooling='avg'来设定 base_model = VGG19(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, pooling='avg') x = base_model.output prediction = Dense(NUM_CLASSES, activation='softmax')(x) else: # GMP层通过指定pooling='max'来设定 base_model = VGG19(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, pooling='max') x = base_model.output prediction = Dense(NUM_CLASSES, activation='softmax')(x) model = Model(input=base_model.input, output=prediction) model.summary() opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 使用数据增强 train_datagen = ImageDataGenerator() train_generator = train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=FLOWER_CLASSES) test_datagen = ImageDataGenerator() test_generator = test_datagen.flow_from_directory(directory=TEST_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=FLOWER_CLASSES) # 运行模型 history = model.fit_generator(train_generator, epochs=epochs, validation_data=test_generator) return history fc_history = model('fc') avg_history = model('avg') max_history = model('max') # 比较多种模型的精确度 plt.plot(fc_history.history['val_acc']) plt.plot(avg_history.history['val_acc']) plt.plot(max_history.history['val_acc']) plt.title('Model accuracy') plt.ylabel('Validation Accuracy') plt.xlabel('Epoch') plt.legend(['FC', 'AVG', 'MAX'], loc='lower right') plt.grid(True) plt.show() # 比较多种模型的损失率 plt.plot(fc_history.history['val_loss']) plt.plot(avg_history.history['val_loss']) plt.plot(max_history.history['val_loss']) plt.title('Model loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(['FC', 'AVG', 'MAX'], loc='upper right') plt.grid(True) plt.show()
各自运行50次迭代后,我们看看准确度比较:
再看看模型的损失变化:
可以看到,GMP(MAX)完全GG。
FC在1到40轮表现和GAP无太大差异,后期出现过拟合现象。唯一优势是前期学习速度快(考虑跟全连接的结构密切相关,更复杂,学的快),
GAP并没有出现过拟合的现象,但是准确度只接近70%,可能是model的原因。
我们再转向另一个模型InceptionV3,代码稍加改动如下:
下面展示一些 。
import keras from keras.preprocessing.image import ImageDataGenerator from keras.models import Model from keras.applications.inception_v3 import InceptionV3, preprocess_input from keras.layers import Dense, Flatten from matplotlib import pyplot as plt import numpy as np # 为保证公平起见,使用相同的随机种子 np.random.seed(7) batch_size = 32 # 迭代50次 epochs = 50 # 依照模型规定,图片大小被设定为224 IMAGE_SIZE = 224 # 17种花的分类 NUM_CLASSES = 17 TRAIN_PATH = '/home/hutao/Documents/tensorflow/images/17flowerclasses/train' TEST_PATH = '/home/hutao/Documents/tensorflow/images/17flowerclasses/test' FLOWER_CLASSES = ['Bluebell', 'ButterCup', 'ColtsFoot', 'Cowslip', 'Crocus', 'Daffodil', 'Daisy', 'Dandelion', 'Fritillary', 'Iris', 'LilyValley', 'Pansy', 'Snowdrop', 'Sunflower', 'Tigerlily', 'tulip', 'WindFlower'] def model(mode='fc'): if mode == 'fc': # FC层设定为含有512个参数的隐藏层 base_model = InceptionV3(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, pooling='none') x = base_model.output x = Flatten()(x) x = Dense(512, activation='relu')(x) prediction = Dense(NUM_CLASSES, activation='softmax')(x) elif mode == 'avg': # GAP层通过指定pooling='avg'来设定 base_model = InceptionV3(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, pooling='avg') x = base_model.output prediction = Dense(NUM_CLASSES, activation='softmax')(x) else: # GMP层通过指定pooling='max'来设定 base_model = InceptionV3(input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3), include_top=False, pooling='max') x = base_model.output prediction = Dense(NUM_CLASSES, activation='softmax')(x) model = Model(input=base_model.input, output=prediction) model.summary() opt = keras.optimizers.rmsprop(lr=0.0001, decay=1e-6) model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy']) # 使用数据增强 train_datagen = ImageDataGenerator() train_generator = train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=FLOWER_CLASSES) test_datagen = ImageDataGenerator() test_generator = test_datagen.flow_from_directory(directory=TEST_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=FLOWER_CLASSES) # 运行模型 history = model.fit_generator(train_generator, epochs=epochs, validation_data=test_generator) return history fc_history = model('fc') avg_history = model('avg') max_history = model('max') # 比较多种模型的精确度 plt.plot(fc_history.history['val_acc']) plt.plot(avg_history.history['val_acc']) plt.plot(max_history.history['val_acc']) plt.title('Model accuracy') plt.ylabel('Validation Accuracy') plt.xlabel('Epoch') plt.legend(['FC', 'AVG', 'MAX'], loc='lower right') plt.grid(True) plt.show() # 比较多种模型的损失率 plt.plot(fc_history.history['val_loss']) plt.plot(avg_history.history['val_loss']) plt.plot(max_history.history['val_loss']) plt.title('Model loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(['FC', 'AVG', 'MAX'], loc='upper right') plt.grid(True) plt.show()
先进行准确率的比较:
再看看损失的变化过程:
很明显,在InceptionV3模型下,FC、GAP和GMP都表现很好,但可以看出GAP的表现依旧最好,其准确度普遍在90%以上,而另两种的准确度在80~90%之间。
从以上结果来看,GAP是优于FC的,但也不能证明在所有的网络上都能够使用,比如在结构和深度都比较小的网络上,GAP代替FC作者猜想可能会导致欠拟合的现象,这需要更多的验证和尝试对比。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。