मैं हास्केल में एक तंत्रिका नेटवर्क वास्तुकला को लागू करने की कोशिश कर रहा हूं, और 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 पर है ।
इसलिए, अगर किसी को समस्या की जानकारी है, या यहां तक कि सिर्फ एक पवित्रता की जांच है कि मैं एल्गोरिथ्म को सही ढंग से लागू कर रहा हूं, तो मैं आभारी रहूंगा।