कनवल्शनल नेटवर्क को कम करने के लिए जेडी तकनीक - प्रूनिंग
आपके सामने फिर से वस्तुओं का पता लगाने का कार्य है। प्राथमिकता स्वीकार्य सटीकता के साथ संचालन की गति है। आप YOLOv3 आर्किटेक्चर लें और इसे आगे प्रशिक्षित करें। सटीकता (mAp75) 0.95 से अधिक है। लेकिन रन रेट अब भी कम है. बकवास।
आज हम परिमाणीकरण को बायपास करेंगे। और कट के नीचे हम देखेंगे मॉडल प्रूनिंग - सटीकता की हानि के बिना अनुमान को तेज करने के लिए नेटवर्क के अनावश्यक हिस्सों को ट्रिम करना। यह स्पष्ट है कि कहां, कितना और कैसे काटना है। आइए जानें कि इसे मैन्युअल रूप से कैसे करें और आप इसे कहां स्वचालित कर सकते हैं। अंत में केरस पर एक भंडार है।
परिचय
मेरे पिछले काम के स्थान, पर्म में मैक्रोस्कोप में, मुझे एक आदत मिली - हमेशा एल्गोरिदम के निष्पादन समय की निगरानी करने की। और हमेशा पर्याप्तता फ़िल्टर के माध्यम से नेटवर्क रनटाइम की जांच करें। आमतौर पर उत्पादन में अत्याधुनिक इस फिल्टर को पास नहीं करता है, जिसके कारण मुझे प्रूनिंग करनी पड़ी।
प्रूनिंग एक पुराना विषय है जिस पर चर्चा की गई थी स्टैनफोर्ड व्याख्यान 2017 में. मुख्य विचार विभिन्न नोड्स को हटाकर सटीकता खोए बिना प्रशिक्षित नेटवर्क के आकार को कम करना है। यह अच्छा लगता है, लेकिन मैंने इसके उपयोग के बारे में कम ही सुना है। संभवतः, पर्याप्त कार्यान्वयन नहीं हैं, कोई रूसी भाषा के लेख नहीं हैं, या बस हर कोई इसे तकनीकी जानकारी मानता है और चुप रहता है।
लेकिन आइए इसे अलग कर लें
जीवविज्ञान में एक झलक
मुझे अच्छा लगता है जब डीप लर्निंग जीव विज्ञान से आए विचारों को देखता है। वे, विकास की तरह, भरोसा किया जा सकता है (क्या आप जानते हैं कि ReLU बहुत समान है मस्तिष्क में न्यूरॉन सक्रियण का कार्य?)
मॉडल प्रूनिंग प्रक्रिया भी जीव विज्ञान के करीब है। यहां नेटवर्क की प्रतिक्रिया की तुलना मस्तिष्क की प्लास्टिसिटी से की जा सकती है। पुस्तक में कुछ दिलचस्प उदाहरण हैं। नॉर्मन डोज:
एक महिला का मस्तिष्क जो केवल आधे हिस्से के साथ पैदा हुई थी, उसने गायब आधे हिस्से के कार्यों को करने के लिए खुद को पुन: प्रोग्राम किया है।
उस व्यक्ति ने दृष्टि के लिए जिम्मेदार अपने मस्तिष्क के हिस्से को गोली मार दी। समय के साथ, मस्तिष्क के अन्य हिस्सों ने इन कार्यों को संभाल लिया। (हम दोहराने की कोशिश नहीं कर रहे हैं)
इसी तरह, आप अपने मॉडल से कुछ कमजोर कनवल्शन को काट सकते हैं। अंतिम उपाय के रूप में, बचे हुए बंडल कटे हुए बंडलों को बदलने में मदद करेंगे।
क्या आपको ट्रांसफर लर्निंग पसंद है या आप शुरुआत से सीख रहे हैं?
विकल्प नंबर एक. आप Yolov3 पर ट्रांसफर लर्निंग का उपयोग करते हैं। रेटिना, मास्क-आरसीएनएन या यू-नेट। लेकिन अधिकांश समय हमें COCO की तरह 80 ऑब्जेक्ट वर्गों को पहचानने की आवश्यकता नहीं होती है। मेरे व्यवहार में, सब कुछ ग्रेड 1-2 तक ही सीमित है। कोई यह मान सकता है कि 80 कक्षाओं के लिए वास्तुकला यहां अनावश्यक है। इससे पता चलता है कि वास्तुकला को छोटा बनाने की जरूरत है। इसके अलावा, मैं मौजूदा पूर्व-प्रशिक्षित वजन कम किए बिना ऐसा करना चाहूंगा।
विकल्प संख्या दो. हो सकता है कि आपके पास बहुत सारा डेटा और कंप्यूटिंग संसाधन हों, या बस एक सुपर-कस्टम आर्किटेक्चर की आवश्यकता हो। कोई फर्क नहीं पड़ता। लेकिन आप नेटवर्क को शुरू से सीख रहे हैं। सामान्य प्रक्रिया डेटा संरचना को देखना, एक ऐसे आर्किटेक्चर का चयन करना है जो शक्ति में अत्यधिक है, और ड्रॉपआउट को पुनः प्रशिक्षण से दूर करना है। मैंने 0.6 ड्रॉपआउट देखे, कार्ल।
दोनों ही स्थिति में नेटवर्क कम किया जा सकता है. प्रेरित. अब आइए जानें कि खतना किस प्रकार की छंटाई है
सामान्य एल्गोरिदम
हमने निर्णय लिया कि हम बंडलों को हटा सकते हैं। यह काफी सरल दिखता है:
किसी भी कनवल्शन को हटाना नेटवर्क के लिए तनावपूर्ण होता है, जिससे आमतौर पर त्रुटि में कुछ वृद्धि होती है। एक ओर, त्रुटि में यह वृद्धि इस बात का संकेतक है कि हम कितनी सही ढंग से कनवल्शन को हटाते हैं (उदाहरण के लिए, एक बड़ी वृद्धि इंगित करती है कि हम कुछ गलत कर रहे हैं)। लेकिन एक छोटी वृद्धि काफी स्वीकार्य है और अक्सर एक छोटे एलआर के साथ बाद के हल्के अतिरिक्त प्रशिक्षण द्वारा इसे समाप्त कर दिया जाता है। एक अतिरिक्त प्रशिक्षण चरण जोड़ें:
अब हमें यह पता लगाने की जरूरत है कि हम अपना लर्निंग<->प्रूनिंग लूप कब बंद करना चाहते हैं। जब हमें नेटवर्क को एक निश्चित आकार और गति तक कम करने की आवश्यकता होती है (उदाहरण के लिए, मोबाइल उपकरणों के लिए) तो यहां विदेशी विकल्प हो सकते हैं। हालाँकि, सबसे आम विकल्प चक्र को तब तक जारी रखना है जब तक कि त्रुटि स्वीकार्य से अधिक न हो जाए। एक शर्त जोड़ें:
तो, एल्गोरिदम स्पष्ट हो जाता है। यह पता लगाना बाकी है कि हटाए गए कनवल्शन को कैसे निर्धारित किया जाए।
हटाए गए पैकेज खोजें
हमें कुछ संभ्रमों को दूर करने की आवश्यकता है। आगे बढ़ना और किसी को भी "गोली मारना" एक बुरा विचार है, हालांकि यह काम करेगा। लेकिन चूंकि आपके पास एक दिमाग है, आप सोच सकते हैं और हटाने के लिए "कमजोर" कनवल्शन का चयन करने का प्रयास कर सकते हैं। कई विकल्प हैं:
प्रत्येक विकल्प में जीवन का अधिकार और इसकी अपनी कार्यान्वयन विशेषताएं हैं। यहां हम सबसे छोटे L1-माप वाले विकल्प पर विचार करते हैं
YOLOv3 के लिए मैन्युअल प्रक्रिया
मूल वास्तुकला में अवशिष्ट ब्लॉक शामिल हैं। लेकिन इससे कोई फर्क नहीं पड़ता कि वे गहरे नेटवर्क के लिए कितने अच्छे हैं, वे हमें कुछ हद तक बाधित करेंगे। कठिनाई यह है कि आप इन परतों में विभिन्न अनुक्रमितों के साथ सामंजस्य को हटा नहीं सकते हैं:
इसलिए, आइए उन परतों का चयन करें जिनसे हम स्वतंत्र रूप से मेल-मिलाप हटा सकते हैं:
आइए अब एक कार्य चक्र बनाएं:
सक्रियण अपलोड हो रहे हैं
यह पता लगाना कि कितना काटना है
इसे काट दें
LR=10e-1 के साथ 4 युगों को सीखना
परिक्षण
कनवल्शन को अनलोड करना यह अनुमान लगाने के लिए उपयोगी है कि हम एक निश्चित चरण में कितना हिस्सा हटा सकते हैं। अनलोडिंग उदाहरण:
हम देखते हैं कि लगभग हर जगह 5% कनवल्शन में L1-मानदंड बहुत कम है और हम उन्हें हटा सकते हैं। प्रत्येक चरण पर, यह उतराई दोहराई गई और मूल्यांकन किया गया कि कौन सी परतें और कितनी काटी जा सकती हैं।
पूरी प्रक्रिया 4 चरणों में पूरी हुई (आरटीएक्स 2060 सुपर के लिए संख्याएँ यहाँ और हर जगह):
कदम
एमएपी75
पैरामीटरों की संख्या, मिलियन
नेटवर्क आकार, एमबी
प्रारंभिक से, %
रन टाइम, सुश्री
खतना की स्थिति
0
0.9656
60
241
100
180
-
1
0.9622
55
218
91
175
सभी का 5%
2
0.9625
50
197
83
168
सभी का 5%
3
0.9633
39
155
64
155
15+ कनवल्शन वाली परतों के लिए 400%
4
0.9555
31
124
51
146
10+ कनवल्शन वाली परतों के लिए 100%
चरण 2 में एक सकारात्मक प्रभाव जोड़ा गया - बैच आकार 4 मेमोरी में फिट हो गया, जिसने अतिरिक्त प्रशिक्षण की प्रक्रिया को काफी तेज कर दिया।
चरण 4 पर, प्रक्रिया रोक दी गई क्योंकि यहां तक कि दीर्घकालिक अतिरिक्त प्रशिक्षण ने भी mAp75 को पुराने मूल्यों तक नहीं बढ़ाया।
परिणामस्वरूप, हम अनुमान को गति देने में सफल रहे 15% तक , आकार कम करें 35% तक और बिल्कुल नहीं खोना.
सरल आर्किटेक्चर के लिए स्वचालन
सरल नेटवर्क आर्किटेक्चर के लिए (सशर्त ऐड, कॉन्कैटरनेट और अवशिष्ट ब्लॉकों के बिना), सभी कनवल्शनल परतों को संसाधित करने पर ध्यान केंद्रित करना और कनवल्शन को काटने की प्रक्रिया को स्वचालित करना काफी संभव है।
मैंने यह विकल्प लागू किया यहां.
यह सरल है: आपको केवल एक हानि फ़ंक्शन, एक अनुकूलक और बैच जनरेटर की आवश्यकता है:
import pruning
from keras.optimizers import Adam
from keras.utils import Sequence
train_batch_generator = BatchGenerator...
score_batch_generator = BatchGenerator...
opt = Adam(lr=1e-4)
pruner = pruning.Pruner("config.json", "categorical_crossentropy", opt)
pruner.prune(train_batch, valid_batch)
यदि आवश्यक हो, तो आप कॉन्फ़िगरेशन पैरामीटर बदल सकते हैं:
{
"input_model_path": "model.h5",
"output_model_path": "model_pruned.h5",
"finetuning_epochs": 10, # the number of epochs for train between pruning steps
"stop_loss": 0.1, # loss for stopping process
"pruning_percent_step": 0.05, # part of convs for delete on every pruning step
"pruning_standart_deviation_part": 0.2 # shift for limit pruning part
}
इसके अतिरिक्त, मानक विचलन पर आधारित एक सीमा लागू की गई है। लक्ष्य पहले से ही "पर्याप्त" L1 उपायों के साथ कनवल्शन को छोड़कर, हटाए गए हिस्से को सीमित करना है:
इस प्रकार, हम आपको दाईं ओर के समान वितरणों से केवल कमजोर कनवल्शन को हटाने की अनुमति देते हैं और बाईं ओर के समान वितरण से निष्कासन को प्रभावित नहीं करते हैं:
जब वितरण सामान्य हो जाता है, तो pruning_standart_deviation_part गुणांक का चयन किया जा सकता है:
मैं 2 सिग्मा की धारणा की अनुशंसा करता हूँ। या आप मान <1.0 छोड़कर इस सुविधा को अनदेखा कर सकते हैं।
आउटपुट पूरे परीक्षण के लिए नेटवर्क आकार, हानि और नेटवर्क रनटाइम का एक ग्राफ़ है, जिसे 1.0 पर सामान्यीकृत किया गया है। उदाहरण के लिए, यहां गुणवत्ता की हानि के बिना नेटवर्क का आकार लगभग 2 गुना कम हो गया था (100k वजन वाला छोटा कनवल्शनल नेटवर्क):
चलने की गति सामान्य उतार-चढ़ाव के अधीन है और वस्तुतः अपरिवर्तित रहती है। इसके लिए एक स्पष्टीकरण है:
कनवल्शन की संख्या सुविधाजनक (32, 64, 128) से वीडियो कार्ड के लिए सबसे सुविधाजनक नहीं - 27, 51, आदि में बदल जाती है। मैं यहां गलत हो सकता हूं, लेकिन सबसे अधिक संभावना है कि इसका असर होगा।
वास्तुकला व्यापक नहीं है, लेकिन सुसंगत है। चौड़ाई कम करने से हम गहराई को प्रभावित नहीं करते। इस प्रकार, हम भार कम करते हैं, लेकिन गति नहीं बदलते हैं।
इसलिए, रन के दौरान CUDA लोड में 20-30% की कमी में सुधार व्यक्त किया गया था, लेकिन रन टाइम में कमी में नहीं
परिणाम
आइये विचार करें. हमने प्रूनिंग के लिए 2 विकल्पों पर विचार किया - YOLOv3 के लिए (जब आपको अपने हाथों से काम करना होता है) और सरल आर्किटेक्चर वाले नेटवर्क के लिए। यह देखा जा सकता है कि दोनों ही मामलों में सटीकता की हानि के बिना नेटवर्क आकार में कमी और गति प्राप्त करना संभव है। परिणाम:
आकार कम करना
त्वरण दौड़
CUDA लोड कम करना
परिणामस्वरूप, पर्यावरण मित्रता (हम कंप्यूटिंग संसाधनों के भविष्य के उपयोग को अनुकूलित करते हैं। कहीं न कहीं कोई खुश होता है ग्रेटा ट्यूनबर्ग)
परिशिष्ट
छंटाई चरण के बाद, आप परिमाणीकरण जोड़ सकते हैं (उदाहरण के लिए, TensorRT के साथ)