1

J'essaie de réapprendre (lire finetune) un classificateur d'image MobileNet.Tensorflow: Différentes valeurs d'activation pour la même image

Le script de recyclage donné par le flux tensoriel here (à partir du tutorial), met à jour uniquement les poids de la couche entièrement connectée nouvellement ajoutée. J'ai modifié ce script pour mettre à jour les poids de toutes les couches du modèle pré-entraîné. J'utilise l'architecture MobileNet avec un multiplicateur de profondeur de 0.25 et une taille de 128.

Cependant, pendant le recyclage j'ai observé une chose étrange, si je donne une image particulière comme entrée pour l'inférence dans un lot avec d'autres images, l'activation les valeurs après que certaines couches sont différentes de celles lorsque l'image est passée seule. Les valeurs d'activation d'une même image provenant de lots différents sont également différentes. Exemple - Pour deux lots - batch_1 : [img1, img2, img3]; batch_2 : [img1, img4, img5]. Les activations pour img1 sont différentes des deux lots.

Voici le code que j'utilise pour l'inférence -

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}) 

Le code ci-dessus est exécuté une fois qu'il est et une fois avec le changement suivant dans la dernière ligne:

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

Voici quelques-unes nœuds du graphique:

[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', ... ...] 

maintenant, quand layerXname = 'MobilenetV1/MobilenetV1/Conv2d_0/convolution' Les activations sont les mêmes dans les deux cas spécifiés ci-dessus. (c'est-à-dire layerxactivations et layerxactivations_batch [0] sont identiques). Mais après cette couche, toutes les couches ont des valeurs d'activation différentes. Je pense que les opérations batchNorm après la couche 'MobilenetV1/MobilenetV1/Conv2d_0/convolution' se comportent différemment pour les entrées batch et une seule image. Ou est le problème causé par quelque chose d'autre?

Toute aide/pointeur serait appréciée.

Répondre

0

Lorsque vous créez le mobilenet, il existe un paramètre appelé is_training. Si vous ne le définissez pas sur false, la couche de suppression et la couche de normalisation par lots vous donneront des résultats différents dans différentes itérations. La normalisation par lots ne changera probablement que très peu les valeurs, mais l'abandon les modifiera beaucoup car il supprime certaines valeurs d'entrée.

Jetez un oeil à la signature de 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

Merci @jorgemf! Comme je m'en doutais dans ma question, le problème était avec batchNorm et le réglage de 'is_training' à' False' fonctionne. Mais ce n'est pas la bonne façon. Idéalement, le graphique devrait être chargé avec 'is_training' comme' True' pendant l'entraînement, puis 'is_training' comme False pendant l'inférence. Mais puisque ici je n'ai pas écrit le batchnorm moi-même et plutôt le graphique est chargé à partir du code MobileNet; Je suis encore à comprendre comment faire ce qui précède.Vous pouvez vous référer ici - https://stackoverflow.com/questions/39353503/tensorflow-tf-slim-model-with-is-training-true-and-false ou https://ruishu.io/2016/12/27/batchnorm/ – Krist

+0

@Krist ne pas oublier de marquer la réponse comme valide si elle vous a aidé. – jorgemf

-1

Ceci est dû au lot Normalization.

Comment utilisez-vous l'inférence. Est-ce que vous le chargez à partir des fichiers de point de contrôle ou utilisez-vous un modèle Frozen Protobuf. Si vous utilisez un modèle figé, vous pouvez vous attendre à des résultats similaires pour différents formats d'entrées.

Vérifiez this sur. Un problème similaire pour une application différente est soulevé ici.

+0

Je ne pense pas qu'il soit gelé le graphique ou que le problème que vous avez lié est dû à un graphique gelé. – jorgemf

+0

J'ai dit que c'était dû à la normalisation des lots. Lorsque vous figez le graphique, l'opération Moving Mean/Average est modifiée et donne des résultats prévisibles. –

+1

Maintenant, je le vois, il pourrait être soit batch_norm ou la couche de décrochage. Les deux prennent le paramètre is_training – jorgemf