python - 如何在 Keras/Tensorflow 中编写自定义损失函数,该函数使用带有引用 numpy 代码的循环/迭代

标签 python tensorflow keras pytorch

我看到了这个问题:Implementing custom loss function in keras with condition我需要做同样的事情,但代码似乎需要循环。

我有一个自定义的 numpy 函数,它计算与平均向量的平均欧几里得距离。我是根据论文 https://arxiv.org/pdf/1801.05365.pdf 写的:

Equation Picture

import numpy as np

def mean_euclid_distance_from_mean_vector(n_vectors):

    dists = []

    for (i, v) in enumerate(n_vectors):
        n_vectors_rest = n_vectors[np.arange(len(n_vectors)) != i]

        print("rest of vectors: ")
        print(n_vectors_rest)

        # calculate mean vector
        mean_rest = n_vectors_rest.mean(axis=0)

        print("mean rest vector")
        print(mean_rest)

        dist = v - mean_rest

        print("dist vector")
        print(dist)
        dists.append(dist)

    # dists is now a matrix of distance vectors (distance from the mean vector)
    dists = np.array(dists)

    print("distance vector matrix")
    print(dists)

    # here we matmult each vector
    # sum them up
    # and divide by the total number of elements
    result = np.sum([np.matmul(d, d) for d in dists]) / dists.size

    return result


features = np.array([
    [1,2,3,4],
    [4,3,2,1]
])

c = mean_euclid_distance_from_mean_vector(features)

print(c)

不过,我需要此函数才能在 tensorflow 中使用 Keras。所以自定义 lambda https://www.tensorflow.org/api_docs/python/tf/keras/layers/Lambda

但是,我不确定如何在 Keras/Tensorflow 中实现上述内容,因为它有循环,而且论文中谈到计算 m_i 的方式似乎需要循环,就像我实现的方式一样以上。

作为引用,此代码的 PyTorch 版本位于:https://github.com/PramuPerera/DeepOneClass

最佳答案

给定一个像这样的特征图:

features = np.array([
    [1, 2, 3, 4],
    [2, 4, 4, 3],
    [3, 2, 1, 4],
], dtype=np.float64)

反射(reflect)了 batch_size

batch_size = features.shape[0]

k = features.shape[1]

在 Tensorflow 中实现上述公式可以通过以下方式表达(原型(prototype)化):

dim = (batch_size, features.shape[1])
def zero(i):
    arr = np.ones(dim)
    arr[i] = 0
    return arr


mapper = [zero(i) for i in range(batch_size)]
elems = (features, mapper)
m = (1 / (batch_size - 1)) * tf.map_fn(lambda x: tf.math.reduce_sum(x[0] * x[1], axis=0), elems, dtype=tf.float64)
pairs = tf.map_fn(lambda x: tf.concat(x, axis=0) , tf.stack([features, m], 1), dtype=tf.float64)
compactness_loss = (1 / (batch_size * k)) * tf.map_fn(lambda x: tf.math.reduce_euclidean_norm(x), pairs, dtype=tf.float64)

with tf.Session() as sess:
    print("loss value output is: ", compactness_loss.eval())

产生:

loss value output is:  [0.64549722 0.79056942 0.64549722]

但是batch需要一个measure,所以需要减少;通过所有值的总和。

Tensorflow 中想要的 Compactness Loss 函数是:

def compactness_loss(actual, features):
    features = Flatten()(features)
    k = 7 * 7 * 512
    dim = (batch_size, k)

    def zero(i):
        z = tf.zeros((1, dim[1]), dtype=tf.dtypes.float32)
        o = tf.ones((1, dim[1]), dtype=tf.dtypes.float32)
        arr = []
        for k in range(dim[0]):
            arr.append(o if k != i else z)
        res = tf.concat(arr, axis=0)
        return res

    masks = [zero(i) for i in range(batch_size)]
    m = (1 / (batch_size - 1)) * tf.map_fn(
        # row-wise summation
        lambda mask: tf.math.reduce_sum(features * mask, axis=0),
        masks,
        dtype=tf.float32,
    )
    dists = features - m
    sqrd_dists = tf.pow(dists, 2)
    red_dists = tf.math.reduce_sum(sqrd_dists, axis=1)
    compact_loss = (1 / (batch_size * k)) * tf.math.reduce_sum(red_dists)
    return compact_loss

当然,为了方便起见,可以将 Flatten() 移回模型中,并且 k 可以直接从特征图派生;这回答了你的问题。您可能只是难以找出模型的预期值是 - 例如来自针对 imagenet 训练的 VGG16(或任何其他架构)的特征图?

论文说:

In our formulation (shown in Figure 2 (e)), starting froma pre-trained deep model, we freeze initial features (gs) and learn (gl) and (hc). Based on the output of the classification sub-network (hc), two losses compactness loss and descriptiveness loss are evaluated. These two losses, introduced in the subsequent sections, are used to assess the quality of the learned deep feature. We use the provided one-class dataset to calculate the compactness loss. An external multi-class reference dataset is used to evaluate the descriptiveness loss.As shown in Figure 3, weights of gl and hc are learned in the proposed method through back-propagation from the composite loss. Once training is converged, system shown in setup in Figure 2(d) is used to perform classification where the resulting model is used as the pre-trained model.

然后查看“框架”主干 here加上:

AlexNet Binary and VGG16 Binary (Baseline). A binary CNN is trained by having ImageNet samples and one-class image samples as the two classes using AlexNet andVGG16 architectures, respectively. Testing is performed using k-nearest neighbor, One-class SVM [43], Isolation Forest [3]and Gaussian Mixture Model [3] classifiers.

让我想知道将建议的密集层添加到 SecondaryReference 网络到单个类输出(Sigmoid)甚至是不合理和二进制类输出(使用 Softmax)并使用 mean_squared_error 作为所谓的紧凑性损失和 binary_cross_entropy 作为描述性损失。

关于python - 如何在 Keras/Tensorflow 中编写自定义损失函数,该函数使用带有引用 numpy 代码的循环/迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62079034/

相关文章:

python-docx 如何获取节的内容/正文

python - 使用 Python 直接从 zip 文件中读取 xml 文件

neural-network - Keras - 层的线性堆栈?

python - 如何在神经网络的隐藏层中对权重矩阵的列实现正交约束?

python - 属性错误: 'Node' object has no attribute 'outbound_layers'

python - 递归公式带有循环很慢,有没有办法让这段代码运行得更快?

python - 如何使用 SqlAlchemy declarative_base 创建单个表

python - 非常奇怪的 tensorflow 行为

单(多核)CPU 设备上的 TensorFlow 执行

tensorflow - tf.train.MonitoredTrainingSession 和 tf.train.Supervisor 有什么区别