2017-12-18 1 views
0

Ich versuche ein Triplet-Netzwerk wie in der facenet article beschrieben zu trainieren.Genauigkeit 99%, Klassifizierung falsch - Triplet-Netzwerk

Ich berechne die Genauigkeit des Validierungssatzes, indem ich die Tripletts zähle, bei denen der positive Abstand (anker - positiv) kleiner ist als der negative Abstand (anker - negativ) und dann dividiert durch die Gesamtzahl der Tripel im Stapel.

Ich bekomme tolle Ergebnisse: 99% Genauigkeit. Aber wenn ich meine Modelleinbettungen verwende, um Bilder zu klassifizieren (ich nehme ein unbekanntes Bild und vergleiche es - mit euklidischer Distanz - mit einigen beschrifteten Bildern) - sind nur noch höchstens 20% Ergebnisse korrekt.

Was mache ich falsch?

Unten finden Sie meine detaillierte Implementierung.


Triplet Erzeugung

Bevor Triplett Generation habe ich ausgerichtet und beschnitten sowohl die Ausbildung und das Test-Set unter Verwendung von DLIB (beide CASIA und LFW), so dass die Hauptelemente jeder Fläche (Augen, Ohren, Lippen) sind fast gleich positioniert.

Um die Triplets zu erzeugen, wähle ich zufällig einen CASIA-Ordner mit 40 oder mehr Bildern und wähle dann 40 Anker, jeder der Anker mit einem entsprechenden positiven Bild (das zufällig ausgewählt wird, sich aber vom Anker unterscheidet). Dann wähle ich für jedes Anker-positive Paar ein zufälliges Negativ.


Triplet Verlust

Hier ist meine Triplett Verlustfunktion:

def triplet_loss(d_pos, d_neg): 

    print("d_pos "+str(d_pos)) 
    print("d_neg "+str(d_neg)) 

    margin = 0.2 

    loss = tf.reduce_mean(tf.maximum(0., margin + d_pos - d_neg)) 


    return loss 

Das ist mein positiver Abstand (zwischen Anker und positiv) und negativen Abstand (zwischen Anker und Negativ).

**model1** = embeddings generated for the anchor image 
**model2** = embeddings generated for the positive image 
**model3** = embeddings generated for the negative image 

Die Variable Kosten I ist der Verlust bei jedem Schritt zu berechnen.

d_pos_triplet = tf.reduce_sum(tf.square(model1 - model2), 1) 
    d_neg_triplet = tf.reduce_sum(tf.square(model1 - model3), 1) 

    d_pos_triplet_acc = tf.sqrt(d_pos_triplet + 1e-10) 
    d_neg_triplet_acc = tf.sqrt(d_neg_triplet + 1e-10) 

    d_pos_triplet_test = tf.reduce_sum(tf.square(model1_test - model2_test), 1) 
    d_neg_triplet_test = tf.reduce_sum(tf.square(model1_test - model3_test), 1) 

    d_pos_triplet_acc_test = tf.sqrt(d_pos_triplet_test + 1e-10) 
    d_neg_triplet_acc_test = tf.sqrt(d_neg_triplet_test + 1e-10) 


    cost = triplet_loss(d_pos_triplet, d_neg_triplet) 
    cost_test = triplet_loss(d_pos_triplet_test, d_neg_triplet_test) 

Ich nehme dann die Einbettungen eins nach dem anderen und testen, ob der Verlust positiv ist - weil 0 Verlust bedeutet, dass das Netzwerk lernt nicht (wie im facenet Artikel stellte ich fest, halbhart wählen Drillinge)

input1,input2, input3, anchor_folder_helper, anchor_photo_helper, positive_photo_helper = training.next_batch_casia(s,e) #generate complet random 

      s = i * batch_size 
      e = (i+1) *batch_size 

     input1,input2, input3, anchor_folder_helper, anchor_photo_helper, positive_photo_helper = training.next_batch_casia(s,e) #generate complet random 


     lly = 0; 

     '''counter which helps me generate the same number of triplets each batch''' 

     while lly < len(input1): 

      input_lly1 = input1[lly:lly+1] 
      input_lly2 = input2[lly:lly+1] 
      input_lly3 = input3[lly:lly+1] 

      loss_value = sess.run([cost], feed_dict={x_anchor:input_lly1, x_positive:input_lly2, x_negative:input_lly3}) 



      while(loss_value[0]<=0): 
       ''' While the generated triplet has loss 0 (which means dpos - dneg + margin < 0) I keep generating triplets. I stop when I manage to generate a semi-hard triplet. ''' 
       input_lly1,input_lly2, input_lly3, anchor_folder_helper, anchor_photo_helper, positive_photo_helper = training.cauta_hard_negative(anchor_folder_helper, anchor_photo_helper, positive_photo_helper) 
       loss_value = sess.run([cost], feed_dict={x_anchor:input_lly1, x_positive:input_lly2, x_negative:input_lly3}) 

       if (loss_value[0] > 0): 
        _, loss_value, distance1_acc, distance2_acc, m1_acc, m2_acc, m3_acc = sess.run([accum_ops, cost, d_pos_triplet_acc, d_neg_triplet_acc, model1, model2, model3], feed_dict={x_anchor:input_lly1, x_positive:input_lly2, x_negative:input_lly3}) 
       tr_acc = compute_accuracy(distance1_acc, distance2_acc) 

       if math.isnan(tr_acc) and epoch != 0: 
        print('tr_acc %0.2f' % tr_acc) 
        pdb.set_trace() 
        avg_loss += loss_value 
        avg_acc +=tr_acc*100 

        contor_i = contor_i + 1 

        lly = lly + 1 

Das ist mein Modell ist - beachten sie, dass, wenn ich L2 Normalisierung meiner Genauigkeit gelten sinkt deutlich (vielleicht tue ich es falsch):

def siamese_convnet(x): 

    w_conv1_1 = tf.get_variable(name='w_conv1_1', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 1, 64]) 
    w_conv1_2 = tf.get_variable(name='w_conv1_2', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 64, 64]) 

    w_conv2_1 = tf.get_variable(name='w_conv2_1', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 64, 128]) 
    w_conv2_2 = tf.get_variable(name='w_conv2_2', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 128, 128]) 

    w_conv3_1 = tf.get_variable(name='w_conv3_1', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 128, 256]) 
    w_conv3_2 = tf.get_variable(name='w_conv3_2', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 256, 256]) 
    w_conv3_3 = tf.get_variable(name='w_conv3_3', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 256, 256]) 

    w_conv4_1 = tf.get_variable(name='w_conv4_1', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 256, 512]) 
    w_conv4_2 = tf.get_variable(name='w_conv4_2', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 512, 512]) 
    w_conv4_3 = tf.get_variable(name='w_conv4_3', initializer=tf.contrib.layers.xavier_initializer(), shape=[1, 1, 512, 512]) 

    w_conv5_1 = tf.get_variable(name='w_conv5_1', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 512, 512]) 
    w_conv5_2 = tf.get_variable(name='w_conv5_2', initializer=tf.contrib.layers.xavier_initializer(), shape=[3, 3, 512, 512]) 
    w_conv5_3 = tf.get_variable(name='w_conv5_3', initializer=tf.contrib.layers.xavier_initializer(), shape=[1, 1, 512, 512]) 

    w_fc_1 = tf.get_variable(name='w_fc_1', initializer=tf.contrib.layers.xavier_initializer(), shape=[5*5*512, 2048]) 
    w_fc_2 = tf.get_variable(name='w_fc_2', initializer=tf.contrib.layers.xavier_initializer(), shape=[2048, 1024]) 

    w_out = tf.get_variable(name='w_out', initializer=tf.contrib.layers.xavier_initializer(), shape=[1024, 128]) 

    bias_conv1_1 = tf.get_variable(name='bias_conv1_1', initializer=tf.constant(0.01, shape=[64])) 
    bias_conv1_2 = tf.get_variable(name='bias_conv1_2', initializer=tf.constant(0.01, shape=[64])) 

    bias_conv2_1 = tf.get_variable(name='bias_conv2_1', initializer=tf.constant(0.01, shape=[128])) 
    bias_conv2_2 = tf.get_variable(name='bias_conv2_2', initializer=tf.constant(0.01, shape=[128])) 

    bias_conv3_1 = tf.get_variable(name='bias_conv3_1', initializer=tf.constant(0.01, shape=[256])) 
    bias_conv3_2 = tf.get_variable(name='bias_conv3_2', initializer=tf.constant(0.01, shape=[256])) 
    bias_conv3_3 = tf.get_variable(name='bias_conv3_3', initializer=tf.constant(0.01, shape=[256])) 

    bias_conv4_1 = tf.get_variable(name='bias_conv4_1', initializer=tf.constant(0.01, shape=[512])) 
    bias_conv4_2 = tf.get_variable(name='bias_conv4_2', initializer=tf.constant(0.01, shape=[512])) 
    bias_conv4_3 = tf.get_variable(name='bias_conv4_3', initializer=tf.constant(0.01, shape=[512])) 

    bias_conv5_1 = tf.get_variable(name='bias_conv5_1', initializer=tf.constant(0.01, shape=[512])) 
    bias_conv5_2 = tf.get_variable(name='bias_conv5_2', initializer=tf.constant(0.01, shape=[512])) 
    bias_conv5_3 = tf.get_variable(name='bias_conv5_3', initializer=tf.constant(0.01, shape=[512])) 

    bias_fc_1 = tf.get_variable(name='bias_fc_1', initializer=tf.constant(0.01, shape=[2048])) 
    bias_fc_2 = tf.get_variable(name='bias_fc_2', initializer=tf.constant(0.01, shape=[1024])) 

    out = tf.get_variable(name='out', initializer=tf.constant(0.01, shape=[128])) 

    x = tf.reshape(x , [-1, 160, 160, 1]); 

    conv1_1 = tf.nn.relu(conv2d(x, w_conv1_1) + bias_conv1_1); 
    conv1_2= tf.nn.relu(conv2d(conv1_1, w_conv1_2) + bias_conv1_2); 

    max_pool1 = max_pool(conv1_2); 

    conv2_1 = tf.nn.relu(conv2d(max_pool1, w_conv2_1) + bias_conv2_1); 
    conv2_2 = tf.nn.relu(conv2d(conv2_1, w_conv2_2) + bias_conv2_2); 

    max_pool2 = max_pool(conv2_2) 

    conv3_1 = tf.nn.relu(conv2d(max_pool2, w_conv3_1) + bias_conv3_1); 
    conv3_2 = tf.nn.relu(conv2d(conv3_1, w_conv3_2) + bias_conv3_2); 
    conv3_3 = tf.nn.relu(conv2d(conv3_2, w_conv3_3) + bias_conv3_3); 

    max_pool3 = max_pool(conv3_3) 

    conv4_1 = tf.nn.relu(conv2d(max_pool3, w_conv4_1) + bias_conv4_1); 
    conv4_2 = tf.nn.relu(conv2d(conv4_1, w_conv4_2) + bias_conv4_2); 
    conv4_3 = tf.nn.relu(conv2d(conv4_2, w_conv4_3) + bias_conv4_3); 

    max_pool4 = max_pool(conv4_3) 

    conv5_1 = tf.nn.relu(conv2d(max_pool4, w_conv5_1) + bias_conv5_1); 
    conv5_2 = tf.nn.relu(conv2d(conv5_1, w_conv5_2) + bias_conv5_2); 
    conv5_3 = tf.nn.relu(conv2d(conv5_2, w_conv5_3) + bias_conv5_3); 

    max_pool5 = max_pool(conv5_3) 

    fc_helper = tf.reshape(max_pool5, [-1, 5*5*512]); 
    fc_1 = tf.nn.relu(tf.matmul(fc_helper, w_fc_1) + bias_fc_1); 

    fc_2 = tf.nn.relu(tf.matmul(fc_1, w_fc_2) + bias_fc_2); 

    output = tf.matmul(fc_2, w_out) + out 
    #output = tf.nn.l2_normalize(output, 0) THIS IS COMMENTED 


    return output 

Mein Modell in einem Rahmen unabhängiger Art und Weise:

conv 3x3 (1, 64) 
conv 3x3 (64,64) 
max_pooling 
conv 3x3 (64, 128) 
conv 3x3 (128, 128) 
max_pooling 
conv 3x3 (128, 256) 
conv 3x3 (256, 256) 
conv 3x3 (256, 256) 
max_pooling 
conv 3x3 (256, 512) 
conv 3x3 (512, 512) 
conv 1x1 (512, 512) 
max_pooling 
conv 3x3 (256, 512) 
conv 3x3 (512, 512) 
conv 1x1 (512, 512) 
max_pooling 
fully_connected(128) 
fully_connected(128) 
output(128) 

Antwort

1

Ihre L2 Normalisierung ist Feature-weise, wenn es Vorbild weise sein sollte.

+0

Vielen Dank für die Antwort! Können Sie bitte weitere Einzelheiten angeben? Was meinst du exemplarisch? Vielen Dank! –

+0

@HelloLili hast du herausgefunden, was exemplarisch bedeutet? –

+0

@AbhijitBalaji Nein, aber ich habe herausgefunden, was ich falsch gemacht habe: output = tf.nn.l2_normalize (Ausgabe, 0) sollte ausgegeben werden = tf.nn.l2_normalize (Ausgabe, Achse = 1) –

Verwandte Themen