Как реализовать функцию Softmax в Python

247

Из класса глубокого обучения Udacity , softmax у_i - это просто экспонента, деленная на сумму экспоненты всего вектора Y:

введите описание изображения здесь

Где S(y_i)функция softmax y_iи eэкспоненциальная, а jнет. столбцов во входном векторе Y.

Я пробовал следующее:

import numpy as np

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum()

scores = [3.0, 1.0, 0.2]
print(softmax(scores))

который возвращает:

[ 0.8360188   0.11314284  0.05083836]

Но предлагаемое решение было:

def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    return np.exp(x) / np.sum(np.exp(x), axis=0)

который выдает тот же результат, что и первая реализация , хотя первая реализация явно принимает разность каждого столбца и максимума, а затем делит на сумму.

Может кто-то математически показать, почему? Один правильный, а другой неправильный?

Схожи ли реализация с точки зрения сложности кода и времени? Что является более эффективным?

Alvas
источник
6
Мне любопытно, почему вы попытались реализовать это таким образом с помощью функции max. Что заставило вас думать об этом таким образом?
BBischof
1
Я не знаю, я думал, что обработка максимума как 0 и что-то вроде перемещения графика влево и отсечения в 0 помогает. Тогда мой диапазон как бы сокращается от -inf to +infдо -inf to 0. Я думаю, что я переосмыслил. hahahaaa
Alvas
1
У меня все еще есть один подпункт) вопросов, который, кажется, не ответил ниже. Какое значение axis = 0в предложенном ответе от Udacity?
Парва Таккар
3
Если вы посмотрите на пустую документацию, в ней обсуждается, что делает сумма (x, axis = 0) - и аналогично axis = 1 -. Короче говоря, он обеспечивает направление суммирования массива. В этом случае он говорит, что нужно суммировать по векторам. В этом случае это соответствует знаменателям в функции softmax.
BBischof
3
Как и каждую вторую неделю, есть более правильный ответ до того момента, когда моя математика не достаточно хороша, чтобы решить, кто является правильным =) Любой математик, который не дал ответа, может помочь решить, какой из них правильный?
alvas

Ответы:

137

Они оба верны, но ваш предпочтен с точки зрения численной стабильности.

Вы начинаете с

e ^ (x - max(x)) / sum(e^(x - max(x))

Используя тот факт, что a ^ (b - c) = (a ^ b) / (a ​​^ c) мы имеем

= e ^ x / (e ^ max(x) * sum(e ^ x / e ^ max(x)))

= e ^ x / sum(e ^ x)

Вот что говорит другой ответ. Вы можете заменить max (x) на любую переменную, и она будет отменена.

Тревор Меррифилд
источник
4
Переформатирование вашего ответа @TrevorM для дальнейшего уточнения: e ^ (x - max (x)) / сумма (e ^ (x - max (x)), используя ^ (b - c) = (a ^ b) / (a ​​^ c) мы имеем, = e ^ x / {e ^ max (x) * sum (e ^ x / e ^ max (x))} = e ^ x / sum (e ^ x)
shanky_thebearer
5
@Trevor Merrifield, я не думаю, что первый подход получил какой-либо «ненужный термин». На самом деле это лучше, чем второй подход. Я добавил этот пункт в качестве отдельного ответа.
Шагун Содхани
6
@ Shagun Вы правы. Эти два математически эквивалентны, но я не учел числовую стабильность.
Тревор Меррифилд
Надеюсь, вы не возражаете: я отредактировал «ненужный термин» на тот случай, если люди не читают комментарии (или комментарии исчезают). Эта страница получает довольно много трафика от поисковых систем, и в настоящее время это первый ответ, который видят люди.
Алекс Райли
Интересно, почему вы вычитаете max (x), а не max (abs (x)) (исправьте знак после определения значения). Если все ваши значения ниже нуля и очень велики по абсолютному значению, а единственное значение (максимум) близко к нулю, вычитание максимума ничего не изменит. Разве это не будет все еще численно нестабильным?
Cerno
103

(Ну ... здесь много путаницы, как в вопросе, так и в ответах ...)

Начнем с того, что два решения (то есть ваше и предложенное) не эквивалентны; они случаются эквивалентным только для частного случая 1-D бигованных массивов. Вы бы обнаружили это, если бы попробовали также двумерный массив очков в представленном примере теста Udacity.

С точки зрения результатов, единственное фактическое различие между двумя решениями - это axis=0аргумент. Чтобы увидеть, что это так, давайте попробуем ваше решение ( your_softmax), и единственное, где различие заключается в axisаргументе:

import numpy as np

# your solution:
def your_softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum()

# correct solution:
def softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=0) # only difference

Как я уже сказал, для одномерного массива результатов результаты действительно идентичны:

scores = [3.0, 1.0, 0.2]
print(your_softmax(scores))
# [ 0.8360188   0.11314284  0.05083836]
print(softmax(scores))
# [ 0.8360188   0.11314284  0.05083836]
your_softmax(scores) == softmax(scores)
# array([ True,  True,  True], dtype=bool)

Тем не менее, вот результаты для двумерного массива оценок, приведенного в тесте Udacity в качестве тестового примера:

scores2D = np.array([[1, 2, 3, 6],
                     [2, 4, 5, 6],
                     [3, 8, 7, 6]])

print(your_softmax(scores2D))
# [[  4.89907947e-04   1.33170787e-03   3.61995731e-03   7.27087861e-02]
#  [  1.33170787e-03   9.84006416e-03   2.67480676e-02   7.27087861e-02]
#  [  3.61995731e-03   5.37249300e-01   1.97642972e-01   7.27087861e-02]]

print(softmax(scores2D))
# [[ 0.09003057  0.00242826  0.01587624  0.33333333]
#  [ 0.24472847  0.01794253  0.11731043  0.33333333]
#  [ 0.66524096  0.97962921  0.86681333  0.33333333]]

Результаты разные - второй действительно идентичен ожидаемому в викторине Udacity, где все столбцы действительно равны 1, что не относится к первому (неправильному) результату.

Таким образом, вся суета была на самом деле за детали реализации - axisаргумент. Согласно документации numpy.sum :

По умолчанию axis = None будет суммировать все элементы входного массива

в то время как здесь мы хотим суммировать построчно, следовательно axis=0. Для одномерного массива сумма (только) строки и сумма всех элементов оказываются идентичными, следовательно, в этом случае ваши идентичные результаты ...

Если axisоставить в стороне проблему, ваша реализация (т. Е. Ваш выбор сначала вычесть максимум) на самом деле лучше предложенного решения! Фактически, это рекомендуемый способ реализации функции softmax - см. Здесь обоснование (числовая стабильность, также указанная некоторыми другими ответами здесь).

desertnaut
источник
Хорошо, если вы просто говорите о многомерном массиве. Первое решение можно легко исправить, добавив axisаргумент к обоим maxи sum. Тем не менее, первая реализация еще лучше , так как вы можете легко переполнение при приемеexp
Луи Ян
@LouisYang Я не подписан; какое «первое» решение? Какой из них не использует exp? Что еще было изменено здесь, кроме добавления axisаргумента?
пустынен
Первое решение относится к решению от @alvas. Разница в том, что в предложенном решении в вопросе Алваша отсутствует часть вычитания макс. Это может легко вызвать переполнение, например, exp (1000) / (exp (1000) + exp (1001)) против exp (-1) / (exp (-1) + exp (0)) одинаковы в математике, но первый переполнится.
Луи Ян
@LouisYang до сих пор, не уверен, что я понимаю необходимость вашего комментария - все это уже было четко указано в ответе.
пустынен
@LouisYang, пожалуйста, не позволяйте (последующей) популярности этой темы обмануть вас, и попробуйте представить контекст, в котором был предложен собственный ответ: озадаченный ОП (« оба дают одинаковый результат ») и (все еще!) Принятый ответ утверждая, что « оба верны » (ну, они не так ). Никогда не предполагалось, что ответом будет « это самый правильный и эффективный способ вычисления softmax в целом »; это просто означало оправдать, почему в обсуждаемом конкретном тесте Udacity эти 2 решения не эквивалентны.
пустынен
56

Итак, это действительно комментарий к ответу десернаута, но я пока не могу его комментировать из-за своей репутации. Как он указал, ваша версия верна только в том случае, если ваш вклад состоит из одного образца. Если ваш вход состоит из нескольких образцов, это неправильно. Однако решение пустынетаут также неверно. Проблема состоит в том, что, как только он берет одномерный ввод, а затем он берет двумерный ввод. Позвольте мне показать это вам.

import numpy as np

# your solution:
def your_softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum()

# desertnaut solution (copied from his answer): 
def desertnaut_softmax(x):
    """Compute softmax values for each sets of scores in x."""
    e_x = np.exp(x - np.max(x))
    return e_x / e_x.sum(axis=0) # only difference

# my (correct) solution:
def softmax(z):
    assert len(z.shape) == 2
    s = np.max(z, axis=1)
    s = s[:, np.newaxis] # necessary step to do broadcasting
    e_x = np.exp(z - s)
    div = np.sum(e_x, axis=1)
    div = div[:, np.newaxis] # dito
    return e_x / div

Давайте возьмем пример пустынных:

x1 = np.array([[1, 2, 3, 6]]) # notice that we put the data into 2 dimensions(!)

Это вывод:

your_softmax(x1)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

desertnaut_softmax(x1)
array([[ 1.,  1.,  1.,  1.]])

softmax(x1)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

Вы можете видеть, что версия desernauts потерпит неудачу в этой ситуации. (Не было бы, если бы ввод был только одномерный, как np.array ([1, 2, 3, 6]).

Теперь давайте используем 3 сэмпла, поэтому мы используем двумерный ввод. Следующий x2 не совпадает с примером из примера desernauts.

x2 = np.array([[1, 2, 3, 6],  # sample 1
               [2, 4, 5, 6],  # sample 2
               [1, 2, 3, 6]]) # sample 1 again(!)

Этот вход состоит из партии с 3 образцами. Но образец один и три по сути одинаковы. Теперь мы ожидаем 3 ряда активаций softmax, где первый должен совпадать с третьим, а также с нашей активацией x1!

your_softmax(x2)
array([[ 0.00183535,  0.00498899,  0.01356148,  0.27238963],
       [ 0.00498899,  0.03686393,  0.10020655,  0.27238963],
       [ 0.00183535,  0.00498899,  0.01356148,  0.27238963]])


desertnaut_softmax(x2)
array([[ 0.21194156,  0.10650698,  0.10650698,  0.33333333],
       [ 0.57611688,  0.78698604,  0.78698604,  0.33333333],
       [ 0.21194156,  0.10650698,  0.10650698,  0.33333333]])

softmax(x2)
array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037047],
       [ 0.01203764,  0.08894682,  0.24178252,  0.65723302],
       [ 0.00626879,  0.01704033,  0.04632042,  0.93037047]])

Я надеюсь, вы видите, что это только в моем решении.

softmax(x1) == softmax(x2)[0]
array([[ True,  True,  True,  True]], dtype=bool)

softmax(x1) == softmax(x2)[2]
array([[ True,  True,  True,  True]], dtype=bool)

Кроме того, вот результаты реализации softmax TensorFlows:

import tensorflow as tf
import numpy as np
batch = np.asarray([[1,2,3,6],[2,4,5,6],[1,2,3,6]])
x = tf.placeholder(tf.float32, shape=[None, 4])
y = tf.nn.softmax(x)
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(y, feed_dict={x: batch})

И результат:

array([[ 0.00626879,  0.01704033,  0.04632042,  0.93037045],
       [ 0.01203764,  0.08894681,  0.24178252,  0.657233  ],
       [ 0.00626879,  0.01704033,  0.04632042,  0.93037045]], dtype=float32)
ChuckFive
источник
6
Это был бы один адский комментарий ;-)
Майкл Бенджамин
27
np.exp (z) / np.sum (np.exp (z), axis = 1, keepdims = True) достигает того же результата, что и ваша функция softmax. шаги с s не нужны.
PabTorre
На месте ` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)также должно работать.
Debashish
2
так много неправильных / неэффективных решений на этой странице. Сделайте себе одолжение и используйте PabTorre's
мисс Палмер
@PabTorre ты имел ввиду ось = -1? Ось = 1 не будет работать для одномерного ввода
DiehardTheTryhard
36

Я бы сказал, что хотя оба математически верны, с точки зрения реализации, первый лучше. При вычислении softmax промежуточные значения могут стать очень большими. Деление двух больших чисел может быть численно нестабильным. В этих заметках (из Стэнфорда) упоминается трюк нормализации, который, по сути, то, что вы делаете.

Шагун Содхани
источник
3
Последствия катастрофической отмены нельзя недооценивать.
Сезар
24

Sklearn также предлагает реализацию Softmax

from sklearn.utils.extmath import softmax
import numpy as np

x = np.array([[ 0.50839931,  0.49767588,  0.51260159]])
softmax(x)

# output
array([[ 0.3340521 ,  0.33048906,  0.33545884]]) 
Роман Орак
источник
3
Как именно это отвечает на конкретный вопрос, касающийся самой реализации , а не наличия какой-либо сторонней библиотеки?
пустынен
8
Я искал стороннюю реализацию для проверки результатов обоих подходов. Вот как этот комментарий помогает.
Эухенио Ф. Мартинес Пачеко
13

С математической точки зрения обе стороны равны.

И вы можете легко доказать это. Давай m=max(x). Теперь ваша функция softmaxвозвращает вектор, i-я координата которого равна

введите описание изображения здесь

обратите внимание, что это работает для любого m, потому что для всех (даже сложных) чиселe^m != 0

  • с точки зрения сложности вычислений они также эквивалентны и оба выполняются во O(n)времени, где nесть размер вектора.

  • с точки зрения числовой устойчивости , первое решение является предпочтительным, потому что e^xрастет очень быстро и даже при довольно небольших значениях xоно будет переполнено. Вычитание максимального значения позволяет избавиться от этого переполнения. Чтобы на практике испытать то, о чем я говорил, попробуйте выполнить x = np.array([1000, 5])обе ваши функции. Один вернет правильную вероятность, второй переполнитсяnan

  • ваше решение работает только для векторов (викторина Udacity хочет, чтобы вы рассчитали его и для матриц). Для того, чтобы это исправить, вам нужно использоватьsum(axis=0)

Сальвадор Дали
источник
1
Когда полезно вычислять softmax по матрице, а не по вектору? т.е. какие модели выходной матрицы? Может ли это быть еще более размерным?
mrgloom
2
Вы имеете в виду первое решение в «с точки зрения численной устойчивости, второе решение является предпочтительным ...»?
Dataman
10

РЕДАКТИРОВАТЬ . Начиная с версии 1.2.0, scipy включает softmax в качестве специальной функции:

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

Я написал функцию, применяющую softmax к любой оси:

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

Вычитание максимума, как описывали другие пользователи, является хорошей практикой. Я написал подробный пост об этом здесь .

Нолан Конавей
источник
9

Здесь вы можете узнать, почему они использовали - max.

Оттуда:

«Когда вы пишете код для вычисления функции Softmax на практике, промежуточные члены могут быть очень большими из-за экспонент. Деление больших чисел может быть численно нестабильным, поэтому важно использовать метод нормализации».

Садег Салехи
источник
4

Более краткая версия:

def softmax(x):
    return np.exp(x) / np.exp(x).sum(axis=0)
Пимин Константин Кефалукос
источник
9
это может привести к арифметическому переполнению
minhle_r7
4

Чтобы предложить альтернативное решение, рассмотрите случаи, когда ваши аргументы чрезвычайно велики по величине, такие exp(x)как недопущение (в отрицательном случае) или переполнение (в положительном случае). Здесь вы хотите оставаться в пространстве журнала как можно дольше, возводя в степень только в конце, где вы можете быть уверены, что результат будет хорошим.

import scipy.special as sc
import numpy as np

def softmax(x: np.ndarray) -> np.ndarray:
    return np.exp(x - sc.logsumexp(x))
PikalaxALT
источник
Чтобы сделать его равным коду постеров, вы должны добавить его axis=0в качестве аргумента logsumexp.
Бьорн Линдквист
Кроме того, можно распаковать дополнительные аргументы для передачи в logsumexp.
PikalaxALT
3

Мне нужно было что-то совместимое с выводом плотного слоя из Tensorflow .

Решение от @desertnaut в этом случае не работает, потому что у меня есть пакеты данных. Поэтому я пришел с другим решением, которое должно работать в обоих случаях:

def softmax(x, axis=-1):
    e_x = np.exp(x - np.max(x)) # same code
    return e_x / e_x.sum(axis=axis, keepdims=True)

Полученные результаты:

logits = np.asarray([
    [-0.0052024,  -0.00770216,  0.01360943, -0.008921], # 1
    [-0.0052024,  -0.00770216,  0.01360943, -0.008921]  # 2
])

print(softmax(logits))

#[[0.2492037  0.24858153 0.25393605 0.24827873]
# [0.2492037  0.24858153 0.25393605 0.24827873]]

Ссылка: Tensorflow softmax

Лукас Касагранде
источник
Просто помните, что ответ относится к очень специфической обстановке, описанной в вопросе; никогда не предполагалось, что это будет «как вычислить softmax в целом при любых обстоятельствах или в формате данных на ваш вкус» ...
desertnaut
Я вижу, я поместил это здесь, потому что вопрос относится к "классу глубокого обучения Udacity", и он не будет работать, если вы используете Tensorflow для построения своей модели. Ваше решение круто и чисто, но оно работает только в очень специфическом сценарии. Спасибо, в любом случае.
Лукас Казагранде
2

Я бы предложил это:

def softmax(z):
    z_norm=np.exp(z-np.max(z,axis=0,keepdims=True))
    return(np.divide(z_norm,np.sum(z_norm,axis=0,keepdims=True)))

Это будет работать как для стохастика, так и для пакета.
Для получения дополнительной информации см .: https://medium.com/@ravish1729/analysis-of-softmax-function-ad058d6a564d.

Равиш Кумар Шарма
источник
1

Чтобы сохранить числовую стабильность, необходимо вычесть max (x). Ниже приведен код для функции softmax;

def softmax (x):

if len(x.shape) > 1:
    tmp = np.max(x, axis = 1)
    x -= tmp.reshape((x.shape[0], 1))
    x = np.exp(x)
    tmp = np.sum(x, axis = 1)
    x /= tmp.reshape((x.shape[0], 1))
else:
    tmp = np.max(x)
    x -= tmp
    x = np.exp(x)
    tmp = np.sum(x)
    x /= tmp


return x
Рахул Ахаджа
источник
1

Уже подробно ответили в приведенных выше ответах. maxвычитается, чтобы избежать переполнения. Я добавляю сюда еще одну реализацию в python3.

import numpy as np
def softmax(x):
    mx = np.amax(x,axis=1,keepdims = True)
    x_exp = np.exp(x - mx)
    x_sum = np.sum(x_exp, axis = 1, keepdims = True)
    res = x_exp / x_sum
    return res

x = np.array([[3,2,4],[4,5,6]])
print(softmax(x))
Debashish
источник
1

Кажется, что все публикуют свое решение, поэтому я опубликую свое:

def softmax(x):
    e_x = np.exp(x.T - np.max(x, axis = -1))
    return (e_x / e_x.sum(axis=0)).T

Я получаю те же результаты, что и импортированные из sklearn:

from sklearn.utils.extmath import softmax
юлианский
источник
1
import tensorflow as tf
import numpy as np

def softmax(x):
    return (np.exp(x).T / np.exp(x).sum(axis=-1)).T

logits = np.array([[1, 2, 3], [3, 10, 1], [1, 2, 5], [4, 6.5, 1.2], [3, 6, 1]])

sess = tf.Session()
print(softmax(logits))
print(sess.run(tf.nn.softmax(logits)))
sess.close()
король
источник
Добро пожаловать в ТАК. Объяснение того, как ваш код отвечает на вопрос, всегда полезно.
Ник
1

Основываясь на всех ответах и примечаниях CS231n , позвольте мне подвести итог:

def softmax(x, axis):
    x -= np.max(x, axis=axis, keepdims=True)
    return np.exp(x) / np.exp(x).sum(axis=axis, keepdims=True)

Использование:

x = np.array([[1, 0, 2,-1],
              [2, 4, 6, 8], 
              [3, 2, 1, 0]])
softmax(x, axis=1).round(2)

Вывод:

array([[0.24, 0.09, 0.64, 0.03],
       [0.  , 0.02, 0.12, 0.86],
       [0.64, 0.24, 0.09, 0.03]])
remykarem
источник
0

Я хотел бы добавить немного больше понимания проблемы. Здесь правильно вычесть максимум из массива. Но если вы запустите код в другом посте, вы обнаружите, что он не дает правильного ответа, когда массив имеет размеры 2D или выше.

Здесь я даю вам несколько советов:

  1. Чтобы получить максимум, попробуйте сделать это вдоль оси X, вы получите одномерный массив.
  2. Измените ваш максимальный массив в исходную форму.
  3. У np.exp получим экспоненциальное значение.
  4. Делай np.sum вдоль оси.
  5. Получите окончательные результаты.

Следуя полученному результату, вы получите правильный ответ, выполнив векторизацию. Поскольку это связано с домашней работой колледжа, я не могу опубликовать точный код здесь, но я хотел бы дать больше советов, если вы не понимаете.

Хао Сюй
источник
1
Это не связано с какой-либо домашней работой в колледже, а только с оценкой практического теста по неаккредитованному курсу, где правильный ответ дается на следующем этапе ...
desertnaut
0

Цель функции softmax состоит в том, чтобы сохранить соотношение векторов, а не сдавливать конечные точки сигмоидом, поскольку значения насыщаются (т. Е. Стремятся к +/- 1 (tanh) или от 0 до 1 (логистический)). Это связано с тем, что он сохраняет больше информации о скорости изменения в конечных точках и, таким образом, более применим к нейронным сетям с выходным кодированием 1 из N (т. Е. Если мы раздавим конечные точки, было бы сложнее дифференцировать 1). выходного класса -N, потому что мы не можем сказать, какой из них является "самым большим" или "самым маленьким", потому что они были сжаты.); также это делает общую выходную сумму равной 1, и чистый победитель будет ближе к 1, в то время как другие числа, которые близки друг к другу, будут суммироваться до 1 / p, где p - число выходных нейронов с аналогичными значениями.

Цель вычитания максимального значения из вектора состоит в том, что когда вы выполняете e ^ y экспоненты, вы можете получить очень высокое значение, которое обрезает число с плавающей точкой при максимальном значении, приводящем к привязке, что не имеет место в этом примере. Это становится БОЛЬШОЙ проблемой, если вы вычитаете максимальное значение, чтобы получить отрицательное число, тогда у вас есть отрицательный показатель, который быстро сжимает значения, изменяющие соотношение, что и произошло в вопросе автора и дало неправильный ответ.

Ответ от Udacity УЖАСНО неэффективен. Первое, что нам нужно сделать, это вычислить e ^ y_j для всех компонент вектора, СОХРАНЯТЬ ЭТИ ЗНАЧЕНИЯ, затем суммировать их и делить. Где Udacity испортил это они вычисляют e ^ y_j ДВАЖДЫ !!! Вот правильный ответ:

def softmax(y):
    e_to_the_y_j = np.exp(y)
    return e_to_the_y_j / np.sum(e_to_the_y_j, axis=0)

источник
0

Цель состояла в том, чтобы достигнуть подобных результатов, используя Numpy и Tensorflow. Единственное отличие от исходного ответа - это axisпараметр для np.sumAPI.

Первоначальный подход : axis=0- Это, однако, не дает ожидаемых результатов, когда измерения равны N.

Модифицированный подход : axis=len(e_x.shape)-1- Всегда суммируйте по последнему измерению. Это обеспечивает результаты, аналогичные функции softmax тензорного потока.

def softmax_fn(input_array):
    """
    | **@author**: Prathyush SP
    |
    | Calculate Softmax for a given array
    :param input_array: Input Array
    :return: Softmax Score
    """
    e_x = np.exp(input_array - np.max(input_array))
    return e_x / e_x.sum(axis=len(e_x.shape)-1)
kingspp
источник
0

Вот обобщенное решение, использующее numpy и сравнение для корректности с tenorflow и scipy:

Подготовка данных:

import numpy as np

np.random.seed(2019)

batch_size = 1
n_items = 3
n_classes = 2
logits_np = np.random.rand(batch_size,n_items,n_classes).astype(np.float32)
print('logits_np.shape', logits_np.shape)
print('logits_np:')
print(logits_np)

Вывод:

logits_np.shape (1, 3, 2)
logits_np:
[[[0.9034822  0.3930805 ]
  [0.62397    0.6378774 ]
  [0.88049906 0.299172  ]]]

Softmax с использованием тензор потока:

import tensorflow as tf

logits_tf = tf.convert_to_tensor(logits_np, np.float32)
scores_tf = tf.nn.softmax(logits_np, axis=-1)

print('logits_tf.shape', logits_tf.shape)
print('scores_tf.shape', scores_tf.shape)

with tf.Session() as sess:
    scores_np = sess.run(scores_tf)

print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)

print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np,axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

Вывод:

logits_tf.shape (1, 3, 2)
scores_tf.shape (1, 3, 2)
scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
  [0.4965232  0.5034768 ]
  [0.64137274 0.3586273 ]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]

Softmax с использованием scipy:

from scipy.special import softmax

scores_np = softmax(logits_np, axis=-1)

print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)

print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np, axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

Вывод:

scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
  [0.4965232  0.5034768 ]
  [0.6413727  0.35862732]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]

Softmax с использованием numpy ( https://nolanbconaway.github.io/blog/2017/softmax-numpy ):

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


scores_np = softmax(logits_np, axis=-1)

print('scores_np.shape', scores_np.shape)
print('scores_np:')
print(scores_np)

print('np.sum(scores_np, axis=-1).shape', np.sum(scores_np, axis=-1).shape)
print('np.sum(scores_np, axis=-1):')
print(np.sum(scores_np, axis=-1))

Вывод:

scores_np.shape (1, 3, 2)
scores_np:
[[[0.62490064 0.37509936]
  [0.49652317 0.5034768 ]
  [0.64137274 0.3586273 ]]]
np.sum(scores_np, axis=-1).shape (1, 3)
np.sum(scores_np, axis=-1):
[[1. 1. 1.]]
mrgloom
источник
0

Функция softmax - это функция активации, которая превращает числа в вероятности, которые в сумме равны единице. Функция softmax выводит вектор, который представляет распределения вероятностей списка результатов. Это также основной элемент, используемый в задачах классификации глубокого обучения.

Функция Softmax используется, когда у нас есть несколько классов.

Это полезно для определения класса, который имеет макс. Вероятность.

Функция Softmax идеально используется в выходном слое, где мы на самом деле пытаемся получить вероятности для определения класса каждого входа.

Он варьируется от 0 до 1.

Функция Softmax превращает логиты [2.0, 1.0, 0.1] в вероятности [0.7, 0.2, 0.1], а вероятности составляют 1. Логиты - это необработанные результаты, полученные последним слоем нейронной сети. До активации происходит. Чтобы понять функцию softmax, мы должны посмотреть на вывод (n-1) -го слоя.

Функция softmax фактически является функцией arg max. Это означает, что он не возвращает наибольшее значение из входных данных, но положение самых больших значений.

Например:

До софтмакс

X = [13, 31, 5]

После софтмакс

array([1.52299795e-08, 9.99999985e-01, 5.10908895e-12]

Код:

import numpy as np

# your solution:

def your_softmax(x): 

"""Compute softmax values for each sets of scores in x.""" 

e_x = np.exp(x - np.max(x)) 

return e_x / e_x.sum() 

# correct solution: 

def softmax(x): 

"""Compute softmax values for each sets of scores in x.""" 

e_x = np.exp(x - np.max(x)) 

return e_x / e_x.sum(axis=0) 

# only difference
Кришна Вир
источник