Жесткий отрицательный майнинг в тензорном потоке (обучение дескриптору) - PullRequest
0 голосов
/ 01 августа 2020
• 1000 *
def loss_desc_triplet(y_true, y_pred):
    """Triplet loss.
    """
    
    d1 = y_pred[:,0:128]
    d2 = y_pred[:,128:256]
    d3 = y_pred[:,256:384]
    ...

Код без жесткого отрицательного анализа выглядит так:

if mine_negative == False:
        d_pos = tf.sqrt(tf.reduce_sum(tf.square(d1 - d2), axis=1))
        d_neg = tf.sqrt(tf.reduce_sum(tf.square(d1 - d3), axis=1))
        
        if loss_type == "triplet":
            if squared_loss:
                return tf.nn.relu(tf.square(d_pos) - tf.square(d_neg) + margin)
            else:
                return tf.nn.relu(d_pos - d_neg + margin)

Теперь моя идея состоит в том, чтобы вычислить евклидово расстояние от каждого отдельного якоря до каждого отдельного положительного дескриптора в пакете, а затем проверьте, меньше ли расстояние между исходной привязкой и любым из других положительных дескрипторов, чем расстояние между исходной привязкой и исходным негативом. В этом случае я хочу использовать положительное значение другого триплета для формирования нового триплета.

Вот мой код, который я придумал:

def hard_negative_mining_ec(anchor, positive, batch_size):
    all_distances = []
    for i in range(batch_size):
        distances = []
        for ii in range(batch_size):
            if i == ii:
                continue
            current_dist = tf.sqrt(tf.reduce_sum(tf.square(anchor[i,:] - positive[ii,:])))
            distances.append(current_dist)
        current_desc_pairs = tf.stack(distances)
        all_distances.append(tf.keras.backend.min(current_desc_pairs))
        
    return tf.stack(all_distances)

и новую функцию потерь:

elif mine_negative == True:
        d_pos = tf.sqrt(tf.reduce_sum(tf.square(d1 - d2), axis=1))
        d_neg = tf.sqrt(tf.reduce_sum(tf.square(d1 - d3), axis=1))

        d_hnm_neg = hard_negative_mining_ec(d1, d2, batch_size=batch_size)
        
        d_opti_neg = tf.math.minimum(d_neg, d_hnm_neg)

        if loss_type == "triplet":
            if squared_loss:
                return tf.reduce_mean(tf.nn.relu(tf.square(d_pos) - tf.square(d_opti_neg) + margin))
            else:
                return tf.reduce_mean(tf.nn.relu(d_pos - d_opti_neg + margin))

Однако теперь мой скрипт Tensorflow больше не работает. Моя системная память просто заполнена, но фактическое обучение не начинается.

Что мне здесь не хватает?

РЕДАКТИРОВАТЬ:

Я обновил свой код:

import numpy as np
np.set_printoptions(suppress=True)

import tensorflow as tf
gpus = tf.config.experimental.list_physical_devices('GPU')
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)


anchor = (np.random.random((10,10))*10).astype(int).astype(np.float32)
positive = (np.random.random((10,10))*10).astype(int).astype(np.float32)

anchor_tf = tf.convert_to_tensor(anchor)
positive_tf = tf.convert_to_tensor(positive)

def hard_negative_mining_ec(anchor, positive):
    x_r = tf.repeat(anchor, repeats=tf.shape(positive)[0])
    y_r = tf.repeat(positive, repeats=tf.shape(anchor)[0])
    
    x_r = tf.transpose(tf.reshape(x_r, [tf.shape(positive)[0], 
                                        tf.shape(positive)[0],tf.shape(positive)[0]]), [0,2,1])
    y_r = tf.transpose(tf.reshape(y_r, [tf.shape(anchor)[0], 
                                        tf.shape(anchor)[0],tf.shape(anchor)[0]]), [2,0,1])
    
    desc_dist = tf.sqrt(tf.reduce_sum(tf.square(x_r - y_r), axis=2))
    
    eye_tf = tf.eye(tf.shape(desc_dist)[1])*1000
    
    d_pos = desc_dist+eye_tf
    
    print(d_pos)
    
    best = tf.keras.backend.min(d_pos, axis=1)
    print(best)
    return best

    
hard_negative_mining_ec(anchor_tf, positive_tf)

Теоретически это работает так, как задумано, и у меня нет проблемы, упомянутой выше. Однако моя сеть больше не обучается должным образом, а точность снижается.

...