I am trying to implement chamfer distance in tensorflow.
But, my code is taking input as numpy array. To convert a numpy into a tensor, we need to run a session, but the process is already in another session. I think two sessions can't run in parallel.
So, can anyone help me with the implementation of chamfer distance in tensorflow or help me with this problem of two simultaneous sessions?
my code is:
def chamfer_distance(array1,array2):
    # final = 0
    # final = tf.cast(final,tf.float32)
    batch_size = array1.get_shape()[0].value
    num_point = array1.get_shape()[1].value
    sess = tf.Session()
    arr1,arr2 = sess.run([array1,array2])
    del sess
    dist = 0
    for i in range(batch_size):
        tree1 = KDTree(arr1[i], leafsize=num_point+1)
        tree2 = KDTree(arr2[i], leafsize=num_point+1)
        distances1, _ = tree1.query(arr2[i])
        distances2, _ = tree2.query(arr1[i])
        distances1 = tf.convert_to_tensor(distances1)
        distances2 = tf.convert_to_tensor(distances2)
        av_dist1 = tf.reduce_mean(distances1)
        av_dist2 = tf.reduce_mean(distances2)
        dist = dist + (av_dist1+av_dist2)/batch_size
    return dist
                I've implemented TF version of chamfer distance:
def distance_matrix(array1, array2):
    """
    arguments: 
        array1: the array, size: (num_point, num_feature)
        array2: the samples, size: (num_point, num_feature)
    returns:
        distances: each entry is the distance from a sample to array1
            , it's size: (num_point, num_point)
    """
    num_point, num_features = array1.shape
    expanded_array1 = tf.tile(array1, (num_point, 1))
    expanded_array2 = tf.reshape(
            tf.tile(tf.expand_dims(array2, 1), 
                    (1, num_point, 1)),
            (-1, num_features))
    distances = tf.norm(expanded_array1-expanded_array2, axis=1)
    distances = tf.reshape(distances, (num_point, num_point))
    return distances
def av_dist(array1, array2):
    """
    arguments:
        array1, array2: both size: (num_points, num_feature)
    returns:
        distances: size: (1,)
    """
    distances = distance_matrix(array1, array2)
    distances = tf.reduce_min(distances, axis=1)
    distances = tf.reduce_mean(distances)
    return distances
def av_dist_sum(arrays):
    """
    arguments:
        arrays: array1, array2
    returns:
        sum of av_dist(array1, array2) and av_dist(array2, array1)
    """
    array1, array2 = arrays
    av_dist1 = av_dist(array1, array2)
    av_dist2 = av_dist(array2, array1)
    return av_dist1+av_dist2
def chamfer_distance_tf(array1, array2):
    batch_size, num_point, num_features = array1.shape
    dist = tf.reduce_mean(
               tf.map_fn(av_dist_sum, elems=(array1, array2), dtype=tf.float64)
           )
    return dist
And for validation purpose, I also implemented a sklearn version:
def chamfer_distance_sklearn(array1,array2):
    batch_size, num_point = array1.shape[:2]
    dist = 0
    for i in range(batch_size):
        tree1 = KDTree(array1[i], leaf_size=num_point+1)
        tree2 = KDTree(array2[i], leaf_size=num_point+1)
        distances1, _ = tree1.query(array2[i])
        distances2, _ = tree2.query(array1[i])
        av_dist1 = np.mean(distances1)
        av_dist2 = np.mean(distances2)
        dist = dist + (av_dist1+av_dist2)/batch_size
    return dist
Also a numpy version:
def array2samples_distance(array1, array2):
    """
    arguments: 
        array1: the array, size: (num_point, num_feature)
        array2: the samples, size: (num_point, num_feature)
    returns:
        distances: each entry is the distance from a sample to array1 
    """
    num_point, num_features = array1.shape
    expanded_array1 = np.tile(array1, (num_point, 1))
    expanded_array2 = np.reshape(
            np.tile(np.expand_dims(array2, 1), 
                    (1, num_point, 1)),
            (-1, num_features))
    distances = LA.norm(expanded_array1-expanded_array2, axis=1)
    distances = np.reshape(distances, (num_point, num_point))
    distances = np.min(distances, axis=1)
    distances = np.mean(distances)
    return distances
def chamfer_distance_numpy(array1, array2):
    batch_size, num_point, num_features = array1.shape
    dist = 0
    for i in range(batch_size):
        av_dist1 = array2samples_distance(array1[i], array2[i])
        av_dist2 = array2samples_distance(array2[i], array1[i])
        dist = dist + (av_dist1+av_dist2)/batch_size
    return dist
You can validate the result using following script:
batch_size = 8
num_point = 20
num_features = 4
np.random.seed(1)
array1 = np.random.randint(0, high=4, size=(batch_size, num_point, num_features))
array2 = np.random.randint(0, high=4, size=(batch_size, num_point, num_features))
print('sklearn: ', chamfer_distance_sklearn(array1, array2))
print('numpy: ', chamfer_distance_numpy(array1, array2))
array1_tf = tf.constant(array1, dtype=tf.float64)
array2_tf = tf.constant(array2, dtype=tf.float64)
dist_tf = chamfer_distance_tf(array1_tf, array2_tf)
with tf.Session() as sess:
    print('tf: ', sess.run(dist_tf))
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With