2012-03-28 19 views
19

के लिए सॉफ्टमैक्स सक्रियण फ़ंक्शन का कार्यान्वयन मैं तंत्रिका नेटवर्क की अंतिम परत में Softmax सक्रियण फ़ंक्शन का उपयोग कर रहा हूं। लेकिन मुझे इस समारोह के सुरक्षित कार्यान्वयन में समस्याएं हैं।तंत्रिका नेटवर्क

Vector y = mlp(x); // output of the neural network without softmax activation function 
for(int f = 0; f < y.rows(); f++) 
    y(f) = exp(y(f)); 
y /= y.sum(); 

यह> 100 छिपा नोड्स के लिए बहुत अच्छी तरह से काम नहीं करता है क्योंकि y कई मामलों में NaN (यदि y (च)> 709, exp (होगा:

एक अनुभवहीन कार्यान्वयन यह एक होगा वाई (एफ)) इंफ वापस आ जाएगा)। मैं इस संस्करण के साथ आया था:

Vector y = mlp(x); // output of the neural network without softmax activation function 
for(int f = 0; f < y.rows(); f++) 
    y(f) = safeExp(y(f), y.rows()); 
y /= y.sum(); 

जहां safeExp

double safeExp(double x, int div) 
{ 
    static const double maxX = std::log(std::numeric_limits<double>::max()); 
    const double max = maxX/(double) div; 
    if(x > max) 
    x = max; 
    return std::exp(x); 
} 

इस समारोह के रूप में परिभाषित किया गया है exp के इनपुट सीमित करता है। ज्यादातर मामलों में यह काम करता है लेकिन सभी मामलों में नहीं और मैंने वास्तव में यह पता लगाने में कामयाब नहीं किया कि यह किस मामले में काम नहीं करता है। जब मेरी पिछली परत में 800 छिपा न्यूरॉन्स हैं तो यह बिल्कुल काम नहीं करता है।

हालांकि, अगर यह काम करता है तो भी मैं एएनएन के परिणाम को "विकृत" करता हूं। क्या आप सही समाधान की गणना करने के किसी अन्य तरीके से सोच सकते हैं? क्या कोई सी ++ पुस्तकालय या चाल है जिसका उपयोग मैं इस एएनएन के सटीक आउटपुट की गणना के लिए कर सकता हूं?

संपादित करें: Itamar Katz द्वारा प्रदान समाधान है:

Vector y = mlp(x); // output of the neural network without softmax activation function 
double ymax = maximal component of y 
for(int f = 0; f < y.rows(); f++) 
    y(f) = exp(y(f) - ymax); 
y /= y.sum(); 

और यह वास्तव में गणितीय में ही है। अभ्यास में हालांकि, फ्लोटिंग पॉइंट परिशुद्धता के कारण कुछ छोटे मान 0 बन जाते हैं। मुझे आश्चर्य है कि पाठ्यपुस्तकों में इन कार्यान्वयन विवरणों में से कोई भी क्यों नहीं लिखता है।

+3

"मुझे आश्चर्य है कि कोई भी पाठ्यपुस्तकों में इन कार्यान्वयन विवरणों को कभी भी क्यों नहीं लिखता है।" मैंने हमेशा एक ही चीज़ को सोचा है! – pjreddie

+0

"यह वास्तव में गणितीय रूप से वही है" - आगे पढ़ने के बाद, कोई कहता है कि संख्यात्मक स्थिरता के कारण आपकी विधि को प्राथमिकता दी गई है .: https://stackoverflow.com/questions/34968722/softmax-function-python – gremwell

उत्तर

12

पहले लॉग स्केल पर जाएं, यानी y के बजाय log(y) की गणना करें। संख्यात्मक का लॉग छोटा है। Denominator के लॉग की गणना करने के लिए, आप निम्न 'चाल' का उपयोग कर सकते हैं: http://lingpipe-blog.com/2009/06/25/log-sum-of-exponentials/

+0

एक आदर्श समाधान। मैं एक मिनट में कोड जोड़ दूंगा। क्या आप इसकी पुष्टि कर सकते हैं? आपका बहुत बहुत धन्यवाद। – alfa

+0

यह सही प्रतीत नहीं होता है; 'लॉग (वाई (एफ))' के बीजगणित का पालन करें: ** लॉग (वाई (एफ)) = लॉग (एक्स (वाई (एफ)) - लॉग (योग (एक्स (वाई (एफ))) * * और योग के लॉग के लिए उल्लिखित 'चाल' परिणाम में प्लग करें। –

+0

ln (y_f) = ln (exp (a_f)) - ln (f 'exp (a_f') पर योग) = af - ln [f 'exp (m)/exp (m) * exp (a_f') पर योग ] = a_f - m - ln (f से अधिक 'exp (-m) * exp (a_f)) = a_f - m - ln [sum over f' exp (a_f'-m)] <=> y_f exp (a_f-m)/(एफ 'एक्स (ए_एफ' - एम) पर योग)। उपरोक्त सूचीबद्ध कोड में exp_) से पहले__f y_f है। त्रुटि कहां है? : डी – alfa

7

मुझे पता है कि यह पहले से ही उत्तर दिया गया है लेकिन मैं यहां एक कदम-दर-चरण पोस्ट करूंगा। लॉग पर

पुट:

log oj = zj - log {sum_i { exp(zi + m - m)}} 
    = zj - log {sum_i { exp(m) exp(zi - m) }}, 
    = zj - log {exp(m) sum_i {exp(zi - m)}} 
    = zj - m - log {sum_i { exp(zi - m)}} 

अवधि exp (ज़ी-एम) अधःप्रवाह ग्रस्त कर सकते हैं:

zj = wj . x + bj 
oj = exp(zj)/sum_i{ exp(zi) } 
log oj = zj - log sum_i{ exp(zi) } 

Let मीटर max_i {ज़ी} लॉग-योग-exp चाल का उपयोग हो अगर एम अन्य z_i से कहीं अधिक है, लेकिन यह ठीक है क्योंकि इसका मतलब है कि z_i सामान्यीकरण के बाद सॉफ्टमैक्स आउटपुट पर अप्रासंगिक है। अंतिम परिणाम यह है:

oj = exp (zj - m - log{sum_i{exp(zi-m)}}) 
+0

धन्यवाद! आपका जवाब मदद करता है! आपने उल्लेख किया "लेकिन यह ठीक है क्योंकि इसका अर्थ यह है कि z_i सामान्यीकरण के बाद सॉफ्टमैक्स आउटपुट पर अप्रासंगिक है", क्या आपका मतलब है कि 'exp (zi-m) 'होता है। यह परिणाम में ज्यादा त्रुटि नहीं जोड़ता है? –

+0

देर से उत्तर क्षमा करें। हां, यदि एम >> ज़ी तो एक्स (ज़ी-एम) 0 के करीब होगा, तो अंडरफ्लो इसे 0 पर बदल देता है, जो अंतिम परिणामों में से अधिकतर नहीं बदलता है। –

संबंधित मुद्दे