5 votes

Fonction Softmax d'un tableau numpy par ligne

J'essaie d'appliquer une fonction softmax à un tableau numpy. Mais je n'obtiens pas les résultats souhaités. Voici le code que j'ai essayé :

 import numpy as np
 x = np.array([[1001,1002],[3,4]])
 softmax = np.exp(x - np.max(x))/(np.sum(np.exp(x - np.max(x)))
 print softmax

Je pense que le x - np.max(x) Le code ne soustrait pas le maximum de chaque ligne. Le maximum doit être soustrait de x pour éviter les très grands nombres.

C'est censé produire

 np.array([
    [0.26894142, 0.73105858],
    [0.26894142, 0.73105858]])

Mais j'y arrive :

np.array([
    [0.26894142, 0.73105858],
    [0, 0]])

7voto

Paul Panzer Points 30707

Un moyen pratique de conserver les axes qui sont consommés par les opérations de "réduction" telles que max o sum es el keepdims mot-clé :

mx = np.max(x, axis=-1, keepdims=True)
mx
# array([[1002],
#        [   4]])
x - mx
# array([[-1,  0],
#        [-1,  0]])
numerator = np.exp(x - mx)
denominator = np.sum(numerator, axis=-1, keepdims=True)
denominator
# array([[ 1.36787944],
#        [ 1.36787944]])
numerator/denominator
# array([[ 0.26894142,  0.73105858],
         [ 0.26894142,  0.73105858]])

3voto

Yibo Yang Points 420

Ma ligne de 5 (qui utilise scipy logsumexp pour les parties délicates) :

def softmax(a, axis=None):
    """
    Computes exp(a)/sumexp(a); relies on scipy logsumexp implementation.
    :param a: ndarray/tensor
    :param axis: axis to sum over; default (None) sums over everything
    """
    from scipy.special import logsumexp
    lse = logsumexp(a, axis=axis)  # this reduces along axis
    if axis is not None:
        lse = np.expand_dims(lse, axis)  # restore that axis for subtraction
    return np.exp(a - lse)

Vous devrez peut-être utiliser from scipy.misc import logsumexp si vous avez une ancienne version de scipy.

2voto

Nolan Conaway Points 945

EDITAR . Depuis la version 1.2.0, scipy inclut softmax comme fonction spéciale :

https://scipy.github.io/devdocs/generated/scipy.special.softmax.html

J'ai écrit une fonction softmax très générale opérant sur un axe arbitraire, y compris le délicat bit de soustraction max. La fonction est ci-dessous, et j'ai écrit un article de blog à ce sujet ici .

def softmax(X, theta = 1.0, axis = None):
    """
    Compute the softmax of each element along an axis of X.

    Parameters
    ----------
    X: ND-Array. Probably should be floats. 
    theta (optional): float parameter, used as a multiplier
        prior to exponentiation. Default = 1.0
    axis (optional): axis to compute values along. Default is the 
        first non-singleton axis.

    Returns an array the same size as X. The result will sum to 1
    along the specified axis.
    """

    # make X at least 2d
    y = np.atleast_2d(X)

    # find axis
    if axis is None:
        axis = next(j[0] for j in enumerate(y.shape) if j[1] > 1)

    # multiply y against the theta parameter, 
    y = y * float(theta)

    # subtract the max for numerical stability
    y = y - np.expand_dims(np.max(y, axis = axis), axis)

    # exponentiate y
    y = np.exp(y)

    # take the sum along the specified axis
    ax_sum = np.expand_dims(np.sum(y, axis = axis), axis)

    # finally: divide elementwise
    p = y / ax_sum

    # flatten if X was 1D
    if len(X.shape) == 1: p = p.flatten()

    return p

1voto

Pranay Aryal Points 2298

En x - np.max(x) Le code ne fait pas de soustraction par ligne. Faisons-le étape par étape. Tout d'abord, nous allons créer un tableau 'maxes' en faisant des tuiles ou une copie de la colonne :

maxes = np.tile(np.max(x,1), (2,1)).T

Cela créera une matrice 2X2 qui correspondra aux maxima pour chaque ligne en faisant un double de la colonne (tuile). Après cela, vous pouvez faire :

 x = np.exp(x - maxes)/(np.sum(np.exp(x - maxes), axis = 1))

Vous devriez obtenir votre résultat avec ceci. Le site axis = 1 est pour le softmax en ligne que vous avez mentionné dans le titre de votre réponse. J'espère que cela vous aidera.

1voto

mario23 Points 322

Que pensez-vous de ça ?

Pour avoir pris max le long des lignes, il suffit de spécifier l'argument comme axis=1 puis convertir le résultat en un vecteur colonne (mais un tableau 2D en fait) en utilisant np.newaxis/None .

In [40]: x
Out[40]: 
array([[1001, 1002],
       [   3,    4]])

In [41]: z = x - np.max(x, axis=1)[:, np.newaxis]

In [42]: z
Out[42]: 
array([[-1,  0],
       [-1,  0]])

In [44]: softmax = np.exp(z) / np.sum(np.exp(z), axis=1)[:, np.newaxis]

In [45]: softmax
Out[45]: 
array([[ 0.26894142,  0.73105858],
       [ 0.26894142,  0.73105858]])

Dans la dernière étape, encore une fois, lorsque vous prenez la somme, spécifiez simplement l'argument axis=1 pour l'additionner le long des lignes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X