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