मीनिंग ऑफ बफर_साइसेट इन दैटसेट.मैप, डाटसेट.परफैच और डाटसेट.शफल


100

TensorFlow प्रलेखन के अनुसार , prefetchऔर कक्षा के mapतरीके tf.contrib.data.Dataset, दोनों में एक पैरामीटर है buffer_size

के लिए prefetchविधि, पैरामीटर के रूप में जाना जाता है buffer_sizeऔर प्रलेखन के अनुसार:

बफर_साइज़: एक tf.int64 स्केलर tf.Tensor, अधिकतम संख्या तत्वों का प्रतिनिधित्व करता है जो प्रीफ़ैचिंग होने पर बफ़र हो जाएंगे।

के लिए mapविधि, पैरामीटर के रूप में जाना जाता है output_buffer_sizeऔर प्रलेखन के अनुसार:

output_buffer_size: (वैकल्पिक) एक tf.int64 स्केलर tf.Tensor, बफ़र किए जाने वाले संसाधित तत्वों की अधिकतम संख्या का प्रतिनिधित्व करेगा।

इसी तरह shuffleविधि के लिए, एक ही मात्रा प्रकट होती है और प्रलेखन के अनुसार:

बफर_साइज़: एक tf.int64 स्केलर tf.Tensor, इस डेटासेट से उन तत्वों की संख्या का प्रतिनिधित्व करता है जिनसे नया डेटासेट सैंपल करेगा।

इन मापदंडों के बीच क्या संबंध है?

मान लीजिए कि मैं एक Datasetवस्तु बनाता हूं :

 tr_data = TFRecordDataset(trainfilenames)
    tr_data = tr_data.map(providefortraining, output_buffer_size=10 * trainbatchsize, num_parallel_calls\
=5)
    tr_data = tr_data.shuffle(buffer_size= 100 * trainbatchsize)
    tr_data = tr_data.prefetch(buffer_size = 10 * trainbatchsize)
    tr_data = tr_data.batch(trainbatchsize)

bufferउपरोक्त स्निपेट में मापदंडों द्वारा क्या भूमिका निभाई जा रही है ?


1
404 "प्रलेखन" के लिए लिंक नहीं मिला।
प्रदीप सिंह

जवाबों:


150

TL, DR , उनके समान नामों के बावजूद, इन तर्कों का काफी अंतर है। buffer_sizeमें Dataset.shuffle()आपके डेटासेट की अनियमितता, और इसलिए जिस क्रम में तत्वों उत्पादित कर रहे हैं प्रभावित कर सकते हैं। buffer_sizeमें Dataset.prefetch()केवल समय यह अगले तत्व का निर्माण करने के लेता प्रभावित करता है।


buffer_sizeमें तर्क tf.data.Dataset.prefetch()और output_buffer_sizeमें तर्क tf.contrib.data.Dataset.map()धुन करने का तरीका प्रदान प्रदर्शन दोनों बहस TensorFlow बता अधिक से अधिक की एक बफर बनाने के लिए: अपने इनपुट पाइप लाइन के buffer_sizeतत्वों, और एक पृष्ठभूमि धागा पृष्ठभूमि में है कि बफर भरने के लिए। (ध्यान दें कि हमने उस output_buffer_sizeतर्क को हटा दिया Dataset.map()जब वह से स्थानांतरित किया tf.contrib.dataगया था tf.data। नया कोड समान व्यवहार प्राप्त करने के Dataset.prefetch()बाद उपयोग करना चाहिए map()।)

प्रीफ़ेच बफर को जोड़ने से डाउनस्ट्रीम संगणना के साथ डेटा के प्रीप्रोसेसिंग को ओवरलैप करके प्रदर्शन में सुधार हो सकता है। आमतौर पर पाइपलाइन के बहुत अंत में एक छोटे प्रीफैच बफर (शायद सिर्फ एक तत्व के साथ) को जोड़ना सबसे अधिक उपयोगी होता है, लेकिन अधिक जटिल पाइपलाइन अतिरिक्त प्रीफैचिंग से लाभ उठा सकते हैं, खासकर जब किसी एकल तत्व का उत्पादन करने का समय भिन्न हो सकता है।

इसके विपरीत, buffer_sizeतर्क परिवर्तन tf.data.Dataset.shuffle()की यादृच्छिकता को प्रभावित करता है । हमने Dataset.shuffle()ऐसे tf.train.shuffle_batch()डेटासेट को संभालने के लिए ट्रांसफ़ॉर्मेशन ( फंक्शन की तरह जो इसे रिप्लेस करता है) डिज़ाइन किया है जो मेमोरी में फिट होने के लिए बहुत बड़े हैं। संपूर्ण डेटासेट में फेरबदल करने के बजाय, यह buffer_sizeतत्वों का एक बफर बनाए रखता है , और बेतरतीब ढंग से उस बफर से अगले तत्व का चयन करता है (यदि उपलब्ध है, तो अगले इनपुट तत्व के साथ इसे प्रतिस्थापित करना)। परिवर्तन के मूल्य को बदलना एक buffer_sizeसमान फेरबदल है: यदि buffer_sizeडेटासेट में तत्वों की संख्या से अधिक है, तो आपको एक समान फेरबदल मिलता है; अगर यह होता है1तो आप बिल्कुल नहीं फेरबदल मिलता है। बहुत बड़े डेटासेट के लिए, एक विशिष्ट "अच्छा पर्याप्त" दृष्टिकोण है कि प्रशिक्षण से पहले एक बार डेटा को कई फाइलों में बेतरतीब ढंग से शार्प किया जाए, फिर फाइलनाम को समान रूप से फेरबदल किया जाए, और फिर एक छोटे फेरबदल बफर का उपयोग किया जाए। हालांकि, उपयुक्त विकल्प आपके प्रशिक्षण कार्य की सटीक प्रकृति पर निर्भर करेगा।



इस स्पष्टीकरण के लिए, मेरे पास अभी भी कुछ भ्रम हैं tf.data.Dataset.shuffle()। मैं सटीक फेरबदल प्रक्रिया जानना चाहूंगा। कहते हैं, पहले batch_sizeनमूने बेतरतीब ढंग से पहले buffer_sizeतत्वों से चुने गए हैं, और इसी तरह।
Bs He

1
@mrry IIUC फेरबदल फाइलनाम महत्वपूर्ण है क्योंकि अन्यथा प्रत्येक युग बैचों में एक ही तत्व को देखेगा ... 999; और बैचों में 1000.1999; आदि, जहां मैं 1 फ़ाइल = 1000 बैचों को मानता हूं। फ़ाइल नाम में फेरबदल के साथ भी, अभी भी कुछ गैर-यादृच्छिकता है: ऐसा इसलिए है क्योंकि फ़ाइल #k से उदाहरण सभी प्रत्येक युग में एक दूसरे के करीब हैं। यह बहुत बुरा नहीं हो सकता है क्योंकि फ़ाइल #k ही यादृच्छिक है; अभी भी कुछ मामलों में, यहां तक ​​कि प्रशिक्षण को गड़बड़ कर सकता है। सही फेरबदल प्राप्त करने का एकमात्र तरीका buffer_sizeफ़ाइल आकार के बराबर सेट करना होगा (और पाठ्यक्रम की फ़ाइलों को फेरबदल करना)।
अधिकतम

Tensorflow rc 15.0। dataset.shuffle(buffer_size=1)फेरबदल के साथ अभी भी होता है। कोई विचार?
सेर्गेई बुशमैनोव

@SergeyBushmanov यह आपके फेरबदल से पहले परिवर्तन पर निर्भर हो सकता है, उदाहरण के लिए list_files (), जो डिफ़ॉल्ट रूप से प्रत्येक युग की शुरुआत में फ़ाइल नाम को फेरबदल करता है।
Xiaolong

129

का महत्व buffer_sizeमेंshuffle()

मैं तनाव @mrry से पिछले जवाब पर अनुवर्ती कार्रवाई करना चाहता था महत्व के buffer_sizeमें tf.data.Dataset.shuffle()

कम होने से buffer_sizeआपको कुछ मामलों में सिर्फ हीनता नहीं मिलेगी : यह आपके पूरे प्रशिक्षण को गड़बड़ कर सकता है।


एक व्यावहारिक उदाहरण: कैट क्लासिफायरियर

उदाहरण के लिए मान लीजिए कि आप चित्रों पर एक कैट क्लासिफायरशिप का प्रशिक्षण ले रहे हैं, और आपका डेटा निम्न तरीके से व्यवस्थित है ( 10000प्रत्येक श्रेणी में छवियों के साथ ):

train/
    cat/
        filename_00001.jpg
        filename_00002.jpg
        ...
    not_cat/
        filename_10001.jpg
        filename_10002.jpg
        ...

डेटा इनपुट करने का एक मानक तरीका tf.dataफ़ाइलनामों की सूची और संबंधित लेबल की सूची होना और tf.data.Dataset.from_tensor_slices()डेटासेट बनाने के लिए उपयोग करना हो सकता है:

filenames = ["filename_00001.jpg", "filename_00002.jpg", ..., 
             "filename_10001.jpg", "filename_10002.jpg", ...]
labels = [1, 1, ..., 0, 0...]  # 1 for cat, 0 for not_cat

dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
dataset = dataset.shuffle(buffer_size=1000)  # 1000 should be enough right?
dataset = dataset.map(...)  # transform to images, preprocess, repeat, batch...

बड़ा मुद्दा ऊपर कोड के साथ कि डाटासेट वास्तव में सही तरीके से नहीं फेरबदल किया जाएगा। एक युग की पहली छमाही के लिए, हम केवल बिल्ली की छवियां देखेंगे, और दूसरी छमाही के लिए केवल गैर-बिल्ली चित्र। इससे प्रशिक्षण को काफी नुकसान होगा।
प्रशिक्षण की शुरुआत में, डेटासेट पहले 1000फ़ाइलनाम को ले जाएगा और उन्हें इसके बफर में डाल देगा, फिर उनमें से एक को यादृच्छिक रूप से उठाएगा। चूंकि सभी पहली 1000छवियां बिल्ली की छवियां हैं, इसलिए हम केवल शुरुआत में बिल्ली की छवियां चुनेंगे।

यहाँ पर यह सुनिश्चित करना है कि पहले buffer_sizeसे बड़ा है 20000, या अग्रिम में फेरबदल करना है filenamesऔर labels(स्पष्ट रूप से समान सूचकांकों के साथ)।

चूंकि मेमोरी में सभी फाइलनाम और लेबल को स्टोर करना कोई समस्या नहीं है, हम वास्तव buffer_size = len(filenames)में यह सुनिश्चित करने के लिए उपयोग कर सकते हैं कि सब कुछ एक साथ मिला दिया जाएगा। tf.data.Dataset.shuffle()भारी परिवर्तनों को लागू करने से पहले कॉल करना सुनिश्चित करें (जैसे छवियों को पढ़ना, उन्हें संसाधित करना, बैच करना ...)।

dataset = tf.data.Dataset.from_tensor_slices((filenames, labels))
dataset = dataset.shuffle(buffer_size=len(filenames)) 
dataset = dataset.map(...)  # transform to images, preprocess, repeat, batch...

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


1
अगला नमूना हमेशा बफर से चुना जाता है (आकार 1000 के यहाँ)। तो पहला नमूना पहले 1000 फ़ाइलनामों से लिया गया है। बफर का आकार 999 तक घट जाता है, इसलिए यह अगला इनपुट लेता है ( filename_01001) और इसे जोड़ता है। दूसरा नमूना इन 1000 फ़ाइलनामों से यादृच्छिक रूप से लिया गया है (1001 प्रथम फ़ाइल नाम का पहला नमूना)।
ओलिवियर मोइंड्रोट

1
इस निम्न बफ़र आकार के साथ समस्या यह है कि आपके पहले बैच में केवल बिल्लियाँ होंगी। तो मॉडल तुच्छ रूप से केवल "बिल्ली" की भविष्यवाणी करना सीखेगा। नेटवर्क को प्रशिक्षित करने का सबसे अच्छा तरीका "बिल्ली" और "गैर बिल्ली" की समान मात्रा के साथ बैच हैं।
ओलिवियर मोइंड्रोट

1
आप tf.summary.histogramसमय के साथ लेबल के वितरण की साजिश का उपयोग कर सकते हैं ।
ओलिवियर मोइंड्रोट

3
टाइपो नहीं: डेटासेट में प्रत्येक वर्ग की 10k छवियां होती हैं, इसलिए कुल बफर आकार 20k से ऊपर होना चाहिए। लेकिन ऊपर के उदाहरण में, मैंने 1k का बफर आकार लिया जो बहुत कम है।
ओलिवियर मोइंड्रोट

1
हां, बफर साइज को डाटासेट साइज में सेट करना आम तौर पर ठीक है। डेटासेट आकार से ऊपर कुछ भी बेकार होगा (और जब तक आप फेरबदल करने से पहले अपने डेटासेट को दोहराते नहीं हैं, बफर डेटासेट से बड़ा नहीं हो सकता है)।
ओलिवियर मोइंड्रोट

7

कोड

import tensorflow as tf
def shuffle():
    ds = list(range(0,1000))
    dataset = tf.data.Dataset.from_tensor_slices(ds)
    dataset=dataset.shuffle(buffer_size=500)
    dataset = dataset.batch(batch_size=1)
    iterator = dataset.make_initializable_iterator()
    next_element=iterator.get_next()
    init_op = iterator.initializer
    with tf.Session() as sess:
        sess.run(init_op)
        for i in range(100):
            print(sess.run(next_element), end='')

shuffle()

उत्पादन

[298] [326] [2] [351] [92] [398] [72] [134] [404] [378] [238] [131] [369] [324] [35] [182] [441 ] [370] [372] [144] [77] [11] [199] [65] [346] [418] [493] [343] [444] [470] [222] [83] [61] [ १] [३६६] [४ ९] [३ ९ ५] [३ ९९ ] [१ [[] [५० 36] [२] [] [५२४ ] [३ ]६] [३ ]६] []1१] [१ ]१] [४9 ९] [१ ]२ ] [१५ ९] [१ ९ ५] [२३२] [१६०] [३५२] [४ ९ ५] [२४१] [३४४] [१२]] [३ ]२] [४२ ९ ] [३ ]२] [४9 ९] [५१ ९] [११६] [३ ९ ५] [१६५] [२३३] ] [37] [486] [553] [111] [525] [170] [571] [215] [530] [47] [291] [558] [21] [245] [514] [103] [ ४५] [५४५] [२१ ९] [४६ [] [३३ [] [३ ९ २] [५४] [१३ ९] [३३ ९] [४४9] [४1१] [५] ९] [३२१] [३२१] [३११] [२३४] [३१४]


2
यह इंगित करता है कि इट्रेटर द्वारा उत्पादित प्रत्येक तत्व के लिए, बफर को डेटासेट के संबंधित अगले तत्व से भरा जा रहा है जो पहले बफर में नहीं था।
एलेक्स

2

दरअसल @ ओलिवियर-मूइंड्रॉट का जवाब सही नहीं है।

आप फ़ाइल नाम और लेबल बनाकर उसका सत्यापन कर सकते हैं क्योंकि वह / वह फेरबदल मूल्यों का उल्लेख करता है और प्रिंट करता है।

आप देखेंगे कि प्रत्येक फेरबदल प्रक्रिया बेतरतीब ढंग से नमूना उत्पन्न करेगी, जो डेटासेट से बफर आकार के बराबर होती है।

dataset = dataset.shuffle(buffer_size=1000)
iterator = dataset.make_one_shot_iterator()
next_element = iterator.get_next()
with tf.Session() as sess:
    for i in range(1000):
        print(sess.run(next_element))

2

मैंने पाया कि @ ओलिवियर-मोइन्ड्रॉट वास्तव में सही है, मैंने @ हेक्सो द्वारा दिए गए संशोधनों का उपयोग करके @Houtarou Oreki द्वारा प्रदान किए गए कोड की कोशिश की। मेरे द्वारा उपयोग किया गया कोड निम्नलिखित था:

fake_data = np.concatenate((np.arange(1,500,1),np.zeros(500)))

dataset = tf.data.Dataset.from_tensor_slices(fake_data)
dataset=dataset.shuffle(buffer_size=100)
dataset = dataset.batch(batch_size=10)
iterator = dataset.make_initializable_iterator()
next_element=iterator.get_next()

init_op = iterator.initializer

with tf.Session() as sess:
    sess.run(init_op)
    for i in range(50):
        print(i)
        salida = np.array(sess.run(next_element))
        print(salida)
        print(salida.max())

कोड आउटपुट वास्तव में 1 से लेकर (बफर_साइज + (i * बैच_साइज)) तक की संख्या है , जहां मैं आपके द्वारा अगली बार चलाने की संख्या है । मुझे लगता है कि जिस तरह से यह काम कर रहा है वह निम्नलिखित है। सबसे पहले, buffer_size नमूनों से क्रम में उठाया जाता है fake_data । फिर एक-एक करके बैच_साइज के नमूने बफर से उठाए जाते हैं। हर बार जब बैच का नमूना बफर से लिया जाता है तो उसे नकली_डाटा से क्रम में लिया जाता है । मैंने निम्नलिखित कोड का उपयोग करके इस अंतिम चीज़ का परीक्षण किया:

aux = 0
for j in range (10000):
    with tf.Session() as sess:
        sess.run(init_op)
        salida = np.array(sess.run(next_element))
        if salida.max() > aux:
            aux = salida.max()

print(aux)

कोड द्वारा उत्पादित अधिकतम मूल्य 109 था। इसलिए आपको प्रशिक्षण के दौरान एक समान नमूना सुनिश्चित करने के लिए अपने बैच_साइज के भीतर एक संतुलित नमूने का आश्वासन देना होगा।

मैं इस पर जांच की क्या @mrry प्रदर्शन के बारे में कहा, मैंने पाया कि batch_size स्मृति में नमूनों की उस राशि prefetch होगा। मैंने निम्नलिखित कोड का उपयोग करके इसका परीक्षण किया:

dataset = dataset.shuffle(buffer_size=20)
dataset = dataset.prefetch(10)
dataset = dataset.batch(batch_size=5)

डेटासेट बदलने के कारण डेटा (RAM) का उपयोग मेमोरी (RAM) में कोई परिवर्तन नहीं हुआ। यह महत्वपूर्ण है जब आपका डेटा रैम में फिट नहीं होता है। मुझे लगता है कि सबसे अच्छा तरीका है कि आप अपने डेटा / file_names को फेरबदल करने से पहले उन्हें tf.dataset को खिलाएं, और फिर बफर_साइज़ का उपयोग करके बफर आकार को नियंत्रित करें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.