我需要为Keras VGG16准备预训练权重吗?

9
作为背景,我对机器学习的世界相对较新,并尝试进行一个项目,目标是对NBA比赛中的戏剧进行分类。我的输入是每个游戏中的每个戏剧的40帧序列,我的标签是给定戏剧的11个全面分类。
计划是将每个帧序列传入CNN中提取一组特征。然后将给定视频的每个特征序列传递到RNN中。
我目前大多数实现都是使用Keras完成的,并选择使用VGG16模型进行CNN。以下是一些相关代码:
video = keras.Input(shape = (None, 255, 255, 3), name = 'video')
cnn = keras.applications.VGG16(include_top=False, weights = None, input_shape=
(255,255,3), pooling = 'avg', classes=11)
cnn.trainable = True

我的问题是 - 如果我的目标是对 NBA 比赛视频剪辑进行分类,那么是否仍然有必要将 VGG16 ConvNet 的权重初始化为 'imagenet'?如果是,为什么?如果不是,我该如何训练 VGG16 ConvNet 来获得自己的一组权重,然后如何将它们插入到此函数中?我很难找到任何教程,在使用 VGG16 模型时,有人包含了他们自己的一组权重。如果我的问题有些幼稚,请原谅,但我真的很感激任何帮助来澄清这个问题。

考虑访问Data Science SECross Validated,针对机器学习的问题进行专门咨询。 - E net4
1个回答

15

你是否应该针对特定任务重新训练VGG16?绝对不需要!重新训练如此庞大的网络很难,并且需要在训练深度网络方面具有很多直觉和知识。让我们分析一下为什么可以使用在ImageNet上预训练的权重来完成您的任务:

  • ImageNet是一个包含数百万张图像的巨大数据集。 VGG16本身在强大的GPU上进行了3-4天的训练。在CPU上(假设您没有像NVIDIA GeForce Titan X那样强大的GPU),这将需要几周时间。

  • ImageNet包含来自真实世界场景的图像。 NBA比赛也可以被视为真实世界场景。因此,预先在ImageNet上训练的特征很可能也可以用于NBA比赛。

实际上,您不需要使用预先训练的VGG16的所有卷积层。让我们看一下可视化内部VGG16层并查看它们检测到了什么(取自此文章;图像太大,所以我只放了一个链接以保持紧凑):

  • 第一和第二个卷积块查看低级特征,例如角,边缘等。
  • 第三和第四个卷积块查看表面特征,曲线,圆形等。
  • 第五层查看高级特征

那么,您可以决定哪种特征对于您的具体任务是有益的。您是否需要第5个块的高级特性?或者您可能想要使用第3个块的中级特性?也许您想在VGG的底层加入另一个神经网络?如需更多说明,请参阅我撰写的以下教程;它曾经在SO文档中。


使用VGG和Keras进行迁移学习和微调

本例子提供了三个简要而全面的子例:

  • Keras库中可用的预训练模型中加载权重
  • 在VGG的任意层之上叠加另一个网络进行训练
  • 在其他层的中间插入一层
  • 关于使用VGG进行微调和迁移学习的提示和经验法则

加载预训练权重

Keras提供了在ImageNet数据集上预训练的模型,包括VGG-16VGG-19。在本例中,将使用VGG-16。欲了解更多信息,请访问Keras应用程序文档

from keras import applications

# This will load the whole VGG16 network, including the top Dense layers.
# Note: by specifying the shape of top layers, input tensor shape is forced
# to be (224, 224, 3), therefore you can use it only on 224x224 images.
vgg_model = applications.VGG16(weights='imagenet', include_top=True)

# If you are only interested in convolution filters. Note that by not
# specifying the shape of top layers, the input tensor shape is (None, None, 3),
# so you can use them for any size of images.
vgg_model = applications.VGG16(weights='imagenet', include_top=False)

# If you want to specify input tensor
from keras.layers import Input
input_tensor = Input(shape=(160, 160, 3))
vgg_model = applications.VGG16(weights='imagenet',
                               include_top=False,
                               input_tensor=input_tensor)

# To see the models' architecture and layer names, run the following
vgg_model.summary()

使用来自VGG的底层创建新网络

假设您要针对大小为(160, 160, 3)的图像执行某些特定任务,您希望使用预训练的VGG底层,直到名称为block2_pool的层。

vgg_model = applications.VGG16(weights='imagenet',
                               include_top=False,
                               input_shape=(160, 160, 3))

# Creating dictionary that maps layer names to the layers
layer_dict = dict([(layer.name, layer) for layer in vgg_model.layers])

# Getting output tensor of the last VGG layer that we want to include
x = layer_dict['block2_pool'].output

# Stacking a new simple convolutional network on top of it    
x = Conv2D(filters=64, kernel_size=(3, 3), activation='relu')(x)
x = MaxPooling2D(pool_size=(2, 2))(x)
x = Flatten()(x)
x = Dense(256, activation='relu')(x)
x = Dropout(0.5)(x)
x = Dense(10, activation='softmax')(x)

# Creating new model. Please note that this is NOT a Sequential() model.
from keras.models import Model
custom_model = Model(input=vgg_model.input, output=x)

# Make sure that the pre-trained bottom layers are not trainable
for layer in custom_model.layers[:7]:
    layer.trainable = False

# Do not forget to compile it
custom_model.compile(loss='categorical_crossentropy',
                     optimizer='rmsprop',
                     metrics=['accuracy'])

删除多个层并在中间插入一个新层

假设您需要通过用单个卷积层替换block1_conv1block2_conv2来加速VGG16,并保存预训练权重。 思路是将整个网络分解为单独的层,然后重新组合。以下是针对您任务的特定代码:

vgg_model = applications.VGG16(include_top=True, weights='imagenet')

# Disassemble layers
layers = [l for l in vgg_model.layers]

# Defining new convolutional layer.
# Important: the number of filters should be the same!
# Note: the receiptive field of two 3x3 convolutions is 5x5.
new_conv = Conv2D(filters=64, 
                  kernel_size=(5, 5),
                  name='new_conv',
                  padding='same')(layers[0].output)

# Now stack everything back
# Note: If you are going to fine tune the model, do not forget to
#       mark other layers as un-trainable
x = new_conv
for i in range(3, len(layers)):
    layers[i].trainable = False
    x = layers[i](x)

# Final touch
result_model = Model(input=layer[0].input, output=x)

最后一行:Model(input=layers[0].input, output=x) - Naomi Fridman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接