首页 > 解决方案 > 在自定义损失函数中迭代张量

问题描述

我需要将这个损失函数用于 CNN,list_distance 和 list_residual 是来自隐藏层的输出张量,这对于计算损失很重要,但是当我执行代码时它会返回这个错误

TypeError:张量对象仅在启用急切执行时才可迭代。要迭代此张量,请使用 tf.map_fn。

是否有另一种方法可以在不使用 X 中的 costruct x 或将其转换为 numpy 数组或使用 keras 的后端函数的情况下迭代张量?


def DBL(y_true, y_pred, list_distances, list_residual, l=0.65):
    prob_dist = []
    Li = []

    # mean of the images power spectrum
    S = np.sum([np.power(np.abs(fp.fft2(residual)), 2)
                for residual in list_residual], axis=0) / K.shape(list_residual)[0]
    # log-ratio between the geometric and arithmetic of S
    R = np.log10((scistats.gmean(S) / np.mean(S)))

    for c_i, dis_i in enumerate(list_distances):
        prob_dist.append([
            np.exp(-dis_i) / sum([np.exp(-dis_j) if c_j != c_i else 0 for c_j, dis_j in enumerate(list_distances)])
        ])
    for count, _ in enumerate(prob_dist):
        Li.append(
            -1 * np.log10(sum([p_j for c_j, p_j in enumerate(prob_dist[count])
                               if y_pred[count] == 1 and count != c_j])))

    L0 = np.sum(Li)

    return L0 - l * R

标签: pythonkerasconv-neural-network

解决方案


您需要定义一个自定义函数来输入tf.map_fn()- Tensorflow dox

映射器函数使用您定义的函数将现有对象(张量)映射(很有趣)到一个新对象中。

他们将自定义函数应用于对象中的每个元素,而无需使用for循环。

例如(未经测试的代码,可能无法在我的手机 atm 上运行):

def custom(a):
    b = a + 1
    return b

original = np.array([2,2,2])
mapped = tf.map_fn(custom, original)
# mapped == [3, 3, 3] ... hopefully

Tensorflow 示例都使用lambda函数,因此如果上述方法不起作用,您可能需要像这样定义函数。张量流示例:

elems = np.array([1, 2, 3, 4, 5, 6])
squares = map_fn(lambda x: x * x, elems)
# squares == [1, 4, 9, 16, 25, 36]

编辑:

顺便说一句,map 函数比 for 循环更容易并行化 - 假设对象的每个元素都是唯一处理的 - 因此您可以通过使用它们看到性能提升。

编辑2:

对于“减少总和,但不在此索引上”部分,我强烈建议您开始回顾矩阵运算......如前所述,map函数按元素工作 - 他们不知道其他元素。一个reduce函数是你想要的,但是当你尝试做“不是这个索引”的求和时,即使它们是有限的……张量流也是围绕矩阵运算构建的……不是 MapReduce 范式。

这些方面的东西可能会有所帮助:

sess = tf.Session()
var = np.ones([3, 3, 3]) * 5

zero_identity = tf.linalg.set_diag(
    var, tf.zeros(var.shape[0:-1], dtype=tf.float64)
)
exp_one = tf.exp(var)
exp_two = tf.exp(zero_identity)
summed = tf.reduce_sum(exp_two, axis = [0,1])
final = exp_one / summed

print("input matrix: \n", var, "\n")
print("Identities of the matrix to Zero: \n", zero_identity.eval(session=sess), "\n")
print("Exponential Values numerator: \n", exp_one.eval(session=sess), "\n")
print("Exponential Values to Sum: \n", exp_two.eval(session=sess), "\n")
print("Summed values for zero identity matrix\n ... along axis [0,1]: \n", summed.eval(session=sess), "\n")
print("Output:\n", final.eval(session=sess), "\n")

推荐阅读