2016-07-31 9 views
12

कैफे में, convolution परत एक निचला ब्लॉब लेता है, और इसे सीखा फ़िल्टर (जिसे वजन प्रकार - "जेवियर", "एमएसआरए" आदि का उपयोग करके प्रारंभ किया जाता है) के साथ घुल जाता है। हालांकि, मेरा सवाल यह है कि क्या हम केवल दो निचले ब्लब्स को हल कर सकते हैं और एक शीर्ष ब्लॉब का उत्पादन कर सकते हैं। ऐसा करने का सबसे शानदार तरीका क्या होगा? इसका उद्देश्य यह है: नीचे ब्लॉब में से एक data होगा और दूसरा एक गतिशील फ़िल्टर होगा (data के आधार पर बदल रहा है) पिछली परतों द्वारा उत्पादित (मैं dynamic convolution लागू करने की कोशिश कर रहा हूं)।कैफे में दो ब्लब्स को कैसे नियंत्रित करें

मेरे प्रयास:

एक तरह से जो मेरे मन में आए filler.hpp को संशोधित करने और एक filler मैट्रिक्स ही ("जेवियर", "MSRA" आदि के बजाय) के रूप में एक नीचे ब्लॉब आवंटित करने के लिए किया गया था। तब मैंने सोचा कि संकल्प परत वहां से उठाएगी। हम lr = 0 सेट कर सकते हैं यह इंगित करने के लिए कि हमारे कस्टम फिलर द्वारा शुरू किया गया वजन बदला नहीं जाना चाहिए। हालांकि, मैंने सोर्स कोड को देखने के बाद, मुझे अभी भी यह नहीं पता कि यह कैसे करना है। दूसरी तरफ, मैं कैफे के वर्कफ़्लो को तोड़ना नहीं चाहता हूं। मैं अभी भी दृढ़ परतों को सामान्य रूप से काम करना चाहता हूं, अगर मैं उन्हें चाहता हूं।

जाहिर है एक और अधिक कठिन रास्ता Slice, tile और/या Scale परत के संयोजन का उपयोग करने के लिए सचमुच घुमाव के लागू करने के लिए है। मुझे लगता है कि यह काम करेगा, लेकिन यह गन्दा हो जाएगा। कोई अन्य विचार?

संपादित करें 1:

मैं Caffe के घुमाव के परत को संशोधित करके एक नई परत को लिखा था। विशेष रूप से, src/caffe/layers/conv_layer.cpp में, लाइन 27 पर, यह वजन filler द्वारा परिभाषित किया जाता है और इसे नीचे ब्लॉब के साथ घुल जाता है। तो filler से उस ब्लॉब को पॉप्युलेट करने के बजाय, मैंने परत को संशोधित किया है कि अब इसमें दो बोतलें हैं। नीचे से एक सीधे filler को सौंपा जाता है। अब मुझे कुछ अन्य बदलाव करना पड़ा जैसे:

  1. weight ब्लॉब के सभी नमूनों के लिए समान मूल्य है। यहां विभिन्न नमूनों के लिए इसका एक अलग मूल्य होगा।
this->forward_cpu_gemm(
    bottom_data + n * this->bottom_dim_, 
    weight, 
    top_data + n * this->top_dim_); 

करने के लिए:: तो मैं से लाइन 32 बदल

this->forward_cpu_gemm(
    bottom_data + n * bottom[1]->count(1), 
    bottom[0]->cpu_data() + n * bottom[0]->count(1), 
    top_data + n * this->top_dim_); 

चीजों को आसान बनाने के लिए, मैं मान लिया कोई पूर्वाग्रह शामिल अवधि है कि वहाँ, कदम हमेशा होता है 1, गद्दी हमेशा 0 हो सकता है , समूह हमेशा 1 होगा। हालांकि, जब मैंने आगे के पास का परीक्षण किया, तो उसने मुझे कुछ अजीब जवाब दिया (एक सरल संकल्प कर्नेल = np.ones((1,1,3,3)) के साथ। इस कर्नेल के लिए सीखने की दर शून्य पर सेट की गई ताकि यह बदले न जाए। हालांकि, मुझे सही उत्तर नहीं मिल रहा है। किसी भी सुझाव की सराहना की जाएगी।

कृपया मौजूदा परतों जैसे Slice, Eltwise, Crop का उपयोग करके समाधान का प्रस्ताव न दें। मैंने पहले से ही कार्यान्वित किया है - यह काम करता है - लेकिन यह अविश्वसनीय जटिल और स्मृति अक्षम है।

+2

मैंने इसे पढ़ा "कैफी में दो ब्लोंड को कैसे मनाने के लिए": \ – Elazar

+0

@Elazar तो यही कारण है कि आप नीचे मतदान करते हैं? (बस मजाक कर रहे हैं): पी –

उत्तर

7

मुझे लगता है कि आप पूरी तरह से सही तरीके से हैं।

"अजीब" घुमाव के परिणामों के लिए, मुझे लगता है कि बग सबसे संभवतः है:

2 डी घुमाव पर विचार करें

और लगता है bottom[1] के आकार (num, channels, height, width) है,

के बाद से caffe में घुमाव के किया जाता है 2 मैट्रिक्स के गुणा के रूप में, weight (रूपांतरण क्रनेल का प्रतिनिधित्व) और col_buffer (डेटा से संकलित करने के लिए पुनर्गठित), और weightnum_out पंक्तियों औरका हैकॉलम, col_buffer, channels/this->group_ * kernel_h * kernel_w पंक्तियों और height_out * width_out स्तंभों की है, इसलिए गतिशील घुमाव परत का एक weight ब्लॉब के रूप में, bottom[0] के आकार बेहतर (num, num_out, channels/group, kernel_h, kernel_w) हो

bottom[0]->count(1) == num_out * channels/this->group_ * kernel_h * kernel_w 

, जिसमें num_out गतिशील घुमाव की संख्या है को पूरा करने के चाहिए परत के आउटपुट फीचर नक्शे।

इसका मतलब है कि, घुमाव के समारोह

this->forward_cpu_gemm(bottom_data + n * bottom[1]->count(1) 
        , bottom[0]->cpu_data() + n * bottom[0]->count(1) 
        , top_data + n * this->top_dim_); 

काम करने के लिए ठीक से, आप सुनिश्चित करना चाहिए कि

bottom[0]->shape(0) == bottom[1]->shape(0) == num 
bottom[0]->count(1) == num_out * channels/this->group_ * kernel_h * kernel_w 

तो सबसे संभवतः 4-आयाम np.ones((1,1,3,3)) के सरल घुमाव गिरी आप इस्तेमाल कर सकते हैं उपर्युक्त स्थिति को प्रमाणित न करें और परिणामस्वरूप गलत संकल्प परिणाम

आशा है कि यह स्पष्ट है और आपकी मदद करेगा।

########## अद्यतन 1, अक्टूबर 10 वीं, 2016 बीजिंग समय ##########

मैं एक गतिशील घुमाव परत जोड़ने here लेकिन कोई साथ यूनिट परीक्षण अभी तक। यह परत कैफी के वर्कफ़्लो को तोड़ती नहीं है और केवल बेसकोनोल्यूशन क्लास के कुछ निजी सदस्यों को संरक्षित करने के लिए बदलती है।

शामिल फ़ाइलें हैं:

include/caffe/layers/dyn_conv_layer.hpp,base_conv_layer.hpp 
src/caffe/layers/dyn_conv_layer.cpp(cu) 

यह caffe में घुमाव के परत के साथ लगभग एक ही बढ़ता है, और मतभेदों को मुख्य रूप से कर रहे हैं:

  1. अवहेलना समारोह LayerSetUp() प्रारंभ करने में this->kernel_dim_, this->weight_offset_ आदि दृढ़ता से दृढ़ता के लिए और this->blobs_ को प्रारंभ करने के लिए नियमित रूप से वजन और पूर्वाग्रह रखने के लिए कनवॉल्यूशन परत द्वारा उपयोग किया जाता है;
  2. फ़ंक्शन Reshape() को ओवरराइड करने के लिए यह जांचने के लिए कि bottom[1] कर्नेल कंटेनर के रूप में रूपांतरण के लिए उचित आकार है।

क्योंकि मेरे पास इसका परीक्षण करने का कोई समय नहीं है, वहां बग हो सकती हैं और मैं आपकी प्रतिक्रियाओं को देखकर बहुत खुश हूं।

########## अपडेट 2 अक्टूबर 12 वीं, 2016 बीजिंग समय ##########

मैं बस अब dynamic convolution के लिए परीक्षण का मामला अपडेट किया गया। शामिल फ़ाइल src/caffe/test/test_dyn_convolution_layer.cpp है। ऐसा लगता है कि यह ठीक काम करता है, लेकिन शायद अधिक गहन परीक्षण की आवश्यकता है।

आप इसे देखने के लिए cd $CAFFE_ROOT/build && ccmake .., cmake -DBUILD_only_tests="dyn_convolution_layer" .. और make runtest द्वारा इस कैफे का निर्माण कर सकते हैं।

+0

मैं इसे अगले 3-4 दिनों में आज़माउंगा और आपको परिणाम बता दूंगा। धन्यवाद! –

+1

आपको फ़ंक्शन बेसकोनोल्यूशन लेयर :: लेयरसेटअप() पर अधिक ध्यान देना चाहिए, क्योंकि आगे_cpu_gemm() में उपयोग किए जाने वाले कई चर वहां प्रारंभ किए गए हैं। @ पैराग्स। कंधककर – Dale

+0

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

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