简体   繁体   English

在 tensorflow keras 中创建熵作为自定义损失函数

[英]creating entropy as a custom loss function in tensorflow keras

I am trying to create a custom loss function in tensorflow.keras;我正在尝试在 tensorflow.keras 中创建自定义损失函数; particularly, shannon's entropy.特别是香农熵。 Here is the basic neural net structure这是基本的神经网络结构

import tensorflow as tf
import numpy as np

import matplotlib.pyplot as plt

from scipy.stats import entropy
import numpy as np




mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train =x_train / 255.0





model = tf.keras.models.Sequential([

  tf.keras.layers.Flatten(input_shape=(28, 28, 1)),

  tf.keras.layers.Dense(128, activation=tf.nn.sigmoid),
  tf.keras.layers.Dense(10, activation=tf.nn.sigmoid)
])
model.compile(optimizer='sgd',
              loss=entropy_loss,
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=1,batch_size=512)

And I am trying 2 ways to calculate entropy, neither of which is working.我正在尝试 2 种计算熵的方法,这两种方法都不起作用。 The 1st way is to convert the y_true and y_pred to numpy, get the error, then calculate entropy using scipy's entropy measure.第一种方法是将 y_true 和 y_pred 转换为 numpy,获取误差,然后使用 scipy 的熵度量计算熵。 I am facing errors for converting to numpy.我在转换为 numpy 时遇到错误。 The 2nd way I am using tensorflow calculations, based on this:我使用张量流计算的第二种方式,基于此:

how to calculate entropy on float numbers over a tensor in python keras 如何计算python keras中张量上浮点数的熵

and still am facing errors there.并且仍然在那里面临错误。

method1方法一

def entropy_loss(y_true,y_pred):

    # Create a loss function that adds the MSE loss to the mean of all squared activations of a specific layer
   
    return tf.cast(entropy(y_pred.numpy() - y_true.numpy() , base=2))
   
    # Return a function
    #return loss

the 1st way has this error:第一种方式有这个错误:

    <ipython-input-4-14c95bd6b1a3>:5 entropy_loss  *
        return tf.cast(entropy(y_pred.numpy() - y_true.numpy() , base=2))

    AttributeError: 'Tensor' object has no attribute 'numpy'

method2方法二

def entropy_loss(y_true,y_pred):

    y_true=tf.cast(y_true, tf.float32)
    y_pred=tf.cast(y_pred, tf.float32)
    e=y_true-y_pred
    print(e)
    loss= entropy_1(e) 
    #return e
    # Return a function
    return loss
def entropy_1( x):
    def row_entropy(row):
        _, _, count = tf.unique_with_counts(row)
        prob = count / tf.reduce_sum(count)
        return -tf.reduce_sum(prob * tf.math.log(prob))

    value_ranges = [-10.0, 100.0]
    nbins = 50
    new_f_w_t = tf.histogram_fixed_width_bins(x, value_ranges, nbins)
    result = tf.map_fn(row_entropy, new_f_w_t,dtype=tf.float32)
    return result

This method has the following error:此方法有以下错误:

    ValueError: Trying to read from list with wrong element dtype. List has type double but expected type float for '{{node entropy_loss/map/TensorArrayV2Stack/TensorListStack}} = TensorListStack[element_dtype=DT_FLOAT, num_elements=-1](entropy_loss/map/while:3, entropy_loss/map/TensorArrayV2Stack/Const)' with input shapes: [], [0].

Actually, you don't need to implement it.实际上,您不需要实现它。 But, let's figure out.但是,让我们弄清楚。

Suppose, you have batch two, answers and predictions.假设您有第二批,答案和预测。 You suspect, that tf entropy and entropy from scipy will give the same results.您怀疑,来自 scipy 的 tf entropy 和 entropy 会给出相同的结果。

a = np.array([[1], [2]], dtype=np.float)
b = np.array([[0.2, 0.7, 0.1], [0.2, 0.3, 0.5]], dtype=np.float)
at = tf.convert_to_tensor(a)
bt = tf.convert_to_tensor(b)
H = tf.keras.losses.sparse_categorical_crossentropy(a, b)
print(f"TF entropy: {H}")

a = [[0.2, 0.7, 0.1], [0.2, 0.3, 0.5]]
b = [[0, 1, 0], [0, 0, 1]]
H2 = entropy(b, a, axis=1)
print(f"Scipy entropy: {H2}")

Results:结果:
TF entropy: [0.35667494 0.69314718] TF 熵:[0.35667494 0.69314718]
Scipy entropy: [0.35667494 0.69314718] Scipy 熵:[0.35667494 0.69314718]

Ok, let's implement it.好的,让我们实现它。

def my_entropy(y_true, y_pred):
    shape = tf.shape(y_pred)
    batch = shape[0]
    depth = tf.shape(y_pred)[1]
    y_true = tf.cast(y_true, tf.int32)
    y_true = tf.reshape(y_true, shape=(-1, batch))
    one_hot = tf.one_hot(y_true, depth=depth, dtype=tf.float32)
    y_pred = tf.cast(y_pred, dtype=tf.float32)
    div = tf.divide(one_hot, y_pred)
    div = tf.reduce_sum(div, axis=0)
    ind = tf.where(tf.greater(div, 0))
    values = tf.gather_nd(div, ind)
    h = tf.math.log(values)
    return h

Test:测试:
H3 = my_entropy(at, bt) H3 = my_entropy(at, bt)
My entropy: [0.35667497 0.6931472 ]我的熵:[0.35667497 0.6931472]

Now, you can use it as custom loss function as follow:现在,您可以将其用作自定义损失函数,如下所示:

import tensorflow as tf

def my_entropy(y_true, y_pred):
    shape = tf.shape(y_pred)
    batch = shape[0]
    depth = tf.shape(y_pred)[1]
    y_true = tf.cast(y_true, tf.int32)
    y_true = tf.reshape(y_true, shape=(-1, batch))
    one_hot = tf.one_hot(y_true, depth=depth, dtype=tf.float32)
    y_pred = tf.cast(y_pred, dtype=tf.float32)
    div = tf.divide(one_hot, y_pred)
    div = tf.reduce_sum(div, axis=0)
    ind = tf.where(tf.greater(div, 0))
    values = tf.gather_nd(div, ind)
    h = tf.math.log(values)
    return h


if __name__ == '__main__':
    mnist = tf.keras.datasets.mnist

    (x_train, y_train), (x_test, y_test) = mnist.load_data()
    x_train = x_train / 255.0

    model = tf.keras.models.Sequential([

        tf.keras.layers.Flatten(input_shape=(28, 28, 1)),

        tf.keras.layers.Dense(128, activation=tf.nn.sigmoid),
        tf.keras.layers.Dense(10, activation=tf.nn.sigmoid)
    ])
    model.compile(optimizer='sgd',
                  loss=my_entropy,
                  metrics=['accuracy'])

    model.fit(x_train, y_train, epochs=5, batch_size=2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM