วิธีการใช้งานฟังก์ชั่น Softmax ใน Python


247

จากคลาสการเรียนรู้เชิงลึกของ Udacityซอฟต์แม็กซ์ของ y_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)

ซึ่งสร้างเอาต์พุตเดียวกันกับการนำไปใช้ครั้งแรกแม้ว่าการนำไปใช้ครั้งแรกจะใช้ความแตกต่างของแต่ละคอลัมน์และค่าสูงสุดอย่างชัดเจนแล้วหารด้วยผลรวม

บางคนสามารถแสดงเหตุผลทางคณิตศาสตร์ได้ทำไม? ถูกต้องและอีกอันหนึ่งผิด

การใช้งานมีความคล้ายคลึงกันในแง่ของรหัสและความซับซ้อนของเวลาหรือไม่ อันไหนมีประสิทธิภาพมากกว่ากัน?


6
ฉันอยากรู้ว่าทำไมคุณพยายามที่จะใช้มันด้วยวิธีนี้ด้วยฟังก์ชั่นสูงสุด อะไรทำให้คุณคิดในแบบนั้น?
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))

โดยการใช้ความจริงที่ว่าเรามี ^ (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 - สูงสุด (x)) / ผลรวม (e ^ (x - สูงสุด (x)) โดยใช้ ^ (b - c) = (a ^ b) / (a ​​^ c) เรามี = e ^ x / {e ^ max (x) * ผลรวม (e ^ x / e ^ max (x))} = e ^ x / ผลรวม (e ^ x)
shanky_thebearer

5
@ Trevor Merrifield ฉันไม่คิดว่าวิธีแรกจะมี "คำที่ไม่จำเป็น" ในความเป็นจริงมันจะดีกว่าวิธีที่สอง ฉันได้เพิ่มจุดนี้เป็นคำตอบที่แยกจากกัน
Shagun Sodhani

6
@Shagun คุณถูกต้อง ทั้งสองมีความเท่าเทียมกันทางคณิตศาสตร์ แต่ฉันไม่ได้พิจารณาความเสถียรเชิงตัวเลข
Trevor Merrifield

หวังว่าคุณจะไม่รังเกียจ: ฉันแก้ไข "คำที่ไม่จำเป็น" ในกรณีที่คนไม่อ่านความคิดเห็น (หรือความคิดเห็นหายไป) หน้านี้ได้รับอัตราการเข้าชมค่อนข้างมากจากเครื่องมือค้นหาและนี่คือคำตอบแรกที่ผู้คนเห็น
Alex Riley

ฉันสงสัยว่าทำไมคุณลบ max (x) และไม่ใช่ max (abs (x)) (แก้ไขเครื่องหมายหลังจากพิจารณาค่า) หากค่าทั้งหมดของคุณต่ำกว่าศูนย์และมีขนาดใหญ่มากในค่าสัมบูรณ์และเฉพาะค่า (สูงสุด) อยู่ใกล้กับศูนย์การลบค่าสูงสุดจะไม่เปลี่ยนแปลงอะไรเลย มันจะยังคงไม่เสถียรเชิงตัวเลขหรือไม่?
Cerno

102

(เอ่อ ... ความสับสนมากที่นี่ทั้งในคำถามและในคำตอบ ... )

ในการเริ่มต้นโซลูชั่นทั้งสอง (เช่นของคุณและของที่แนะนำ) จะไม่เทียบเท่า พวกเขาเกิดขึ้นจะเทียบเท่าเพียง แต่สำหรับกรณีพิเศษของ 1-D อาร์เรย์คะแนน คุณจะได้ค้นพบมันถ้าคุณลองแถวคะแนน 2-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)

อย่างไรก็ตามนี่คือผลลัพธ์สำหรับอาร์เรย์คะแนน 2 มิติที่กำหนดในแบบทดสอบ 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]]

ผลลัพธ์จะแตกต่างกัน - อันที่สองนั้นเหมือนกันกับแบบที่คาดไว้ในแบบทดสอบความทึบซึ่งคอลัมน์ทั้งหมดรวมกันเป็น 1 ซึ่งไม่ใช่กรณีที่มีผลลัพธ์ (ผิด) ตัวแรก

ดังนั้นเอะอะทั้งหมดนั้นมีไว้สำหรับรายละเอียดการดำเนินการ - axisข้อโต้แย้ง อ้างอิงจากเอกสาร numpy.sum :

ค่าเริ่มต้น Axis = None จะรวมองค์ประกอบทั้งหมดของอาร์เรย์อินพุต

axis=0ในขณะที่ที่นี่เราต้องการที่จะสรุปแถวที่ชาญฉลาดจึง สำหรับอาร์เรย์ 1-D ผลรวมของแถว (เท่านั้น) และผลรวมขององค์ประกอบทั้งหมดจะเหมือนกันดังนั้นผลลัพธ์ที่เหมือนกันของคุณในกรณีนี้ ...

axisปัญหากัน, การดำเนินงานของคุณ (เช่นคุณเลือกที่จะลบครั้งแรกสูงสุด) เป็นจริงดีกว่ากว่าการแก้ปัญหาปัญหา! ในความเป็นจริงมันเป็นวิธีที่แนะนำในการใช้งานฟังก์ชั่น softmax - ดูที่นี่เพื่อเหตุผล (ความมั่นคงเชิงตัวเลขยังชี้ให้เห็นโดยคำตอบอื่น ๆ


ถ้าคุณพูดถึงอาร์เรย์หลายมิติ วิธีการแก้ปัญหาแรกที่สามารถแก้ไขได้อย่างง่ายดายโดยการเพิ่มaxisการโต้แย้งกับทั้งสองและmax sumอย่างไรก็ตามการใช้งานครั้งแรกยังดีกว่าเนื่องจากคุณสามารถล้นได้อย่างง่ายดายเมื่อถ่ายexp
หลุยส์หยาง

@LouisYang ฉันไม่ได้ติดตาม โซลูชันตัวแรกคือตัวไหน? อันไหนไม่ได้ใช้exp? มีการแก้ไขอะไรเพิ่มเติมนอกเหนือจากการเพิ่มaxisอาร์กิวเมนต์
Desertnaut

วิธีแก้ปัญหาแรกอ้างถึงโซลูชันจาก @alvas ความแตกต่างคือการแก้ปัญหาที่แนะนำในคำถามของ alvas นั้นขาดส่วนหนึ่งของการลบค่าสูงสุด สิ่งนี้สามารถทำให้เกิดการโอเวอร์โฟลว์ได้ง่ายเช่น exp (1000) / (exp (1000) + exp (1001)) vs exp (-1) / (exp (-1) + exp (0)) จะเหมือนกันในคณิตศาสตร์ แต่ คนแรกจะล้น
หลุยส์หยาง

@LouisYang ยังคงไม่แน่ใจว่าฉันเข้าใจความจำเป็นของความคิดเห็นของคุณ - ทั้งหมดนี้ได้รับการแก้ไขอย่างชัดเจนในคำตอบ
Desertnaut

@ LouisYang โปรดอย่าปล่อยให้ความนิยม (ต่อมา) ของเธรดหลอกคุณและลองจินตนาการถึงบริบทที่คำตอบของตัวเองถูกเสนอ: OP ที่งงงวย (" ทั้งคู่ให้ผลเหมือนกัน ") และ a (ยัง!) ตอบรับ อ้างว่า " ทั้งคู่ถูกต้อง " (ก็ไม่ได้ ) คำตอบนั้นไม่ได้หมายถึงว่า " เป็นวิธีที่ถูกต้องและมีประสิทธิภาพมากที่สุดในการคำนวณ softmax โดยทั่วไป "; มันก็หมายถึงการแสดงให้เห็นถึงเหตุผลในที่เฉพาะเจาะจงแบบทดสอบ Udacity กล่าวถึง 2 โซลูชั่นไม่เทียบเท่า
Desertnaut

56

ดังนั้นนี่เป็นความเห็นต่อคำตอบของทะเลทราย แต่ฉันไม่สามารถแสดงความคิดเห็นได้เนื่องจากชื่อเสียงของฉัน ในขณะที่เขาชี้ให้เห็นว่ารุ่นของคุณถูกต้องเฉพาะในกรณีที่การป้อนข้อมูลของคุณประกอบด้วยตัวอย่างเดียว หากอินพุตของคุณประกอบด้วยหลายตัวอย่างแสดงว่าผิด อย่างไรก็ตามทางออกของทะเลทรายก็ผิดเช่นกัน ปัญหาคือเมื่อเขารับอินพุต 1 มิติจากนั้นเขาก็รับอินพุตสองมิติ ผมขอแสดงให้คุณดู

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 ตัวอย่างเพราะนั่นคือสาเหตุที่เราใช้อินพุต 2 มิติ 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 แถวโดยครั้งแรกควรเป็นครั้งที่สามและครั้งเดียวกับการเปิดใช้งาน 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)

6
นั่นน่าจะเป็นความคิดเห็นอย่างหนึ่ง ;-)
Michael Benjamin

27
np.exp (z) / np.sum (np.exp (z), แกน = 1, keepdims = True) ถึงผลลัพธ์เดียวกันกับฟังก์ชัน softmax ของคุณ ขั้นตอนกับ s นั้นไม่จำเป็น
PabTorre

ในสถานที่ of` s = s[:, np.newaxis], s = s.reshape(z.shape[0],1)ควรจะยังทำงาน
Debashish

2
โซลูชั่นที่ไม่ถูกต้อง / ไม่มีประสิทธิภาพจำนวนมากในหน้านี้ ทำตัวเองชอบและใช้ PabTorre ของ
นางสาวพาลเมอร์

@PabTorre คุณหมายถึง axis = -1 หรือไม่ แกน = 1 จะไม่ทำงานสำหรับการป้อนข้อมูลแบบมิติเดียว
DiehardTheTryhard

36

ฉันจะบอกว่าในขณะที่ทั้งสองถูกต้องทางคณิตศาสตร์การใช้งานที่ชาญฉลาดคนแรกจะดีกว่า เมื่อคำนวณ softmax ค่ากลางอาจมีขนาดใหญ่มาก การหารสองตัวเลขขนาดใหญ่อาจไม่เสถียรเชิงตัวเลข บันทึกย่อเหล่านี้ (จาก Stanford) พูดถึงเคล็ดลับการทำให้เป็นมาตรฐานซึ่งเป็นสิ่งที่คุณกำลังทำอยู่


3
ผลของการยกเลิกหายนะไม่สามารถประเมินได้
Cesar

24

sklearn ยังมีการใช้งานซอฟต์แม็กซ์

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
สิ่งนี้ตอบคำถามที่เฉพาะเจาะจงอย่างไรซึ่งเกี่ยวข้องกับการดำเนินการเองและไม่เกี่ยวกับความพร้อมใช้งานในห้องสมุดบุคคลที่สามบางแห่ง
Desertnaut

8
ฉันกำลังมองหาการใช้งานของบุคคลที่สามเพื่อตรวจสอบผลลัพธ์ของวิธีการทั้งสอง นี่คือวิธีที่ความคิดเห็นนี้ช่วย
Eugenio F. Martinez Pacheco

13

จากมุมมองทางคณิตศาสตร์ของทั้งสองฝ่ายเท่ากัน

และคุณสามารถพิสูจน์ได้อย่างง่ายดาย m=max(x)Let 's ตอนนี้ฟังก์ชั่นของคุณsoftmaxจะคืนค่าเวกเตอร์ซึ่งพิกัด i-th เท่ากับ

ป้อนคำอธิบายรูปภาพที่นี่

สังเกตว่ามันใช้งานได้กับทุก ๆ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

ในการเสนอทางเลือกอื่นให้พิจารณากรณีที่ข้อโต้แย้งของคุณมีขนาดใหญ่มากเช่นที่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
Björn Lindqvist

อีกวิธีหนึ่งหนึ่งสามารถแกะ args พิเศษเพื่อส่งผ่านไปยัง 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]]

Ref: Tensorflow softmax


เพียงจำไว้ว่าคำตอบหมายถึงการตั้งค่าที่เฉพาะเจาะจงมากที่อธิบายไว้ในคำถาม มันไม่เคยตั้งใจจะเป็น 'วิธีการคำนวณ softmax โดยทั่วไปในสถานการณ์ใด ๆ หรือในรูปแบบข้อมูลที่คุณชื่นชอบ' ...
desertnaut

ฉันเห็นฉันใส่นี่ไว้เพราะคำถามหมายถึง "คลาสการเรียนรู้ลึกของ Udacity" และมันจะไม่ทำงานถ้าคุณใช้ Tensorflow เพื่อสร้างแบบจำลองของคุณ โซลูชันของคุณเย็นและสะอาด แต่ใช้ได้ในสถานการณ์ที่เฉพาะเจาะจงเท่านั้น ขอบคุณอยู่ดี
Lucas Casagrande

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

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 คำอธิบายว่ารหัสของคุณตอบคำถามนั้นมีประโยชน์อย่างไร
Nick

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

ฉันต้องการเสริมความเข้าใจปัญหาให้มากขึ้น ที่นี่มันถูกต้องในการลบสูงสุดของอาร์เรย์ แต่ถ้าคุณเรียกใช้รหัสในโพสต์อื่นคุณจะพบว่ามันไม่ได้ให้คำตอบที่ถูกต้องเมื่ออาเรย์นั้นเป็นมิติ 2 มิติหรือสูงกว่า

ที่นี่ฉันให้คำแนะนำแก่คุณ:

  1. ในการรับค่าสูงสุดลองทำตามแกน x คุณจะได้อาร์เรย์ 1D
  2. เปลี่ยนรูปร่างสูงสุดของคุณเป็นรูปร่างดั้งเดิม
  3. ทำ np.exp รับค่าเอ็กซ์โพเนนเชียล
  4. ทำ np.sum ตามแนวแกน
  5. รับผลสุดท้าย

ติดตามผลลัพธ์ที่คุณจะได้รับคำตอบที่ถูกต้องโดยทำการ vectorization เนื่องจากมันเกี่ยวข้องกับการบ้านของวิทยาลัยฉันจึงไม่สามารถโพสต์รหัสที่แน่นอนได้ที่นี่ แต่ฉันต้องการให้คำแนะนำเพิ่มเติมหากคุณไม่เข้าใจ


1
มันไม่เกี่ยวข้องกับการบ้านของวิทยาลัยใด ๆ เพียงเพื่อตอบคำถามการฝึกฝนที่ยังไม่ผ่านการรับรองในหลักสูตรที่ไม่ผ่านการรับรองซึ่งมีคำตอบที่ถูกต้องไว้ในขั้นตอนต่อไป ...
desertnaut

0

วัตถุประสงค์ของฟังก์ชั่น softmax คือการรักษาอัตราส่วนของเวกเตอร์เมื่อเทียบกับการบีบจุดสิ้นสุดด้วย sigmoid ในขณะที่ค่าอิ่มตัว (เช่นมีแนวโน้มที่จะ +/- 1 (tanh) หรือจาก 0 ถึง 1 (logistical)) นี่เป็นเพราะมันเก็บข้อมูลเพิ่มเติมเกี่ยวกับอัตราการเปลี่ยนแปลงที่จุดสิ้นสุดและดังนั้นจึงสามารถนำไปใช้กับมุ้งประสาทที่มีการเข้ารหัสเอาท์พุท 1-of-N (เช่นถ้าเราบีบจุดสิ้นสุดมันยากที่จะแยกความแตกต่าง 1 -of-N คลาสเอาต์พุตเนื่องจากเราไม่สามารถบอกได้ว่าอันใดคือ "ใหญ่ที่สุด" หรือ "เล็กที่สุด" เพราะพวกมันถูกทำให้แบน) นอกจากนี้ยังทำให้ผลรวมการส่งออกเป็น 1 และผู้ชนะที่ชัดเจนจะใกล้เคียงกับ 1 ในขณะที่ตัวเลขอื่น ๆ ที่อยู่ใกล้กันจะรวมถึง 1 / p โดยที่ p คือจำนวนเซลล์ประสาทเอาท์พุทที่มีค่าใกล้เคียงกัน

จุดประสงค์ของการลบค่าสูงสุดจากเวกเตอร์คือเมื่อคุณทำเลขชี้กำลัง e ^ y คุณอาจได้ค่าที่สูงมากซึ่งคลิปลอยที่ค่าสูงสุดนำไปสู่การผูกซึ่งไม่ใช่กรณีในตัวอย่างนี้ สิ่งนี้จะกลายเป็นปัญหาใหญ่หากคุณลบค่าสูงสุดเพื่อสร้างจำนวนลบคุณจะมีเลขชี้กำลังเป็นลบซึ่งจะลดค่าที่เปลี่ยนแปลงอัตราส่วนอย่างรวดเร็วซึ่งเป็นสิ่งที่เกิดขึ้นในคำถามของโปสเตอร์และให้คำตอบที่ไม่ถูกต้อง

คำตอบที่จัดทำโดย Udacity คือ HORRIBLY ที่ไม่มีประสิทธิภาพ สิ่งแรกที่เราต้องทำคือคำนวณ e ^ y_j สำหรับส่วนประกอบเวกเตอร์ทั้งหมด, เก็บค่าเหล่านั้น, จากนั้นทำการบวกและหาร ที่ความทึบของความยุ่งเหยิงเกิดขึ้นพวกเขาคำนวณ 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 ของ tensorflow

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 ใช้หมายเลข ( 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 เปลี่ยนการบันทึก [2.0, 1.0, 0.1] เป็นความน่าจะเป็น [0.7, 0.2, 0.1] และความน่าจะเป็นที่รวมเป็น 1 การบันทึกคือผลลัพธ์คะแนนดิบโดยชั้นสุดท้ายของเครือข่ายประสาท ก่อนเปิดใช้งานจะเกิดขึ้น เพื่อให้เข้าใจถึงฟังก์ชั่น softmax เราต้องดูผลลัพธ์ของเลเยอร์ (n-1) th

ในความเป็นจริงแล้วฟังก์ชั่น 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.