로부터 Udacity의의 깊은 학습 클래스 , y_i의 softmax를 전체 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)
첫 번째 구현은 명시 적으로 각 열과 최대의 차이를 취한 다음 합계로 나눠도 첫 번째 구현과 동일한 출력 을 생성합니다 .
누군가 수학적으로 이유를 보여줄 수 있습니까? 하나는 정확하고 다른 하나는 잘못입니까?
코드 및 시간 복잡성 측면에서 구현이 유사합니까? 어느 것이 더 효율적입니까?
답변
둘 다 맞지만 수치 안정성의 관점에서 당신이 선호됩니다.
당신은 시작
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)를 임의의 변수로 바꾸면 취소됩니다.
답변
(글쎄 … 질문과 대답 모두에서 많은 혼란이 있습니다 …)
우선 두 가지 솔루션 (예 : 귀하와 제안 된 솔루션)은 동일 하지 않습니다 . 그들은 일어난다 단지 1-D 점수 배열의 특별한 경우에 해당합니다. 제공된 Udacity 퀴즈 예제에서 2 차원 점수 배열을 시도한 경우이를 발견했을 것입니다.
결과적으로 두 솔루션의 실제 차이점은 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
내가 말했듯이 1D 점수 배열의 경우 결과는 실제로 동일합니다.
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 퀴즈에서 테스트 예제로 제공된 2 차원 점수 배열의 결과는 다음과 같습니다.
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
. 1-D 배열의 경우 (전용) 행의 합과 모든 요소의 합이 동일 하므로이 경우 동일한 결과가 발생합니다 …
axis
문제를 제외하고, 구현 (최대 첫째을 뺄 즉, 당신의 선택은) 실제로 더 나은 제안 된 솔루션보다! 실제로, 그것은 softmax 기능을 구현하기 위해 권장되는 방법입니다 . 정당화에 대해서는 여기 를 참조 하십시오 (숫자 안정성, 여기에 다른 답변이 지적함).
답변
따라서 이것은 실제로 desertnaut의 답변에 대한 의견이지만 내 평판으로 인해 아직 댓글을 달 수 없습니다. 그가 지적했듯이 입력이 단일 샘플로 구성된 경우에만 버전이 정확합니다. 입력 값이 여러 샘플로 구성되어 있으면 잘못되었습니다. 그러나 desertnaut의 솔루션도 잘못되었습니다. 문제는 일단 1 차원 입력을받은 다음 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
Desertnauts를 예로 들어 보겠습니다.
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])와 같은 1 차원 인 경우에는 그렇지 않습니다.
이제 2 차원 입력을 사용하는 이유 때문에 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 개의 샘플이 포함 된 배치로 구성됩니다. 그러나 샘플 1과 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)
또한 TensorFlows softmax 구현 결과는 다음과 같습니다.
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)
답변
둘 다 수학적으로, 구현 측면에서는 정확하지만 첫 번째 방법이 더 낫습니다. softmax를 계산할 때 중간 값이 매우 커질 수 있습니다. 두 개의 큰 숫자를 나누면 수치 적으로 불안정 할 수 있습니다.(스탠포드의) 이 노트 는 본질적으로하고있는 정규화 트릭을 언급합니다.
답변
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]])
답변
수학적 관점에서 양측은 동일합니다.
그리고 당신은 이것을 쉽게 증명할 수 있습니다. 하자 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.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
다른 사용자가 설명한 것처럼 최대 값을 빼는 것이 좋습니다. 나는 여기 에 대한 자세한 게시물을 썼습니다 .