ডেটাসেট.ম্যাপ, ডেটাসেট.প্রিফেট এবং ডেটাসেট.শ্যাফলে বাফার_সাইজের অর্থ


101

টেনসরফ্লো ডকুমেন্টেশন অনুসারে , ক্লাসের পদ্ধতি prefetchএবং mapপদ্ধতিগুলি tf.contrib.data.Datasetউভয়ের একটি প্যারামিটার বলে buffer_size

জন্য prefetchপদ্ধতি, প্যারামিটার হিসাবে পরিচিত হয় buffer_sizeএবং ডকুমেন্টেশন অনুযায়ী:

বাফার_সাইজ: একটি tf.int64 স্কেলার tf.Tensor, সর্বাধিক সংখ্যক উপাদানগুলির উপস্থাপনা যা প্রিফেকিংয়ের সময় বাফার হবে।

জন্য mapপদ্ধতি, প্যারামিটার হিসাবে পরিচিত হয় output_buffer_sizeএবং ডকুমেন্টেশন অনুযায়ী:

আউটপুট_বাফার_সাইজ: (ptionচ্ছিক) একটি 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উপরোক্ত স্নিপেটে পরামিতিগুলি কী ভূমিকা পালন করছে ?


4
404 "ডকুমেন্টেশন" লিঙ্ক পাওয়া যায় নি।
প্রদীপ সিং

উত্তর:


151

টিএল; ডিআর তাদের একই নাম থাকা সত্ত্বেও এই যুক্তিগুলির বেশ পার্থক্যযুক্ত অর্থ রয়েছে। 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_sizebuffer_sizebuffer_size1তারপরে আপনি কোনও বদল হবেন না। খুব বড় ডেটাসেটের জন্য, একটি আদর্শ "যথেষ্ট ভাল" পদ্ধতির প্রশিক্ষণ নেওয়ার আগে একবারে এলোমেলোভাবে ডেটা একাধিক ফাইলগুলিতে ছড়িয়ে দেওয়া, তারপরে ফাইলের নামগুলি সমানভাবে বদলানো এবং তারপরে একটি ছোট শাফল বাফার ব্যবহার করা হয়। যাইহোক, উপযুক্ত পছন্দ আপনার প্রশিক্ষণ কাজের সঠিক প্রকৃতির উপর নির্ভর করবে।



এই ব্যাখ্যাটির জন্য, আমার এখনও কিছু বিভ্রান্তি রয়েছে tf.data.Dataset.shuffle()। আমি সঠিক বদলে যাওয়া প্রক্রিয়া জানতে চাই। বলুন, প্রথম batch_sizeনমুনাগুলি এলোমেলোভাবে প্রথম buffer_sizeউপাদানগুলি থেকে বেছে নেওয়া হয়েছে , ইত্যাদি।
বিএস তিনি

4
@ মিঃ আইআইইউসি বদলানো ফাইলের নামগুলি গুরুত্বপূর্ণ কারণ অন্যথায় প্রতিটি যুগের ব্যাচগুলিতে একই উপাদান দেখতে পাবেন 0 ... 999; এবং ব্যাচগুলিতে 1000.1999; ইত্যাদি, যেখানে আমি 1 ফাইল = 1000 ব্যাচ ধরে নিই। এমনকি ফাইলের নাম পরিবর্তনও হওয়া সত্ত্বেও এখনও কিছু অ-র‌্যান্ডম রয়েছে: কারণ ফাইল # কের উদাহরণগুলি প্রতিটি যুগের মধ্যে একে অপরের নিকটে রয়েছে। ফাইল খুব সহজেই এলোমেলো হওয়ায় এটি খুব খারাপ হতে পারে না; এখনও কিছু ক্ষেত্রে, এমনকি যে প্রশিক্ষণ জগাখিচুড়ি করতে পারে। নিখুঁত সাফল্য অর্জনের একমাত্র উপায় হ'ল buffer_sizeফাইলের আকারের সমান হয়ে যাওয়া (এবং অবশ্যই ফাইলগুলিকে বদলানো)।
সর্বাধিক

টেনসরফ্লো আরসি 15.0। সঙ্গে dataset.shuffle(buffer_size=1)অদলবদল এখনও ঘটে। কোন চিন্তা?
সের্গে বুশমানভ

@ সের্গে বুশমানভ এটি আপনার রদবদলের আগে রূপান্তরের উপর নির্ভর করতে পারে, যেমন: তালিকা_ফায়ালস (), যা ডিফল্টরূপে প্রতিটি পর্বের শুরুতে ফাইলের নামগুলি পরিবর্তন করে।
জিয়াওলং

130

গুরুত্ব 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ফাইলের নাম নেবে এবং এটিকে তার বাফারে রাখবে , তারপরে এলোমেলোভাবে একটি বেছে নিন at যেহেতু প্রথম সমস্ত 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...

গ্রহনের বিষয়টি সর্বদা ডাবল চেক করা যাচল করা কী করবে। এই ত্রুটিগুলি ধরার একটি ভাল উপায় হতে পারে সময়ের সাথে সাথে ব্যাচগুলির বিতরণ চক্রান্ত করা (নিশ্চিত করুন যে ব্যাচে আমাদের প্রশিক্ষণের সেট হিসাবে অর্ধ বিড়াল এবং আমাদের উদাহরণে অর্ধ বিড়াল এবং বিড়াল বিড়াল রয়েছে) the


4
পরবর্তী নমুনাটি সর্বদা বাফার থেকে বেছে নেওয়া হয় (আকারটি এখানে 1000)। সুতরাং প্রথম নমুনাটি প্রথম 1000 ফাইলের নাম থেকে নেওয়া হয়। বাফারটি 999 আকারে কমে যায়, সুতরাং এটি পরবর্তী ইনপুট নেয় ( filename_01001) এবং এটি যুক্ত করে। দ্বিতীয় নমুনাটি এ 1000 ফাইলের নামগুলি থেকে এলোমেলোভাবে নেওয়া হয় (1001 প্রথম ফাইলের নাম বিয়োগ প্রথম নমুনা)।
অলিভিয়ার মইনড্রোট

4
এই নিম্ন বাফার আকারের বিষয়টি হ'ল আপনার প্রথম ব্যাচে কেবল বিড়াল থাকবে। সুতরাং মডেল তুচ্ছভাবে কেবল "বিড়াল" ভবিষ্যদ্বাণী করতে শিখবে। নেটওয়ার্কটি প্রশিক্ষণের সর্বোত্তম উপায় হ'ল একই পরিমাণে "বিড়াল" এবং "নন বিড়াল" সহ ব্যাচগুলি।
অলিভিয়ার মইনড্রোট

4
আপনি tf.summary.histogramসময়ের সাথে সাথে লেবেলের বিতরণের প্লট করতে ব্যবহার করতে পারেন ।
অলিভিয়ার মইনড্রোট

4
টাইপো নয় :) ডেটাসেটে প্রতিটি শ্রেণীর 10k চিত্র রয়েছে তাই মোট বাফার আকার 20k এর উপরে হওয়া উচিত। তবে উপরের উদাহরণে, আমি 1 কে বাফার আকার নিয়েছি যা খুব কম।
অলিভিয়ার মইনড্রোট

4
হ্যাঁ বাফার আকারটি ডেটাসেটের আকারে সেট করা ভাল is ডেটাসেটের আকারের উপরে যে কোনও উপায়ে যাই হোক না কেন অকার্যকর হবে (এবং আপনি যদি আপনার ডেটাসেটটি বদলানোর আগে পুনরাবৃত্তি না করেন তবে বাফারটি ডেটাসেটের চেয়ে বড় হতে পারে না)।
অলিভিয়ার মইনড্রোট

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 [ 81] [366] [49] [295] [399] [177] [507] [288] [524] [401] [386] [89] [371] [181] [489] [172] [159] [195] [232] [160] [352] [495] [241] [435] [127] [268] [429] [382] [479] [519] [116] [395] [165] [233 ] [37] [486] [553] [111] [525] [170] [571] [215] [530] [47] [291] [558] [21] [245] [514] [103] [ 45] [545] [219] [468] [338] [392] [54] [139] [339] [448] [471] [589] [321] [223] [311] [234] [314]


4
এটি ইঙ্গিত দেয় যে পুনরুক্তকারী দ্বারা উত্পাদিত প্রতিটি উপাদানগুলির জন্য, বাফারটি ডেটাসেটের संबंधित পরবর্তী উপাদান দিয়ে পূরণ করা হচ্ছে যা আগে বাফারে ছিল না।
অ্যালেক্স

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

আমি দেখতে পেলাম যে @ অলিভিয়ার-মাইন্ড্রোট সত্যই সঠিক, আমি @ হাউটারো ওরেকি প্রদত্ত কোডটি চেষ্টা করেছি, @ ম্যাক্স দ্বারা নির্দেশিত পরিবর্তনগুলি ব্যবহার করে। আমি যে কোডটি ব্যবহার করেছি তা নিম্নলিখিত:

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 থেকে পর্যন্ত একটি সংখ্যা ছিল (buffer_size + + (ঝ * batch_size)), যেখানে আমি যতবার আপনি দৌড়ে next_element । আমি মনে করি এটি যেভাবে কাজ করছে তা নিম্নলিখিত। প্রথমত, 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. সুতরাং প্রশিক্ষণের সময় অভিন্ন নমুনা নিশ্চিত করতে আপনার ব্যাচ_সাইজের মধ্যে আপনার ভারসাম্যপূর্ণ নমুনার নিশ্চয়তা দিতে হবে।

@ মিঃ কর্মক্ষমতা সম্পর্কে যা বলেছিলেন তাও আমি পরীক্ষা করে দেখলাম যে ব্যাচ_সাইজ সেই পরিমাণ নমুনাকে স্মৃতিতে প্রিফেক করবে। আমি নিম্নলিখিত কোড ব্যবহার করে এটি পরীক্ষা করেছি:

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

ডেটাসেট.প্রিফেট্চ (10) পরিমাণ পরিবর্তন করার ফলে ব্যবহৃত মেমরির কোনও পরিবর্তন হয়নি (র‌্যাম)। এটি গুরুত্বপূর্ণ যখন আপনার ডেটা র‍্যামের সাথে খাপ খায় না। আমি মনে করি সবচেয়ে ভাল উপায় হ'ল আপনার ডেটা / ফাইল_নামগুলি tf.dataset খাওয়ানোর আগে এলোমেলো করে দেওয়া এবং তারপরে বাফার_সাইজ ব্যবহার করে বাফার আকারটি নিয়ন্ত্রণ করা ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.