2017-03-27 20 views
8

मैं बहु-जीपीयू के साथ प्रशिक्षण करते समय बैच आंकड़ों को सिंक्रनाइज़ करने के साथ बैच सामान्यीकरण परतों को लागू करने के संभावित तरीकों को जानना चाहता हूं।सिंक्रनाइज़िंग के साथ बहु-जीपीयू बीएन परतों को लागू करने के तरीके और वर्र्स

कैफे शायद कैफी के कुछ प्रकार हैं जो link जैसे कर सकते हैं। लेकिन बीएन परत के लिए, मेरी समझ यह है कि यह अभी भी परतों के आउटपुट सिंक्रनाइज़ करता है, न कि साधन और युद्ध। शायद एमपीआई साधनों और युद्धों को सिंक्रनाइज़ कर सकता है लेकिन मुझे लगता है कि एमपीआई को लागू करने में थोड़ा मुश्किल है।

मशाल मैं कुछ टिप्पणियाँ here और here, जो दिखाने running_mean और running_var सिंक्रनाइज़ किया जा सकता है, लेकिन मुझे लगता है कि बैच मतलब है और बैच वार नहीं कर सकते हैं या सिंक्रनाइज़ करने के लिए मुश्किल हो जाता है देखा है।

टेन्सफोर्लो आम तौर पर, यह कैफे और मशाल जैसा ही होता है। बीएन के कार्यान्वयन this को संदर्भित करता है। मुझे पता है कि tensorflow tf.device() द्वारा निर्दिष्ट किसी भी डिवाइस पर एक ऑपरेशन वितरित कर सकता है। लेकिन इसका मतलब है की गणना और वार्स बी एन परत के बीच में है, इसलिए यदि मैं सीपीयू में साधन और वार्स इकट्ठा, मेरे कोड इस तरह होगा:

cpu_gather = [] 
label_batches = [] 
for i in range(num_gpu): 
    with tf.device('/gpu:%d' % i): 
     with tf.variable_scope('block1', reuse=i > 0): 
      image_batch, label_batch = cifar_input.build_input('cifar10', train_data_path, batch_size, 'train') 
      label_batches.append(label_batch) 

      x = _conv('weights', image_batch, 3, 3, 16, _stride_arr(1)) 
      block1_gather.append(x) 

with tf.device('/cpu:0'): 
    print block1_gather[0].get_shape() 
    x1 = tf.concat(block1_gather, 0) 
    # print x1.get_shape() 
    mean, variance = tf.nn.moments(x1, [0, 1, 2], name='moments') 

for i in range(num_gpu): 
    with tf.device('/gpu:%d' % i): 
     with tf.variable_scope('block2', reuse=i > 0): 
      shape = cpu_gather[i].get_shape().as_list() 
      assert len(shape) in [2, 4] 
      n_out = shape[-1] 
      beta, gamma, moving_mean, moving_var = get_bn_variables(n_out, True, True) 

      x = tf.nn.batch_normalization(
       cpu_gather[i], mean, variance, beta, gamma, 0.00001) 

      x = _relu(x) 

सिर्फ एक बी एन परत के लिए है। सीपीयू में आंकड़ों को इकट्ठा करने के लिए, मुझे कोड तोड़ना है। अगर मेरे पास 100 से अधिक बीएन परतें हैं, तो यह बोझिल होगी।

मैं उन पुस्तकालयों में विशेषज्ञ नहीं हूं इसलिए शायद कुछ गलतफहमी हो, मेरी त्रुटियों को इंगित करने के लिए स्वतंत्र महसूस करें।

मुझे प्रशिक्षण की गति के बारे में ज्यादा परवाह नहीं है। मैं छवि विभाजन कर रहा हूं जो बहुत अधिक GPU स्मृति का उपभोग करता है और बीएन को स्थिर आंकड़ों के लिए उचित बैच आकार (उदाहरण के लिए 16 से अधिक) की आवश्यकता होती है। तो बहु-जीपीयू का उपयोग अनिवार्य है। मेरी राय में, tensorflow सबसे अच्छा विकल्प हो सकता है लेकिन मैं ब्रेकिंग कोड समस्या का समाधान नहीं कर सकता। अन्य पुस्तकालयों के साथ समाधान भी स्वागत किया जाएगा।

+0

कोई टिप्पणी – Seven

+0

की सराहना की जाती है ऐसा लगता है कि [sync_bn_layer] (https://github.com/yjxiong/caffe/blob/action_recog/src/caffe/layers/sync_bn_layer.cu) इसे कैफ़े में कर सकता है। – Seven

उत्तर

2

मुझे यकीन नहीं है कि मैं आपके प्रश्न को पूरी तरह से समझता हूं, लेकिन बशर्ते आपने अपना वैरिएबल स्कोप सही तरीके से स्थापित किया हो, tf.GraphKeys.UPDATE_OPS संग्रह में आपके प्रत्येक टावर के लिए स्वचालित रूप से अपडेट बैच_नॉर्म होना चाहिए। यदि सभी अद्यतन_ओप्स सिंक्रनाइज़ रूप से लागू होते हैं, तो वे पैरामीटर सर्वर द्वारा पूरी तरह से औसत होंगे, आपको केवल यह सुनिश्चित करना होगा कि आपके औसत से पहले अपडेट लागू होते हैं और ग्रेडियेंट लागू होते हैं। (अगर मैं आपके इरादों को सही ढंग से समझता हूं)।

परिवर्तनीय दायरे के कारण अद्यतन ओप के प्रत्येक सेट एक ही चर अपडेट करेगा, इसलिए अपडेट ऑप्स को सिंक्रनाइज़ करने के लिए आपको केवल अपडेट ऑप्स के पूर्ण सेट पर ग्रिडेंट गणना की गेट है। UPDATE_OPS में किसी भी बाहरी ओप को हथियाने से बचने के लिए आपको अपने सभी बैच मानक परतों को एक name_scope में भी समाहित करना चाहिए। नीचे दिए गए कोड कंकाल:

update_ops = [] 
for i, device in enumerate(devices): 
    with tf.variable_scope('foo', reuse=bool(i > 0)): 
    with tf.name_scope('tower_%d' % i) as name_scope: 
     with tf.device(device): 
     # Put as many batch_norm layers as you want here 
     update_ops.extend(tf.get_collection(tf.GraphKeys.UPDATE_OPS, 
              name_scope)) 
# make gradient calculation ops here 
with tf.device(averaging_device): 
    with tf.control_dependencies(update_ops): 
    # average and apply gradients. 

आपको कुछ मौजूदा कोड पर इस कोशिश करना चाहते हैं, तो बस यहाँ if i == 0 लाइन को हटाने की कोशिश: आप कुछ धीमी गति से नीचे देखने के लिए जा रहे हैं https://github.com/tensorflow/models/blob/master/tutorials/image/cifar10_estimator/cifar10_main.py#L115

(हम आम तौर पर केवल एक टॉवर का उपयोग इस कारण से बैच मानक आंकड़ों की गणना करने के लिए), लेकिन यह वही करना चाहिए जो आप चाहते हैं।

+0

धन्यवाद एली बिक्स्बी।क्या आपने कई जीपीयू के साथ प्रशिक्षण बीएन की सफलता हासिल की। कृपया मेरा प्रश्न देखें और मुझे कुछ टिप्पणियां दें https://stackoverflow.com/questions/48150720/how-to-update-variable-of-batchnorm-in-multiple-gpus-in-tensorflow – Jame

+0

धन्यवाद @Eli Bixby आपके लिए जवाब, लेकिन खेद है कि कुछ गलतियां हो सकती हैं। बीएन के लिए, न केवल 'आंकड़े' हैं जिन्हें जमा किया जाना चाहिए, या अपडेट किया जाना चाहिए। प्रत्येक बार वापस प्रसारित ग्रेडियेंट भी माना जाना चाहिए। यदि छोटे बैच आकार का उपयोग किया जाता है, तो ग्रेडियेंट बिल्कुल स्थिर नहीं होते हैं। आपने यहां जो प्रस्ताव दिया है, वह सिर्फ अग्रेषण के लिए है, पिछड़ा वर्ग ऑटो-भेदभाव द्वारा गणना की जाती है और सही ढंग से नहीं की जाती है। – Seven

+0

आपको एक बड़े पर्याप्त बैच आकार का उपयोग करना चाहिए जो प्रत्येक जीपीयू संतृप्त है। हमारे अनुभव में यह बहुत बड़ा है जब भी GPUs के बीच sharded batch_norm के लिए स्थिर ग्रेडियेंट का उत्पादन करने के लिए केवल हमारे अनुभव में एक जीपीयू शार्ड से ग्रेडियेंट प्रसारित करके (कोड जो मैंने लिंक किया है) देखें। इसमें देख रहे हैं AFAICT वर्तमान उच्च स्तर के बैच मानक कार्यों के साथ आवेदन से पहले बैच मानक ग्रेडियेंट औसत करने का कोई तरीका नहीं है, आपको इसे निम्न स्तर के टीएफ में लागू करना होगा। –

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