Cách triển khai chức năng Softmax trong Python


245

Từ lớp học sâu của Udacity , softmax của y_i chỉ đơn giản là số mũ chia cho tổng số mũ của toàn bộ vectơ Y:

nhập mô tả hình ảnh ở đây

Trường hợp S(y_i)là hàm softmax của y_ielà mũ và jlà không. của các cột trong vectơ đầu vào Y.

Tôi đã thử như sau:

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

Trả về:

[ 0.8360188   0.11314284  0.05083836]

Nhưng giải pháp được đề xuất là:

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

mà tạo ra cùng một đầu ra như triển khai đầu tiên , mặc dù việc thực hiện đầu tiên rõ ràng có sự khác biệt của từng cột và tối đa và sau đó chia cho tổng.

Ai đó có thể hiển thị toán học tại sao? Là một cái đúng và cái kia sai?

Là việc thực hiện tương tự về mã và độ phức tạp thời gian? Cái nào hiệu quả hơn?


6
Tôi tò mò tại sao bạn lại cố gắng thực hiện nó theo cách này với chức năng tối đa. Điều gì khiến bạn nghĩ về nó theo cách đó?
BBischof

1
Tôi không biết, tôi nghĩ rằng việc xử lý tối đa là 0 và giống như di chuyển biểu đồ sang trái và clip ở 0 giúp. Sau đó, phạm vi của tôi rút ngắn từ -inf to +infđến -inf to 0. Tôi đoán rằng tôi đã suy nghĩ quá mức. hahahaaa
alvas

1
Tôi vẫn còn một câu hỏi phụ) dường như không được trả lời dưới đây. Tầm quan trọng của axis = 0câu trả lời được đề xuất bởi Udacity là gì?
Parva Thakkar

3
nếu bạn xem tài liệu numpy, nó sẽ thảo luận về tổng (x, trục = 0) - và tương tự trục = 1--. Nói tóm lại, nó cung cấp hướng để tổng hợp một mảng các mảng. Trong trường hợp này, nó bảo nó tính tổng các vectơ. Trong trường hợp này, điều đó tương ứng với mẫu số trong hàm softmax.
BBischof

3
Giống như mọi tuần, có một câu trả lời đúng hơn cho đến khi toán học của tôi không đủ tốt để quyết định ai đúng =) Bất kỳ nhà toán học nào không cung cấp câu trả lời có thể giúp quyết định câu nào đúng?
alvas

Câu trả lời:


137

Cả hai đều đúng, nhưng bạn được ưu tiên từ quan điểm về sự ổn định số.

Bạn bắt đầu với

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

Bằng cách sử dụng thực tế là a ^ (b - c) = (a ^ b) / (a ​​^ c) chúng ta có

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

= e ^ x / sum(e ^ x)

Đó là những gì câu trả lời khác nói. Bạn có thể thay thế max (x) bằng bất kỳ biến nào và nó sẽ hủy bỏ.


4
Định dạng lại câu trả lời của bạn @TrevorM để làm rõ thêm: e ^ (x - max (x)) / sum (e ^ (x - max (x)) bằng cách sử dụng a ^ (b - c) = (a ^ b) / (a ​​^ c) chúng tôi có, = e ^ x / {e ^ max (x) * sum (e ^ x / e ^ max (x))} = e ^ x / sum (e ^ x)
shanky_thebearer

5
@Trevor Merrifield, tôi không nghĩ cách tiếp cận đầu tiên có bất kỳ "thuật ngữ không cần thiết" nào. Trong thực tế, nó là tốt hơn so với cách tiếp cận thứ hai. Tôi đã thêm điểm này như một câu trả lời riêng biệt.
Shagun Sodhani

6
@Shagun Bạn nói đúng. Hai cái này tương đương về mặt toán học nhưng tôi đã không tính đến sự ổn định về số.
Trevor Merrifield

Hy vọng bạn không phiền: Tôi đã chỉnh sửa "thuật ngữ không cần thiết" trong trường hợp mọi người không đọc các bình luận (hoặc các bình luận biến mất). Trang này nhận được khá nhiều lưu lượng truy cập từ các công cụ tìm kiếm và đây hiện là câu trả lời đầu tiên mọi người nhìn thấy.
Alex Riley

Tôi tự hỏi tại sao bạn trừ max (x) chứ không phải max (abs (x)) (sửa dấu sau khi xác định giá trị). Nếu tất cả các giá trị của bạn dưới 0 và rất lớn trong giá trị tuyệt đối của chúng và chỉ có giá trị (tối đa) gần bằng 0, trừ đi tối đa sẽ không thay đổi bất cứ điều gì. Nó sẽ không ổn định về số lượng chứ?
Cerno

101

(Chà ... nhiều nhầm lẫn ở đây, cả trong câu hỏi và câu trả lời ...)

Để bắt đầu, hai giải pháp (tức là của bạn và giải pháp được đề xuất) không tương đương nhau; họ xảy ra là tương đương chỉ dành cho các trường hợp đặc biệt của mảng số 1-D. Bạn sẽ phát hiện ra nó nếu bạn đã thử cả mảng điểm 2-D trong bài kiểm tra Udacity được cung cấp.

Kết quả khôn ngoan, sự khác biệt thực tế duy nhất giữa hai giải pháp là axis=0đối số. Để thấy rằng đây là trường hợp, hãy thử giải pháp của bạn ( your_softmax) và một trong đó sự khác biệt duy nhất là axisđối số:

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

Như tôi đã nói, đối với mảng điểm 1-D, kết quả thực sự giống hệt nhau:

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)

Tuy nhiên, đây là kết quả cho mảng điểm 2 chiều được đưa ra trong bài kiểm tra Udacity làm ví dụ kiểm tra:

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

Các kết quả khác nhau - cái thứ hai thực sự giống hệt với cái được mong đợi trong bài kiểm tra Udacity, trong đó tất cả các cột thực sự bằng 1, không phải là trường hợp có kết quả đầu tiên (sai).

Vì vậy, tất cả sự ồn ào thực sự là cho một chi tiết thực hiện - axisđối số. Theo tài liệu của numpy.sum :

Mặc định, trục = Không, sẽ tổng hợp tất cả các phần tử của mảng đầu vào

trong khi ở đây chúng tôi muốn tổng hợp hàng khôn ngoan, do đó axis=0. Đối với mảng 1-D, tổng của hàng (chỉ) và tổng của tất cả các phần tử xảy ra giống hệt nhau, do đó kết quả giống hệt của bạn trong trường hợp đó ...

Các axisvấn đề sang một bên, thực hiện của bạn (ví dụ: bạn lựa chọn để trừ tối đa đầu tiên) là thực sự tốt hơn so với các giải pháp đề nghị! Trên thực tế, đó là cách được khuyến nghị để thực hiện chức năng softmax - xem ở đây để biết cách biện minh (tính ổn định số, cũng được chỉ ra bởi một số câu trả lời khác ở đây).


Vâng, nếu bạn chỉ nói về mảng đa chiều. Giải pháp đầu tiên có thể dễ dàng được sửa bằng cách thêm axisđối số cho cả hai maxsum. Tuy nhiên, việc triển khai đầu tiên vẫn tốt hơn vì bạn có thể dễ dàng tràn khi thực hiệnexp
Louis Yang

@LouisYang Tôi không theo dõi; giải pháp "đầu tiên" là gì? Cái nào không dùng exp? Những gì đã được sửa đổi ở đây ngoài việc thêm một axisđối số?
Sahnaut

Giải pháp đầu tiên đề cập đến giải pháp từ @alvas. Sự khác biệt là giải pháp được đề xuất trong câu hỏi của alvas thiếu phần trừ tối đa. Điều này có thể dễ dàng gây ra tràn, ví dụ: exp (1000) / (exp (1000) + exp (1001)) so với exp (-1) / (exp (-1) + exp (0)) giống nhau trong toán học nhưng đầu tiên sẽ tràn.
Louis Yang

@LouisYang vẫn không chắc là tôi hiểu sự cần thiết của bình luận của bạn - tất cả điều này đã được giải quyết rõ ràng trong câu trả lời.
Sahnaut

@LouisYang xin đừng để sự phổ biến (tiếp theo) của chủ đề đánh lừa bạn và cố gắng tưởng tượng bối cảnh nơi câu trả lời của chính họ được đưa ra: một OP khó hiểu (" cả hai đều cho kết quả giống nhau ") và câu trả lời được chấp nhận (vẫn!) tuyên bố rằng " cả hai đều đúng " (tốt, họ không ). Câu trả lời không bao giờ có nghĩa là " đó là cách chính xác và hiệu quả nhất để tính toán softmax nói chung "; nó chỉ có nghĩa là để giải thích tại sao , trong bài kiểm tra cụ thể về độ bền được thảo luận, 2 giải pháp không tương đương.
sa mạc

56

Vì vậy, đây thực sự là một bình luận cho câu trả lời của Sahnaut nhưng tôi chưa thể bình luận về nó vì danh tiếng của tôi. Như ông đã chỉ ra, phiên bản của bạn chỉ đúng nếu đầu vào của bạn bao gồm một mẫu duy nhất. Nếu đầu vào của bạn bao gồm một số mẫu, nó là sai. Tuy nhiên, giải pháp của Sahnaut cũng sai. Vấn đề là một khi anh ta lấy đầu vào 1 chiều và sau đó anh ta lấy đầu vào 2 chiều. Hãy để tôi chỉ cho bạn điều này.

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

Hãy lấy ví dụ về sa mạc:

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

Đây là đầu ra:

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

Bạn có thể thấy rằng phiên bản desernauts sẽ thất bại trong tình huống này. (Sẽ không nếu đầu vào chỉ là một chiều như np.array ([1, 2, 3, 6]).

Bây giờ cho phép sử dụng 3 mẫu vì đó là lý do tại sao chúng tôi sử dụng đầu vào 2 chiều. X2 sau đây không giống với ví dụ từ desernauts.

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

Đầu vào này bao gồm một lô với 3 mẫu. Nhưng mẫu một và ba về cơ bản là giống nhau. Bây giờ chúng tôi mong đợi 3 hàng kích hoạt softmax trong đó đầu tiên phải giống với thứ ba và cũng giống như kích hoạt x1 của chúng tôi!

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

Tôi hy vọng bạn có thể thấy rằng đây chỉ là trường hợp với giải pháp của tôi.

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

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

Ngoài ra, đây là kết quả của việc thực hiện softmax của 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})

Và kết quả:

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
Đó sẽ là một địa ngục của một bình luận ;-)
Michael Benjamin

27
np.bao (z) / np.sum (np.bao (z), trục = 1, keepdims = True) đạt kết quả tương tự như hàm softmax của bạn. các bước với s là không cần thiết.
YAMTorre

Ở nơi của tôi s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)cũng nên làm việc.
Debashish

2
rất nhiều giải pháp không chính xác / không hiệu quả trên trang này. Làm cho mình một ưu tiên và sử dụng ChihuahuaTorre
Miss Palmer

@PabTorre có nghĩa là trục = -1? trục = 1 sẽ không hoạt động cho đầu vào một chiều
DiehardTheTryhard

36

Tôi sẽ nói rằng trong khi cả hai đều đúng về mặt toán học, thực thi, thì điều đầu tiên là tốt hơn. Khi tính toán softmax, các giá trị trung gian có thể trở nên rất lớn. Chia hai số lớn có thể không ổn định về số lượng. Những ghi chú (từ Stanford) đề cập đến một thủ thuật bình thường hóa mà về cơ bản là những gì bạn đang làm.


3
Những ảnh hưởng của việc hủy bỏ thảm khốc có thể được đánh giá thấp.
Cesar

24

sklearn cũng cung cấp triển khai 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
Làm thế nào chính xác điều này trả lời câu hỏi cụ thể, đó là về bản thân việc triển khai chứ không phải về tính khả dụng trong một số thư viện của bên thứ ba?
sa mạc

8
Tôi đang tìm kiếm một triển khai của bên thứ ba để xác minh kết quả của cả hai phương pháp. Đây là cách nhận xét này giúp.
Eugenio F. Martinez Pacheco

13

Từ quan điểm toán học cả hai bên đều bằng nhau.

Và bạn có thể dễ dàng chứng minh điều này. Hãy m=max(x). Bây giờ hàm của bạn softmaxtrả về một vectơ, có tọa độ thứ i bằng

nhập mô tả hình ảnh ở đây

lưu ý rằng điều này hoạt động với bất kỳ m, bởi vì đối với tất cả các số (thậm chí phức tạp)e^m != 0

  • từ quan điểm phức tạp tính toán, chúng cũng tương đương và cả hai chạy theo O(n)thời gian, trong đó nkích thước của một vectơ.

  • từ quan điểm ổn định số , giải pháp đầu tiên được ưa thích, bởi vì e^xphát triển rất nhanh và ngay cả đối với các giá trị khá nhỏ của xnó sẽ tràn. Trừ đi giá trị tối đa cho phép thoát khỏi tràn này. Để thực tế trải nghiệm những thứ tôi đã nói về việc cố gắng cung cấp cho x = np.array([1000, 5])cả hai chức năng của bạn. Một sẽ trả về xác suất chính xác, thứ hai sẽ tràn vớinan

  • giải pháp của bạn chỉ hoạt động cho các vectơ (câu đố Udacity muốn bạn tính toán nó cho ma trận). Để khắc phục, bạn cần sử dụngsum(axis=0)


1
Khi nó hữu ích để có thể tính toán softmax trên ma trận chứ không phải trên vector? tức là mô hình đầu ra ma trận gì? Nó có thể thậm chí nhiều chiều hơn?
mrgloom

2
bạn có nghĩa là giải pháp đầu tiên trong "từ quan điểm ổn định số, giải pháp thứ hai được ưa thích ..."?
Dataman

10

CHỈNH SỬA . Kể từ phiên bản 1.2.0, scipy bao gồm softmax như một chức năng đặc biệt:

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

Tôi đã viết một hàm áp dụng softmax trên bất kỳ trục nào:

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

Trừ tối đa, như những người dùng khác mô tả, là một thực hành tốt. Tôi đã viết một bài chi tiết về nó ở đây .


9

Ở đây bạn có thể tìm hiểu tại sao họ sử dụng - max.

Từ đó:

"Khi bạn đang viết mã để tính toán hàm Softmax trong thực tế, các thuật ngữ trung gian có thể rất lớn do số mũ. Việc chia số lớn có thể không ổn định về số, vì vậy điều quan trọng là sử dụng thủ thuật chuẩn hóa."



4

Để đưa ra một giải pháp thay thế, hãy xem xét các trường hợp trong đó các đối số của bạn có cường độ cực lớn như vậy exp(x)sẽ tràn vào (trong trường hợp tiêu cực) hoặc tràn (trong trường hợp tích cực). Ở đây bạn muốn duy trì trong không gian nhật ký càng lâu càng tốt, chỉ cấp số nhân ở cuối nơi bạn có thể tin tưởng rằng kết quả sẽ được xử lý tốt.

import scipy.special as sc
import numpy as np

def softmax(x: np.ndarray) -> np.ndarray:
    return np.exp(x - sc.logsumexp(x))

Để làm cho nó bằng với mã áp phích, bạn cần thêm axis=0làm đối số logsumexp.
Bjorn Lindqvist

Ngoài ra, người ta có thể giải nén các đối số phụ để chuyển sang logumrec.
GulalaxALT

3

Tôi cần một cái gì đó tương thích với đầu ra của một lớp dày đặc từ Tensorflow .

Giải pháp từ @desertnaut không hoạt động trong trường hợp này vì tôi có các lô dữ liệu. Do đó, tôi đã đưa ra một giải pháp khác nên hoạt động trong cả hai trường hợp:

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)

Các kết quả:

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

Tham chiếu: Kéo căng mềm


Chỉ cần nhớ rằng câu trả lời đề cập đến một thiết lập rất cụ thể được mô tả trong câu hỏi; nó không bao giờ có nghĩa là 'làm thế nào để tính toán softmax nói chung trong bất kỳ trường hợp nào, hoặc theo định dạng dữ liệu theo ý thích của bạn' ...
Sahnaut

Tôi hiểu rồi, tôi đã đặt vấn đề này ở đây vì câu hỏi đề cập đến "Lớp học sâu của Udacity" và nó sẽ không hoạt động nếu bạn đang sử dụng Tensorflow để xây dựng mô hình của mình. Giải pháp của bạn là mát mẻ và sạch sẽ nhưng nó chỉ hoạt động trong một kịch bản rất cụ thể. Dẫu sao cũng xin cảm ơn.
Lucas Casagrande


1

Để duy trì sự ổn định về số, nên trừ (x) tối đa. Sau đây là mã cho chức năng 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

Đã trả lời chi tiết trong câu trả lời trên. maxđược trừ để tránh tràn. Tôi đang thêm vào đây một triển khai nữa trong 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

Mọi người dường như đăng giải pháp của họ vì vậy tôi sẽ đăng của tôi:

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

Tôi nhận được kết quả chính xác giống như được nhập 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()

Chào mừng đến với SO. Một lời giải thích về cách mã của bạn trả lời câu hỏi luôn hữu ích.
Nick

1

Dựa trên tất cả các phản hồi và ghi chú CS231n , cho phép tôi tóm tắt:

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

Sử dụng:

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

Đầu ra:

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

Tôi muốn bổ sung thêm một chút hiểu biết về vấn đề này. Đây là chính xác của việc trừ tối đa của mảng. Nhưng nếu bạn chạy mã trong bài đăng khác, bạn sẽ thấy nó không cho bạn câu trả lời đúng khi mảng có kích thước 2D hoặc cao hơn.

Ở đây tôi cho bạn một số gợi ý:

  1. Để đạt tối đa, hãy thử thực hiện dọc theo trục x, bạn sẽ nhận được một mảng 1D.
  2. Định hình lại mảng tối đa của bạn về hình dạng ban đầu.
  3. Làm np.Ex nhận giá trị theo cấp số nhân.
  4. Làm np.sum dọc trục.
  5. Nhận kết quả cuối cùng.

Thực hiện theo kết quả, bạn sẽ nhận được câu trả lời chính xác bằng cách thực hiện vector hóa. Vì nó liên quan đến bài tập về trường đại học, tôi không thể đăng mã chính xác ở đây, nhưng tôi muốn đưa ra nhiều gợi ý hơn nếu bạn không hiểu.


1
Nó không liên quan đến bất kỳ bài tập về nhà đại học nào, chỉ liên quan đến một bài kiểm tra thực hành chưa được phân loại trong một khóa học không được công nhận, trong đó câu trả lời đúng được cung cấp trong bước tiếp theo ...
Sahnaut

0

Mục đích của hàm softmax là bảo toàn tỷ lệ của các vectơ trái ngược với việc nén các điểm cuối bằng một sigmoid dưới dạng các giá trị bão hòa (nghĩa là có xu hướng +/- 1 (tanh) hoặc từ 0 đến 1 (hậu cần)). Điều này là do nó bảo tồn nhiều thông tin hơn về tốc độ thay đổi ở các điểm cuối và do đó có thể áp dụng nhiều hơn cho các mạng lưới thần kinh với Mã hóa đầu ra 1-N (nghĩa là nếu chúng ta đè bẹp các điểm cuối sẽ khó phân biệt điểm 1 hơn lớp đầu ra của -of-N bởi vì chúng ta không thể biết cái nào là "lớn nhất" hay "nhỏ nhất" bởi vì chúng bị cắt xén.); ngoài ra, nó làm cho tổng đầu ra là 1 và người chiến thắng rõ ràng sẽ gần hơn 1 trong khi các số khác gần nhau sẽ tổng bằng 1 / p, trong đó p là số nơ ron đầu ra có giá trị tương tự.

Mục đích của việc trừ giá trị tối đa khỏi vectơ là khi bạn thực hiện các số mũ, bạn có thể nhận được giá trị rất cao mà cắt phao ở giá trị tối đa dẫn đến hòa, không phải là trường hợp trong ví dụ này. Điều này trở thành một vấn đề LỚN nếu bạn trừ đi giá trị tối đa để tạo số âm, sau đó bạn có số mũ âm làm thu nhỏ nhanh chóng các giá trị làm thay đổi tỷ lệ, đó là điều xảy ra trong câu hỏi của người đăng và đưa ra câu trả lời không chính xác.

Câu trả lời được cung cấp bởi Udacity là HORRIBLY không hiệu quả. Điều đầu tiên chúng ta cần làm là tính toán e ^ y_j cho tất cả các thành phần vectơ, KIẾM GIÁ TRỊ, sau đó tổng hợp chúng và chia. Trường hợp Udacity rối tung là họ tính toán e ^ y_j TWICE !!! Đây là câu trả lời đúng:

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

Mục tiêu là đạt được kết quả tương tự bằng cách sử dụng Numpy và Tensorflow. Thay đổi duy nhất từ ​​câu trả lời ban đầu là axistham số cho np.sumapi.

Cách tiếp cận ban đầu : axis=0- Tuy nhiên, điều này không cung cấp kết quả dự định khi kích thước là N.

Cách tiếp cận được sửa đổi : axis=len(e_x.shape)-1- Luôn tính tổng theo chiều cuối cùng. Điều này cung cấp kết quả tương tự như chức năng softmax của tenorflow.

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

Đây là giải pháp tổng quát bằng cách sử dụng numpy và so sánh cho chính xác với scipy ans dòng chảy:

Chuẩn bị dữ liệu:

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)

Đầu ra:

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

Softmax sử dụng tenorflow:

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

Đầu ra:

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 sử dụng 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))

Đầu ra:

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 sử dụng 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))

Đầu ra:

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

Hàm softmax là một hàm kích hoạt biến các số thành xác suất tổng hợp thành một. Hàm softmax đưa ra một vectơ biểu thị phân phối xác suất của danh sách kết quả. Nó cũng là một yếu tố cốt lõi được sử dụng trong các nhiệm vụ phân loại học tập sâu.

Hàm Softmax được sử dụng khi chúng ta có nhiều lớp.

Nó rất hữu ích cho việc tìm ra lớp có max. Xác suất.

Hàm Softmax được sử dụng lý tưởng trong lớp đầu ra, trong đó chúng ta thực sự đang cố gắng đạt được xác suất để xác định lớp của mỗi đầu vào.

Nó dao động từ 0 đến 1.

Hàm Softmax biến các bản ghi [2.0, 1.0, 0.1] thành xác suất [0,7, 0,2, 0,1] và tổng xác suất thành 1. Các bản ghi là đầu ra điểm số thô của lớp cuối cùng của mạng thần kinh. Trước khi kích hoạt diễn ra. Để hiểu chức năng softmax, chúng ta phải nhìn vào đầu ra của lớp thứ (n-1).

Trên thực tế, hàm softmax là hàm arg max. Điều đó có nghĩa là nó không trả về giá trị lớn nhất từ ​​đầu vào, mà là vị trí của các giá trị lớn nhất.

Ví dụ:

Trước khi mềm

X = [13, 31, 5]

Sau khi mềm

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

Mã số:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.