J'apprends le réseau de neurones et je veux écrire une fonction cross_entropy
en python. Où il est défini comme
où N
est le nombre d'échantillons, k
est le nombre de classes, log
est le logarithme naturel, t_i,j
est 1 si l'échantillon i
est dans la classe j
et 0
sinon, et p_i,j
est la probabilité prédite que l'échantillon i
est dans class j
. Pour éviter les problèmes numériques avec le logarithme, découpez les prédictions dans la plage [10^{−12}, 1 − 10^{−12}]
.
Selon la description ci-dessus, j’ai écrit les codes en découpant les prédictions dans la plage [epsilon, 1 − epsilon]
, puis en calculant le cross_entropy sur la base de la formule ci-dessus.
def cross_entropy(predictions, targets, epsilon=1e-12):
"""
Computes cross entropy between targets (encoded as one-hot vectors)
and predictions.
Input: predictions (N, k) ndarray
targets (N, k) ndarray
Returns: scalar
"""
predictions = np.clip(predictions, epsilon, 1. - epsilon)
ce = - np.mean(np.log(predictions) * targets)
return ce
Le code suivant sera utilisé pour vérifier si la fonction cross_entropy
est correcte.
predictions = np.array([[0.25,0.25,0.25,0.25],
[0.01,0.01,0.01,0.96]])
targets = np.array([[0,0,0,1],
[0,0,0,1]])
ans = 0.71355817782 #Correct answer
x = cross_entropy(predictions, targets)
print(np.isclose(x,ans))
La sortie des codes ci-dessus est False, c'est-à-dire que mes codes pour définir la fonction cross_entropy
sont incorrects. Ensuite, j'imprime le résultat de cross_entropy(predictions, targets)
. Il a donné 0.178389544455
et le résultat correct devrait être ans = 0.71355817782
. Quelqu'un pourrait-il m'aider à vérifier quel est le problème avec mes codes?
Vous n'êtes pas si loin du tout, mais souvenez-vous que vous prenez la valeur moyenne de N sommes, où N = 2 (dans ce cas). Donc, votre code pourrait lire:
def cross_entropy(predictions, targets, epsilon=1e-12):
"""
Computes cross entropy between targets (encoded as one-hot vectors)
and predictions.
Input: predictions (N, k) ndarray
targets (N, k) ndarray
Returns: scalar
"""
predictions = np.clip(predictions, epsilon, 1. - epsilon)
N = predictions.shape[0]
ce = -np.sum(targets*np.log(predictions+1e-9))/N
return ce
predictions = np.array([[0.25,0.25,0.25,0.25],
[0.01,0.01,0.01,0.96]])
targets = np.array([[0,0,0,1],
[0,0,0,1]])
ans = 0.71355817782 #Correct answer
x = cross_entropy(predictions, targets)
print(np.isclose(x,ans))
Ici, je pense que c'est un peu plus clair si vous vous en tenez à np.sum()
. De plus, j'ai ajouté 1e-9 à la np.log()
pour éviter la possibilité d'avoir un log (0) dans vos calculs. J'espère que cela t'aides!
NOTE: Selon le commentaire de @ Peter, l'offset de 1e-9
est en effet redondant si votre valeur epsilon est supérieure à 0
.
def cross_entropy(x, y):
""" Computes cross entropy between two distributions.
Input: x: iterabale of N non-negative values
y: iterabale of N non-negative values
Returns: scalar
"""
if np.any(x < 0) or np.any(y < 0):
raise ValueError('Negative values exist.')
# Force to proper probability mass function.
x = np.array(x, dtype=np.float)
y = np.array(y, dtype=np.float)
x /= np.sum(x)
y /= np.sum(y)
# Ignore zero 'y' elements.
mask = y > 0
x = x[mask]
y = y[mask]
ce = -np.sum(x * np.log(y))
return ce
def cross_entropy_via_scipy(x, y):
''' SEE: https://en.wikipedia.org/wiki/Cross_entropy'''
return entropy(x) + entropy(x, y)
from scipy.stats import entropy, truncnorm
x = truncnorm.rvs(0.1, 2, size=100)
y = truncnorm.rvs(0.1, 2, size=100)
print np.isclose(cross_entropy(x, y), cross_entropy_via_scipy(x, y))