Як реалізувати функцію Softmax в Python


247

З класу глибокого навчання Udacity , softmax y_i - це просто експоненція, поділена на суму експоненціала всього Y-вектора:

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

Де S(y_i)функція софтмакса 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)

який дає такий же вихід, як і перша реалізація , навіть незважаючи на те, що перша реалізація явно приймає різницю кожного стовпця та max, а потім ділиться на суму.

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

Чи реалізація схожа за кодом та часовою складністю? Що є більш ефективним?


6
Мені цікаво, чому ви намагалися реалізувати це таким чином за допомогою функції max. Що змусило вас так подумати?
BBischof

1
Я не знаю, я думав, що трактування максимуму як 0 і щось подібне переміщенню графіка вліво, а кліп на 0 допомагає. Тоді мій діапазон сортується від -inf to +infдо -inf to 0. Гадаю, я переосмислив. hahahaaa
alvas

1
У мене є ще одне під) питання, на яке, здається, не відповіли нижче. Яке значення має axis = 0запропонована відповідь Udacity?
Parva Thakkar

3
якщо ви подивитеся на документацію numpy, вона обговорює, яку суму (x, ось = 0) - і аналогічно ось = 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)) / sum (e ^ (x - max (x)), використовуючи ^ (b - c) = (a ^ b) / (a ​​^ в) маємо, = 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)) (фіксуєте знак після визначення значення). Якщо всі ваші значення нижче нуля і дуже великі за своїм абсолютним значенням, і лише значення (максимальне) близьке до нуля, віднімання максимуму нічого не змінить. Хіба це все ще не було б нестабільним?
Чорно

102

(Ну ... тут багато плутанини, як у питанні, так і у відповідях ...)

Для початку два рішення (тобто ваше та запропонований) не є рівнозначними; вони виявляються еквівалентними лише для особливого випадку масивів 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

Як я вже сказав, для 1-D масиву результатів результати справді однакові:

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=0. Для 1-D масиву сума (лише) рядка та сума всіх елементів мають бути однаковими, отже, ідентичні результати у цьому випадку ...

axisПитання в стороні, ваша реалізація (тобто ваш вибір , щоб відняти максимум першого) насправді краще , ніж запропоноване рішення! Насправді, це рекомендований спосіб реалізації функції softmax - див. Тут обґрунтування (числова стабільність, на яку також вказують деякі інші відповіді тут).


Добре, якщо ви просто говорите про багатовимірний масив. Перше рішення можна легко виправити, додавши axisаргументи і в maxі sum. Однак перша реалізація все-таки краща, оскільки ви можете легко переповнюватись під час прийомуexp
Луї Ян

@LouisYang Я не слідкую; яке "перше" рішення? Який із них не використовується exp? Що більше тут було змінено, крім додавання axisаргументу?
пустельний

Перше рішення стосується рішення від @alvas. Різниця полягає в тому, що у запропонованому рішенні у питанні про Alvas відсутня частина віднімання макс. Це може легко викликати переповнення, наприклад, exp (1000) / (exp (1000) + exp (1001)) vs exp (-1) / (exp (-1) + exp (0)) в математиці однакові, але перший переповниться.
Луї Ян

@LouisYang все ще, не впевнений, що я розумію необхідність вашого коментаря - все це вже чітко розглядалося у відповіді.
пустеля

@LouisYang, будь ласка, не дозволяйте (наступна) популярність потоку обдурити вас, і спробуйте уявити контекст, де пропонувалася власна відповідь: спантеличений ОП (" обидва дають однаковий результат ") і (все-таки!) Прийнята відповідь стверджуючи, що " обидва вірні " (ну, це не так ). Відповідь ніколи не мав на увазі " це найправильніший та найефективніший спосіб обчислення softmax взагалі "; це просто означало виправдати, чому в конкретній обговореній вікторині Udacity два рішення не є рівнозначними.
пустеля

56

Отже, це справді коментар до відповіді пустелі, але я поки що не можу коментувати це через свою репутацію. Як він зазначив, ваша версія є правильною лише в тому випадку, якщо ваш вклад складається з одного зразка. Якщо ваш вклад складається з декількох зразків, це неправильно. Однак рішення пустельних корів теж неправильне. Проблема полягає в тому, що раз він бере одновимірний вхід, а потім 2-мірний. Дозвольте мені це показати вам.

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

Ви можете бачити, що версія дезертирів у цій ситуації провалиться. (Не було б, якби вхід був просто таким, як np.array ([1, 2, 3, 6]).

Тепер ми використовуємо 3 зразки, тому ми використовуємо двовимірний вхід. Наступний х2 не є таким, як приклад із дезертирів.

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 TensorFlow:

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)

6
Це був би пекельний коментар ;-)
Майкл Бенджамін

27
np.exp (z) / np.sum (np.exp (z), ось = 1, Keepdims = True) досягає того ж результату, що і ваша функція softmax. кроки з s непотрібні.
PabTorre

Замість ` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)також повинні працювати.
Дебашиш

2
стільки неправильних / неефективних рішень на цій сторінці. Зробіть собі прихильність і скористайтеся послугами PabTorre
міс Палмер

@PabTorre ти мав на увазі ось = -1? ось = 1 не працюватиме для одновимірного введення
DiehardTheTryhard

36

Я б сказав, що хоча обидва є математичними, правильними щодо впровадження, перший краще. При обчисленні софтмаксу проміжні значення можуть стати дуже великими. Поділ двох великих чисел може бути нестабільно чисельним. У цих записках (зі Стенфорда) згадується трюк нормалізації, який по суті є тим, що ви робите.


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
Коли корисно мати можливість обчислювати софтмакс на матриці, а не на вектор? тобто які моделі виводять матрицю? Чи може він бути ще більш розмірним?
mrgloom

2
ти маєш на увазі перше рішення в "з точки зору числової стійкості, друге рішення є кращим ..."?
Dataman

10

EDIT . Станом на версію 1.2.0, scipy включає софтмакс як спеціальну функцію:

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

Щоб запропонувати альтернативне рішення, розгляньте випадки, коли ваші аргументи надзвичайно великі, такі, що 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))

Щоб вона дорівнювала коду плакатів, вам потрібно додати 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


Тільки майте на увазі, що відповідь стосується дуже конкретної установки, описаної у запитанні; він ніколи не мав на увазі "як обчислити софтмакс взагалі за будь-яких обставин або у форматі даних на ваш смак" ...
пустеля

Я бачу, я це виклав тут, тому що питання стосується "класу глибокого навчання" Udacity ", і це не спрацювало, якщо ви використовуєте Tensorflow для створення своєї моделі. Ваше рішення прохолодне та чисте, але воно працює лише у дуже конкретному сценарії. Все одно, дякую.
Лукас Касагранде


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

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

Ласкаво просимо до SO. Пояснення, як ваш код відповідає на питання, завжди корисне.
Нік

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

0

Я хотів би доповнити трохи більше розуміння проблеми. Тут правильним є віднімання max масиву. Але якщо ви запускаєте код в іншій публікації, ви виявите, що він не дає правильної відповіді, коли масив є двовимірним або більшим розміром.

Тут я даю вам кілька пропозицій:

  1. Щоб отримати макс, спробуйте це зробити по осі x, ви отримаєте 1D масив.
  2. Переформатуйте максимальний масив до оригінальної форми.
  3. Чи отримаєте np.exp експоненціальне значення.
  4. Зробіть np.sum вздовж осі.
  5. Отримати остаточні результати.

Дотримуючись результату, ви отримаєте правильну відповідь, зробивши векторизацію. Оскільки це стосується домашнього завдання коледжу, я не можу розмістити тут точний код, але я хотів би дати більше пропозицій, якщо ви не розумієте.


1
Це не пов’язано з будь-якими домашніми завданнями в коледжі, лише з тестовою вікториною на практиці в неакредитованому курсі, де правильна відповідь надана на наступному кроці ...
пустеля

0

Мета функції softmax - зберегти відношення векторів на відміну від збивання кінцевих точок сигмоїдою як значень насичення (тобто мають тенденцію до +/- 1 (tanh) або від 0 до 1 (logistic)). Це пояснюється тим, що вона зберігає більше інформації про швидкість зміни в кінцевих точках і, таким чином, більше застосовується до нейронних мереж з кодуванням вихідного сигналу 1-з-N (тобто, якщо ми стискаємо кінцеві точки, було б важче диференціювати 1 -of-N клас виводу, тому що ми не можемо сказати, який з них є "найбільшим" чи "найменшим", тому що вони зіпсувалися.); також це робить загальну суму виводу до 1, а ясний переможець буде ближче до 1, тоді як інші числа, близькі один до одного, становитимуть 1 / 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)

0

Ось узагальнене рішення з використанням numpy та порівняння для коректності з tensorflow ans 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 за допомогою tensorflow:

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.]]

0

Функція softmax - це функція активації, яка перетворює числа у ймовірності, які дорівнюють одиниці. Функція softmax виводить вектор, який представляє розподіл ймовірностей списку результатів. Це також основний елемент, який використовується в завданнях класифікації глибокого навчання.

Функція Softmax використовується, коли у нас є кілька класів.

Це корисно для з'ясування класу, у якого є макс. Ймовірність.

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

Він коливається від 0 до 1.

Функція Softmax перетворює logits [2.0, 1.0, 0.1] у ймовірності [0.7, 0.2, 0.1], а ймовірності дорівнюють 1. Logits - це необроблені бали, що виводяться останнім шаром нейронної мережі. До того, як відбудеться активація. Щоб зрозуміти функцію softmax, ми повинні подивитися на вихід (n-1) -го шару.

Функція softmax насправді є функцією arg max. Це означає, що воно повертає не найбільше значення з вхідних даних, а позицію найбільших значень.

Наприклад:

Перед softmax

X = [13, 31, 5]

Після softmax

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.