TensorFlow中的欧几里得距离变换

6
我希望创建一个tensorflow函数,用于为我3维张量中的每个二维矩阵复制scipy的欧几里得距离变换
我的3维张量中的第三个轴表示一种one-hot编码特征。我想为每个特征维度创建一个矩阵,在该矩阵中,每个单元格的值等于到最近特征的距离。
例如:
input = [[1 0 0]
         [0 1 0]
         [0 0 1],

         [0 1 0]
         [0 0 0]
         [1 0 0]]

output = [[0    1   1.41]
          [1    0   1   ]
          [1.41 1   0   ],

          [1    0   1   ]
          [1    1   1.41]
          [0    1   2   ]]              

我的当前解决方案是用Python实现的。该方法遍历特征维度的每个单元格,创建一个环绕该单元格的环,并搜索该环是否包含特征。然后计算单元格到每个特征条目的距离并取最小值。如果环中不包含具有特征的单元格,则搜索环变得更宽。

代码:

import numpy as np
import math

def distance_matrix():
    feature_1 = np.eye(5)
    feature_2 = np.array([[0, 1, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [1, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],])
    ground_truth = np.stack((feature_1,feature_2), axis=2)
    x = np.zeros(ground_truth.shape)

    for feature_index in range(ground_truth.shape[2]):
        for i in range(ground_truth.shape[0]):
            for j in range(ground_truth.shape[1]):
                x[i,j,feature_index] = search_ring(i,j, feature_index,0,ground_truth)
    print(x[:,:,0])

def search_ring(i, j,feature_index, ring_size, truth):
    if ring_size == 0 and truth[i,j,feature_index] == 1.:
                    return 0
    else:
        distance = truth.shape[0]
        y_min = max(i - ring_size, 0)
        y_max = min(i + ring_size, truth.shape[0] - 1)
        x_min = max(j - ring_size, 0)
        x_max = min(j + ring_size, truth.shape[1] - 1)

        if truth[y_min:y_max+1, x_min:x_max+1, feature_index].sum() > 0:
            for y in range(y_min, y_max + 1):
                for x in range(x_min, x_max + 1):
                    if y == y_min or y == y_max or x == x_min or x == x_max:
                        if truth[y,x,feature_index] == 1.:
                            dist = norm(i,j,y,x,type='euclidean')
                            distance = min(distance, dist)
            return distance
        else:
            return search_ring(i, j,feature_index, ring_size + 1, truth)

def norm(index_y_a, index_x_a, index_y_b, index_x_b, type='euclidean'):
    if type == 'euclidean':
        return math.sqrt(abs(index_y_a - index_y_b)**2 + abs(index_x_a - index_x_b)**2)
    elif type == 'manhattan':
        return abs(index_y_a - index_y_b) + abs(index_x_a - index_x_b)


def main():
    distance_matrix()
if __name__ == '__main__':
    main()

我的问题是如何在Tensorflow中复制这个过程,因为我需要它用于Keras中的自定义损失函数。我如何访问我正在迭代的项目的索引?
2个回答

0

我曾经用 py_funcscipy 创建过一个带符号的距离变换,与你的情况类似。以下是可能适用于你的代码:

import scipy.ndimage.morphology as morph
arrs = []
for channel_index in range(C):
    arrs.append(tf.py_func(morph.distance_transform_edt, [tensor[..., channel_index]], tf.float32))
edt_tf = tf.stack(arrs, axis=-1)

请注意py_func的限制:它们不会被序列化为GraphDefs,因此在您保存的模型中,函数体将不会被序列化。请参阅tf.py_func文档

0

我认为你使用距离变换在 Keras 中没有问题,基本上你只需要使用tf.py_func,它将现有的Python函数包装成一个TensorFlow操作符。

然而,我认为这里的根本问题是反向传播。在前向传递中,你的模型没有任何问题,但你期望传播哪个梯度?或者你根本不关心它的梯度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接