1

我试图重新训练(读取微调)MobileNet图像分类器。Tensorflow:同一图像的不同激活值

由张量流here(来自tutorial)给出的再训练脚本仅更新新添加的完全连接图层的权重。我修改了这个脚本来更新预训练模型的所有图层的权重。我正在使用MobileNet架构,深度倍数为0.25,输入尺寸为128.

但是,在重新训练时,我观察到一个奇怪的现象,如果我将某个特定图像作为批量推理的输入与其他图像进行比较,一些图层后的值与图像单独传递时的值不同。同样来自不同批次的相同图像的激活值也是不同的。示例 - 对于两批 - batch_1 : [img1, img2, img3]; batch_2 : [img1, img4, img5]。 img1的激活与两个批次都不同。

这里是我使用的推理码 -

for tf.Session(graph=tf.get_default_graph()) as sess: 
    image_path = '/tmp/images/10dsf00003.jpg' 
    id_ = gfile.FastGFile(image_path, 'rb').read() 

    #The line below loads the jpeg using tf.decode_jpeg and does some preprocessing 
    id = sess.run(decoded_image_tensor, {jpeg_data_tensor: id_}) 

    input_image_tensor = graph.get_tensor_by_name('input') 

    layerXname='MobilenetV1/MobilenetV1/Conv2d_1_depthwise/Relu:0' #Name of the layer whose activations to inspect. 
    layerX = graph.get_tensor_by_name(layerXname) 
    layerXactivations=sess.run(layerX, {input_image_tensor: id}) 

上面的代码与在最后一行以下变化一次,因为它是,一旦执行:

layerXactivations_batch=sess.run(layerX, {input_image_tensor: np.asarray([np.squeeze(id), np.squeeze(id), np.squeeze(id)])}) 

以下是一些图中的节点:

[u'input', u'MobilenetV1/Conv2d_0/weights', u'MobilenetV1/Conv2d_0/weights/read', u'MobilenetV1/MobilenetV1/Conv2d_0/convolution', u'MobilenetV1/Conv2d_0/BatchNorm/beta', u'MobilenetV1/Conv2d_0/BatchNorm/beta/read', u'MobilenetV1/Conv2d_0/BatchNorm/gamma', u'MobilenetV1/Conv2d_0/BatchNorm/gamma/read', u'MobilenetV1/Conv2d_0/BatchNorm/moving_mean', u'MobilenetV1/Conv2d_0/BatchNorm/moving_mean/read', u'MobilenetV1/Conv2d_0/BatchNorm/moving_variance', u'MobilenetV1/Conv2d_0/BatchNorm/moving_variance/read', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/add/y', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/add', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/Rsqrt', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/mul', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/mul_1', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/mul_2', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/sub', u'MobilenetV1/MobilenetV1/Conv2d_0/BatchNorm/batchnorm/add_1', u'MobilenetV1/MobilenetV1/Conv2d_0/Relu6', u'MobilenetV1/Conv2d_1_depthwise/depthwise_weights', u'MobilenetV1/Conv2d_1_depthwise/depthwise_weights/read', ... ...] 

现在,当layerXname = 'MobilenetV1/MobilenetV1/Conv2d_0/convolution' 上述两种激活方式都是相同的。 (即 layerxactivations和layerxactivations_batch [0]相同)。 但是在此图层之后,所有图层都具有不同的激活值。我觉得'MobilenetV1/MobilenetV1/Conv2d_0/convolution'层对于批量输入和单个图像的batchNorm操作有所不同。还是由其他问题引起的问题?

任何帮助/指针,将不胜感激。

回答

0

当您构建mobilenet时,有一个参数叫做is_training。如果不将其设置为false,则在不同的迭代中,失落层和批处理规范化层将为您提供不同的结果。批量归一化可能会改变很小的值,但是由于丢弃了一些输入值,丢失将会改变它们很多。

看看到mobilnet的签名:

def mobilenet_v1(inputs, 
       num_classes=1000, 
       dropout_keep_prob=0.999, 
       is_training=True, 
       min_depth=8, 
       depth_multiplier=1.0, 
       conv_defs=None, 
       prediction_fn=tf.contrib.layers.softmax, 
       spatial_squeeze=True, 
       reuse=None, 
       scope='MobilenetV1'): 
    """Mobilenet v1 model for classification. 

    Args: 
    inputs: a tensor of shape [batch_size, height, width, channels]. 
    num_classes: number of predicted classes. 
    dropout_keep_prob: the percentage of activation values that are retained. 
    is_training: whether is training or not. 
    min_depth: Minimum depth value (number of channels) for all convolution ops. 
     Enforced when depth_multiplier < 1, and not an active constraint when 
     depth_multiplier >= 1. 
    depth_multiplier: Float multiplier for the depth (number of channels) 
     for all convolution ops. The value must be greater than zero. Typical 
     usage will be to set this value in (0, 1) to reduce the number of 
     parameters or computation cost of the model. 
    conv_defs: A list of ConvDef namedtuples specifying the net architecture. 
    prediction_fn: a function to get predictions out of logits. 
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is 
     of shape [B, 1, 1, C], where B is batch_size and C is number of classes. 
    reuse: whether or not the network and its variables should be reused. To be 
     able to reuse 'scope' must be given. 
    scope: Optional variable_scope. 

    Returns: 
    logits: the pre-softmax activations, a tensor of size 
     [batch_size, num_classes] 
    end_points: a dictionary from components of the network to the corresponding 
     activation. 

    Raises: 
    ValueError: Input rank is invalid. 
    """ 
+0

谢谢@jorgemf!正如我在我的问题中怀疑的问题是使用batchNorm并将'is_training'设置为'False'工作。但这不是正确的方法。理想情况下,应该在训练时将'is_training'加载为'True',然后在推断时将'is_training'加载为False。但是因为我自己并没有自己写蝙蝠科,而是从MobileNet代码中加载图形;我还没有弄清楚如何做到上述。你可以参考这里 - https://stackoverflow.com/questions/39353503/tensorflow-tf-slim-model-with-is-training-true-and-false或https://ruishu.io/2016/12/27/batchnorm/ – Krist

+0

@Krist不要忘了标记答案是有效的,如果它帮助你。 – jorgemf

-1

这是由于批标准化。

你是如何运行推断。您是从检查点文件加载它还是使用Frozen Protobuf模型?如果您使用冻结模型,您可以预期不同输入格式的结果类似。

检查this出。这里提出了针对不同应用的类似问题。

+0

我不认为他会冻结图表,或者您链接的问题是由于冻结图表造成的。 – jorgemf

+0

我说这是由于批量标准化。当您冻结图表时,运行平均值/平均值的操作会发生变化,并会给出可预测的结果。 –

+1

现在我看到它可能是batch_norm或者dropout图层。两者都采用is_training参数 – jorgemf