तंत्रिका नेटवर्क के प्रशिक्षण में बहुत कम या NaN मान दिखाई देते हैं


329

मैं हास्केल में एक तंत्रिका नेटवर्क वास्तुकला को लागू करने की कोशिश कर रहा हूं, और MNIST पर इसका उपयोग कर रहा हूं।

मैं hmatrixरैखिक बीजगणित के लिए पैकेज का उपयोग कर रहा हूं । मेरा प्रशिक्षण ढांचा pipesपैकेज का उपयोग करके बनाया गया है।

मेरा कोड संकलित करता है और क्रैश नहीं करता है। लेकिन समस्या यह है कि परत के आकार (कहते हैं, 1000), मिनीबैच आकार, और सीखने की दर के कुछ संयोजन संकलन NaNमें मूल्यों को जन्म देते हैं । कुछ निरीक्षण के बाद, मैं देखता हूं कि 1e-100सक्रियणों में अत्यंत छोटे मूल्य (क्रम ) दिखाई देते हैं। लेकिन, जब ऐसा नहीं होता है, तब भी प्रशिक्षण काम नहीं करता है। इसके नुकसान या सटीकता पर कोई सुधार नहीं हुआ है।

मैंने अपना कोड चेक और रीचेक किया, और मैं एक नुकसान में हूं कि समस्या की जड़ क्या हो सकती है।

यहाँ बैकप्रोपैगेशन प्रशिक्षण दिया गया है, जो प्रत्येक परत के लिए डेल्टास की गणना करता है:

backward lf n (out,tar) das = do
    let δout = tr (derivate lf (tar, out)) -- dE/dy
        deltas = scanr (\(l, a') δ ->
                         let w = weights l
                         in (tr a') * (w <> δ)) δout (zip (tail $ toList n) das)
    return (deltas)

lfहानि फ़ंक्शन है, nनेटवर्क है ( प्रत्येक परत के लिए weightमैट्रिक्स और biasवेक्टर), outऔर tarनेटवर्क के वास्तविक आउटपुट और target(वांछित) आउटपुट हैं, और dasप्रत्येक परत के सक्रियण डेरिवेटिव हैं।

बैच मोड में out, tarमैट्रिसेस हैं (पंक्तियाँ आउटपुट वैक्टर हैं), और dasमैट्रिसेस की एक सूची है।

यहाँ वास्तविक ढाल अभिकलन है:

  grad lf (n, (i,t)) = do
    -- Forward propagation: compute layers outputs and activation derivatives
    let (as, as') = unzip $ runLayers n i
        (out) = last as
    (ds) <- backward lf n (out, t) (init as') -- Compute deltas with backpropagation
    let r  = fromIntegral $ rows i -- Size of minibatch
    let gs = zipWith (\δ a -> tr (δ <> a)) ds (i:init as) -- Gradients for weights
    return $ GradBatch ((recip r .*) <$> gs, (recip r .*) <$> squeeze <$> ds)

यहाँ, lfऔर nऊपर के समान हैं, iइनपुट है, और tलक्ष्य आउटपुट है (दोनों बैच रूप में, मैट्रिसेस के रूप में)।

squeezeप्रत्येक पंक्ति में एक मैट्रिक्स को वेक्टर में बदल देता है। यही है, dsडेल्टास के मेट्रिसेस की एक सूची है, जहां प्रत्येक स्तंभ मिनीटैच की एक पंक्ति के लिए डेल्टास से मेल खाता है। तो, पूर्वाग्रहों के लिए ग्रेडिएंट सभी मिनीबैच पर डेल्टास का औसत है। के लिए एक ही बात है gs, जो वजन के लिए ढ़ाल से मेल खाती है।

यहां वास्तविक अपडेट कोड है:

move lr (n, (i,t)) (GradBatch (gs, ds)) = do
    -- Update function
    let update = (\(FC w b af) g δ -> FC (w + (lr).*g) (b + (lr).*δ) af)
        n' = Network.fromList $ zipWith3 update (Network.toList n) gs ds
    return (n', (i,t))

lrसीखने की दर है। FCपरत निर्माता है, और afउस परत के लिए सक्रियण कार्य है।

ग्रेडिएंट डिसेंट एल्गोरिथ्म सीखने की दर के लिए एक नकारात्मक मूल्य में पारित करना सुनिश्चित करता है। ग्रेडिएंट डिसेंट के लिए वास्तविक कोड एक कंपोजिट स्टॉप कंडीशन के साथ, की रचना के चारों ओर एक लूप है gradऔर move

अंत में, यहाँ एक मतलब वर्ग त्रुटि हानि फ़ंक्शन के लिए कोड है:

mse :: (Floating a) => LossFunction a a
mse = let f (y,y') = let gamma = y'-y in gamma**2 / 2
          f' (y,y') = (y'-y)
      in  Evaluator f f'

Evaluator बस एक हानि फ़ंक्शन और उसके व्युत्पन्न (आउटपुट परत के डेल्टा की गणना के लिए) बंडल करता है।

बाकी कोड GitHub: NeuralNetwork पर है

इसलिए, अगर किसी को समस्या की जानकारी है, या यहां तक ​​कि सिर्फ एक पवित्रता की जांच है कि मैं एल्गोरिथ्म को सही ढंग से लागू कर रहा हूं, तो मैं आभारी रहूंगा।


17
धन्यवाद, मैं उस पर गौर करूंगा। लेकिन मुझे नहीं लगता कि यह सामान्य व्यवहार है। जहाँ तक मुझे पता है, मैं जो करने की कोशिश कर रहा हूँ, उसके अन्य कार्यान्वयन (सरल फीडफॉरवर्ड पूरी तरह से जुड़ा हुआ न्यूरल नेटवर्क), या तो हास्केल या अन्य भाषाओं में, ऐसा लगता नहीं है।
चार्ल्स लैंग्लोइस

17
@Charles: क्या आपने वास्तव में कहा कि अन्य कार्यान्वयन के साथ अपने खुद के नेटवर्क और डेटा सेट की कोशिश की? अपने स्वयं के अनुभव में, बीपी आसानी से हियरवायर जाएगा जब एनएन समस्या के अनुकूल है। यदि आपको बीपी के अपने कार्यान्वयन के बारे में संदेह है, तो आप इसके उत्पादन की तुलना एक भोले ढाल की गणना (खिलौने के आकार के एनएन से अधिक) के साथ कर सकते हैं - जो कि बीपी से गलत होने के लिए कठिन है।
shinobi

5
क्या एमएनआईएसटी आमतौर पर एक वर्गीकरण समस्या नहीं है? आप एमईएस का उपयोग क्यों कर रहे हैं? आपको सॉफ्टमैक्स क्रॉसेंट्रोपी (लॉगिट से गणना) का उपयोग करना चाहिए?
mdaoust

6
@CharlesLanglois, यह आपकी समस्या नहीं हो सकती है (मैं कोड नहीं पढ़ सकता) लेकिन "मतलब वर्ग त्रुटि" एक वर्गीकरण समस्या के लिए उत्तल नहीं है, जो कि अटक जाने की व्याख्या कर सकती है। "लॉगिट्स" लॉग-ऑड्स कहने के लिए सिर्फ एक फैंसी तरीका है: यहां सेce = x_j - log(sum_i(exp(x))) गणना का उपयोग करें ताकि आप घातांक का लॉग न लें (जो अक्सर NaN उत्पन्न करता है)
madaoust

6
सबसे ज्यादा मत वाले सवाल (जन ’20 के रूप में) को बिना उत्थान या स्वीकृत उत्तरों के साथ बधाई !

जवाबों:


2

क्या आप बैकप्रोपैजेशन में "लुप्त" और "विस्फोट" ग्रेडिएंट्स के बारे में जानते हैं? मैं हास्केल से बहुत परिचित नहीं हूं इसलिए मैं आसानी से यह नहीं देख सकता कि आपका बैकप्रॉप क्या कर रहा है, लेकिन ऐसा लगता है कि आप लॉजिस्टिक वक्र का उपयोग अपने सक्रियण फ़ंक्शन के रूप में कर रहे हैं।

यदि आप इस फ़ंक्शन के प्लॉट को देखते हैं, तो आप देखेंगे कि इस फ़ंक्शन का ग्रेडिएंट लगभग 0 छोर पर है (चूंकि इनपुट मान बहुत बड़े या बहुत छोटे होते हैं, वक्र का ढलान लगभग समतल होता है), इसलिए गुणा करना या विभाजित करना backpropagation के दौरान इसके परिणामस्वरूप बहुत बड़ी या बहुत कम संख्या होगी। कई परतों से गुजरते हुए बार-बार ऐसा करने से सक्रियता शून्य या अनंत तक पहुंच जाती है। चूंकि प्रशिक्षण के दौरान ऐसा करने से बैकप्रॉप आपके वजन को अपडेट करता है, इसलिए आप अपने नेटवर्क में बहुत सारे शून्य या इन्फिनिटी के साथ समाप्त होते हैं।

समाधान: वहाँ तरीकों का भार है जिसे आप लुप्त हो रही समस्या को हल करने के लिए खोज सकते हैं, लेकिन कोशिश करने के लिए एक आसान बात यह है कि आप एक गैर-संतृप्त करने के लिए उपयोग किए जाने वाले सक्रियण फ़ंक्शन के प्रकार को बदल दें। ReLU एक लोकप्रिय विकल्प है क्योंकि यह इस समस्या को कम करता है (लेकिन दूसरों को पेश कर सकता है)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.