web-dev-qa-db-fra.com

Calcul de distance par paire avec TensorFlow

J'essaie d'impulser cet article: http://ronan.collobert.com/pub/matos/2008_deep_icml.pdf Spécifiquement l'équation (3) de la section 2.

Je veux brièvement faire un calcul de distance par paire pour les fonctionnalités de chaque mini-lot et insérer cette perte dans la perte générale du réseau. Je n'ai que le Tesnor du lot (16 échantillons), le tenseur des étiquettes du lot et la fonction batch Tensor.

Après avoir cherché pendant un bon moment, je n'arrivais toujours pas à comprendre ce qui suit:

1) Comment diviser le lot pour les paires positives (c'est-à-dire la même étiquette) et négatives. Étant donné que le tenseur n'est pas itératif, je ne peux pas comprendre comment obtenir quel échantillon a quelle étiquette, puis diviser mon vecteur, ou obtenir quels indices du tenseur appartiennent à chaque classe.

2) Comment puis-je calculer la distance par paire pour certains des indices du tenseur de lot?

3) Je dois également définir une nouvelle fonction de distance pour les exemples négatifs

Dans l'ensemble, j'ai besoin d'obtenir quels indices appartiennent à quelle classe, faire un calcul de distace par paire positif pour toutes les paires positives. Et faites un autre calcul pour toutes les paires négatives. Ensuite, résumez le tout et ajoutez-le à la perte de réseau.

Toute aide (à l'un ou plusieurs des 3 problèmes) serait très appréciée.

14
mangate

1) Vous devriez faire l'échantillonnage par paire avant alimenter les données dans une session. Marquez chaque paire une étiquette booléenne, disons y = 1 pour la paire appariée, 0 sinon.

2) 3) Il suffit de calculer les deux termes pos/neg pour chaque paire, et de laisser l'étiquette 0-1 y pour choisir laquelle ajouter à la perte.


Créez d'abord des espaces réservés, y_ est pour les étiquettes booléennes.

dim = 64
x1_ = tf.placeholder('float32', shape=(None, dim))
x2_ = tf.placeholder('float32', shape=(None, dim))
y_ = tf.placeholder('uint8', shape=[None])   # uint8 for boolean

Ensuite, le tenseur de perte peut être créé par la fonction.

def loss(x1, x2, y):
    # Euclidean distance between x1,x2
    l2diff = tf.sqrt( tf.reduce_sum(tf.square(tf.sub(x1, x2)),
                                    reduction_indices=1))

    # you can try margin parameters
    margin = tf.constant(1.)     

    labels = tf.to_float(y)

    match_loss = tf.square(l2diff, 'match_term')
    mismatch_loss = tf.maximum(0., tf.sub(margin, tf.square(l2diff)), 'mismatch_term')

    # if label is 1, only match_loss will count, otherwise mismatch_loss
    loss = tf.add(tf.mul(labels, match_loss), \
                  tf.mul((1 - labels), mismatch_loss), 'loss_add')

    loss_mean = tf.reduce_mean(loss)
    return loss_mean

loss_ = loss(x1_, x2_, y_)

Ensuite, alimentez vos données (générées aléatoirement par exemple):

batchsize = 4
x1 = np.random.Rand(batchsize, dim)
x2 = np.random.Rand(batchsize, dim)
y = np.array([0,1,1,0])

l = sess.run(loss_, feed_dict={x1_:x1, x2_:x2, y_:y})
14
weitang114

Réponse courte

Je pense que la façon la plus simple de le faire est d'échantillonner les paires hors ligne (c'est-à-dire en dehors du graphique TensorFlow).
Vous créez tf.placeholder Pour un lot de paires avec leurs étiquettes (positives ou négatives, c'est-à-dire la même classe ou une classe différente), puis vous pouvez calculer dans TensorFlow la perte correspondante.


Avec le code

  1. Vous échantillonnez les paires hors ligne. Vous échantillonnez batch_size Paires d'entrées et sortez les éléments batch_size À gauche des paires de formes [batch_size, input_size]. Vous affichez également les étiquettes des paires (positives ou négatives) de forme [batch_size,]
pairs_left = np.zeros((batch_size, input_size))
pairs_right = np.zeros((batch_size, input_size))
labels = np.zeros((batch_size, 1))  # ex: [[0.], [1.], [1.], [0.]] for batch_size=4
  1. Vous créez ensuite des espaces réservés Tensorflow correspondant à ces entrées. Dans votre code, vous alimenterez les entrées précédentes vers ces espaces réservés dans l'argument feed_dict De sess.run()
pairs_left_node = tf.placeholder(tf.float32, [batch_size, input_size])
pairs_right_node = tf.placeholder(tf.float32, [batch_size, input_size])
labels_node = tf.placeholder(tf.float32, [batch_size, 1])
  1. Nous pouvons maintenant effectuer une rétroaction sur les entrées (disons que votre modèle est un modèle linéaire).
W = ...   # shape [input_size, feature_size]
output_left = tf.matmul(pairs_left_node, W)  # shape [batch_size, feature_size]
output_right = tf.matmul(pairs_right_node, W)  # shape [batch_size, feature_size]
  1. Enfin, nous pouvons calculer la perte par paire. Loss
l2_loss_pairs = tf.reduce_sum(tf.square(output_left - output_right), 1)
positive_loss = l2_loss_pairs
negative_loss = tf.nn.relu(margin - l2_loss_pairs)
final_loss = tf.mul(labels_node, positive_loss) + tf.mul(1. - labels_node, negative_loss)

Et c'est tout ! Vous pouvez désormais optimiser cette perte, avec un bon échantillonnage hors ligne.

7
Olivier Moindrot