webentwicklung-frage-antwort-db.com.de

Kreuzentropie-Funktion (Python)

Ich lerne das neuronale Netzwerk und möchte eine Funktion cross_entropy in Python schreiben. Wo ist es definiert als

 cross entropy

dabei ist N die Anzahl der Samples, k ist die Anzahl der Klassen, log ist der natürliche Logarithmus, t_i,j ist 1, wenn die Probe i in der Klasse j und sonst 0 ist, und p_i,j die vorhergesagte Wahrscheinlichkeit, in der i ist Klasse j. Um numerische Probleme mit dem Logarithmus zu vermeiden, schneiden Sie die Vorhersagen in den [10^{−12}, 1 − 10^{−12}]-Bereich.

Gemäß der obigen Beschreibung habe ich die Codes aufgeschrieben, indem ich die Vorhersagen auf [epsilon, 1 − epsilon] range klippte und dann den cross_entropy anhand der obigen Formel berechnete.

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

Der folgende Code wird verwendet, um zu überprüfen, ob die Funktion cross_entropy korrekt ist.

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))

Die Ausgabe der obigen Codes ist False, dh meine Codes zum Definieren der Funktion cross_entropy sind nicht korrekt. Dann drucke ich das Ergebnis von cross_entropy(predictions, targets) aus. Es gab 0.178389544455 und das korrekte Ergebnis sollte ans = 0.71355817782 sein. Kann mir jemand helfen zu überprüfen, was das Problem mit meinen Codes ist?

7
Jassy.W

Sie sind gar nicht so weit weg, aber denken Sie daran, dass Sie den Durchschnittswert von N Summen verwenden, wobei N = 2 (in diesem Fall). So könnte Ihr Code lesen:

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))

Ich denke, es ist ein bisschen klarer, wenn Sie bei np.sum() bleiben. Außerdem habe ich 1e-9 in die np.log() eingefügt, um die Möglichkeit zu vermeiden, dass in Ihrer Berechnung ein Log (0) angezeigt wird. Hoffe das hilft!

HINWEIS: Gemäß dem Kommentar von @ Peter ist der Versatz von 1e-9 in der Tat überflüssig, wenn Ihr Epsilon-Wert größer als 0 ist.

13
Dascienz
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))
0
Peter