use*_*121 8 python machine-learning deep-learning keras pytorch
我想跟着卷积神经网络(CNN)的方式在这里.但是,github中的这段代码使用的是Pytorch,而我使用的是Keras.
我想重现方框6,7和8,其中下载了来自ImageNet上的VGG-16的预训练权重,并用于使CNN更快地收敛.
特别地,存在一部分(框8),其中从VGG-16下载并跳过权重SegNet(CNN模型中没有对应部分).在我的工作中,我使用的是CNN模型U-Net而不是Segnet.U-Net我正在使用的Keras代码可以在这里找到.
我是Keras的新手,我很欣赏Keras代码中有关如何下载和跳过与我的U-Net模型没有对应关系的VGG权重的任何见解.
Fal*_*nUA 12
您正在解决的技术称为"转移学习" - 当将不同数据集上的预训练模型用作模型的一部分作为更好收敛的起点时.它背后的直觉很简单:我们假设在对如此庞大且丰富的数据集进行训练之后ImageNet,模型的卷积核将学习有用的表示.
在您的特定情况下,您希望VGG16在底部堆叠权重,在顶部堆叠解卷积块.我会一步一步地指出你是新手Keras.这个答案按照逐步教程进行组织,并提供小片段供您在自己的代码中使用.
在PyTorch您链接到上面的代码中,首先定义模型,然后才复制权重.我发现这种方法很丰富,因为它包含许多不必要的代码.在这里,我们将VGG16首先加载,然后将其他图层堆叠在顶部.
from keras import applications
from keras.layers import Input
# Loading without top layers, since you only need convolution. 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 shape, e.g. 256x256 with 3 channels:
input_tensor = Input(shape=(256, 256, 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()
Run Code Online (Sandbox Code Playgroud)
如前一段所述,您无需定义模型并复制权重.只需堆叠其他图层vgg_model:
# Import the layers to be used in U-Net
from keras.layers import ...
# From the U-Net code you provided
def make_conv_block(nb_filters, input_tensor, block):
...
# Creating dictionary that maps layer names to the layers
layers = dict([(layer.name, layer) for layer in vgg_model.layers])
# Getting output tensor of the last VGG layer that we want to include.
# I don't know much about U-Net, but according to the code you provided,
# you don't need the last pooling layer, right?
vgg_top = layers['block5_conv3'].output
# Now getting bottom layers for multi-scale skip-layers
block1_conv2 = layers['block1_conv2'].output
block2_conv2 = layers['block2_conv2'].output
block3_conv3 = layers['block3_conv3'].output
block4_conv3 = layers['block4_conv3'].output
# Stacking the remaining layers of U-Net on top of it (modified from
# the U-Net code you provided)
up6 = Concatenate()([UpSampling2D(size=(2, 2))(vgg_top), block4_conv3])
conv6 = make_conv_block(256, up6, 6)
up7 = Concatenate()([UpSampling2D(size=(2, 2))(conv6), block3_conv3])
conv7 = make_conv_block(128, up7, 7)
up8 = Concatenate()([UpSampling2D(size=(2, 2))(conv7), block2_conv2])
conv8 = make_conv_block(64, up8, 8)
up9 = Concatenate()([UpSampling2D(size=(2, 2))(conv8), block1_conv2])
conv9 = make_conv_block(32, up9, 9)
conv10 = Conv2D(nb_labels, (1, 1), name='conv_10_1')(conv9)
x = Reshape((nb_rows * nb_cols, nb_labels))(conv10)
x = Activation('softmax')(x)
outputs = Reshape((nb_rows, nb_cols, nb_labels))(x)
Run Code Online (Sandbox Code Playgroud)
我想强调的是,我们在本段中所做的只是定义计算图U-Net.此代码专门为VGG16您编写,但您可以根据需要对其他体系结构进行修改.
在上一步之后,我们有一个计算图(我假设您使用Tensorflow后端Keras.如果您正在使用Theano,我建议您切换到,Tensorflow因为此框架现已达到成熟状态).现在,我们需要做以下事情:
# Creating new model. Please note that this is NOT a Sequential() model
# as in commonly found tutorials on the internet.
from keras.models import Model
custom_model = Model(inputs=vgg_model.input, outputs=outputs)
# Make sure that the pre-trained bottom layers are not trainable.
# Here, I freeze all the layers of VGG16 (layers 0-18, including the
# pooling ones.
for layer in custom_model.layers[:19]:
layer.trainable = False
# Do not forget to compile it before training
custom_model.compile(loss='your_loss',
optimizer='your_optimizer',
metrics=['your_metrics'])
Run Code Online (Sandbox Code Playgroud)
假设您是新手Keras和深入学习(正如您在问题中所承认的那样),我建议阅读以下文章以进一步了解Keras上的微调和转移学习过程:
当您学习框架时,文档是您最好的朋友.幸运的是,Keras有一个令人难以置信的文档.
我们放在VGG之上的去卷积块来自UNET架构(即up6到conv10)?请确认.
是的,它与此处相同,只是使用跳过连接层的不同名称(例如,block1_conv2而不是conv1)
我们省略了conv层(即conv1到conv5).你能和我分享为什么会这样吗?
我们不会离开或抛出VGG网络中的任何图层.的VGG16网络体系结构和底部结构U-Net(最多conv5)非常相似.实际上,它们由5以下格式的块组成:
+-----------------+-------------------+
| VGG conv blocks | U-Net conv blocks |
+-----------------+-------------------+
| blockX_conv1 | convN |
| ... | poolN |
| blockX_convN | |
| blockX_pool | |
+-----------------+-------------------+
Run Code Online (Sandbox Code Playgroud)
这是一个更好的可视化.因此,VGG16与底部之间的唯一区别U-Net是每个块VGG16包含多个卷积层而不是一个.这就是为什么,连接的替代conv3,以conv6被连接block3_conv3到conv6.该U-Net架构是一样的,只是在底部更卷积层.
反正有没有将最大池合并到转换层中(在您看来,我们在这里做了什么,将它们排除在外,你会说它是无关紧要的吗?)
我们不会把它们排除在外.我扔掉的唯一汇集层是block5_pool(它是底部的最后一层VGG16) - 因为在原始U-Net(参考代码)中,似乎底部的最后一个卷积块后面没有一个池化层(我们有,conv5但没有pool5).我保留了所有层次VGG16.
我们看到在卷积块上使用了Maxpooling.如果我们想将Segnet与VGG结合起来,我们是否也只是简单地删除这些池层(就像我们在这里用Unet做的那样)?
正如我在上面的问题中解释的那样,我们不会丢弃任何池化层.但是,您需要堆叠不同类型的池化层而不是MaxPooling2D默认使用的简单层VGG16,因为SegNet保留了最大索引.这可以通过tf.nn.max_pool_with_argmax使用替换Keras模型的中间层的技巧来实现(我不会覆盖此答案中的详细信息以保持其清洁).替换是无害的,不需要重新训练,因为合并层不包含任何训练过的重量.
从U-NET 这里是我在用的不同,你可以告诉什么是两者之间的这种差异的影响?
这是一个更浅的U-Net.原始问题中的一个底部有5个卷积块(conv1- conv5),而后者只有3个.根据数据选择需要多少个块(例如,对于简单数据,您可能只想使用2-3个单元格)块,而灰质或组织分割可能需要5个块才能获得更好的质量.请参阅此链接以了解卷积内核"看到"的内容.
另外,您如何看待这里的VGGSegnet .它是否使用了您在问答中提到的中间层的技巧?它是否相当于我最初发布的Pytorch代码?
有趣.这是一个不正确的实现,并不等同于您发布的Pytorch代码.我在该存储库中打开了一个问题.
最后的问题....在转移学习中,将预训练模型(即带有预训练重量的模型)置于底部始终是一条规则吗?
一般来说是.将卷积内核视为"特征":第一层检测小边缘和颜色.以下图层将这些边和颜色组合成更复杂的检测,如"黄线"或"蓝色圆圈".然后,上卷积层基于下层的检测将更抽象的形状检测为"眼睛","鼻子"等.因此,替换底层(而上层取决于底部表示)是不合逻辑的.