अद्यतन - 1/15/2020 : छोटे बैच आकारों के लिए मौजूदा सबसे अच्छा अभ्यास सीधे मॉडल को इनपुट खिलाने के लिए होना चाहिए - यानी preds = model(x)
, और अगर परतें ट्रेन / इंजेक्शन पर अलग तरह से व्यवहार करती हैं, तो model(x, training=False)
। नवीनतम प्रतिबद्ध के अनुसार, यह अब प्रलेखित है ।
मैंने इन्हें बेंचमार्क नहीं किया है, लेकिन Git चर्चा के अनुसार , यह भी कोशिश करने लायक है predict_on_batch()
- विशेष रूप से TF 2.1 में सुधार के साथ।
अंतिम अपराधी : self._experimental_run_tf_function = True
। यह प्रायोगिक है । लेकिन यह वास्तव में बुरा नहीं है।
किसी भी TensorFlow देव पढ़ने के लिए: अपने कोड को साफ करें । यह एक गड़बड़ है। और यह महत्वपूर्ण कोडिंग प्रथाओं का उल्लंघन करता है, जैसे कि एक फ़ंक्शन एक काम करता है ; _process_inputs
एक करता है बहुत से "प्रक्रिया आदानों", के लिए एक ही अधिक _standardize_user_data
। "मैं पर्याप्त भुगतान नहीं कर रहा हूं" - लेकिन आप भुगतान करते हैं , अतिरिक्त समय में अपने सामान को समझने में खर्च करते हैं, और उपयोगकर्ताओं में आपके इश्यू पृष्ठ को बग के साथ आसानी से भरना एक स्पष्ट कोड के साथ हल किया जाता है।
सारांश : यह केवल थोड़ा धीमा है compile()
।
compile()
एक आंतरिक झंडे को सेट करता है जो एक अलग भविष्यवाणी फ़ंक्शन को असाइन करता है predict
। यह फ़ंक्शन प्रत्येक कॉल पर एक नया ग्राफ बनाता है, जो इसे अनलेडेड के सापेक्ष धीमा कर देता है। हालाँकि, अंतर केवल तब स्पष्ट होता है जब ट्रेन का समय डाटा प्रोसेसिंग समय से बहुत कम होता है । यदि हम मॉडल का आकार कम से कम मध्य आकार में बढ़ाते हैं , तो दोनों समान हो जाते हैं। सबसे नीचे कोड देखें।
डेटा प्रोसेसिंग समय में यह मामूली वृद्धि प्रवर्धित ग्राफ क्षमता द्वारा मुआवजा से अधिक है। चूँकि यह केवल एक मॉडल ग्राफ को चारों ओर रखने के लिए अधिक कुशल है, इसलिए पूर्व-संकलन को छोड़ दिया जाता है। फिर भी : यदि आपका मॉडल डेटा के सापेक्ष छोटा है, तो आप compile()
मॉडल इंट्रेंस के बिना बेहतर हैं । वर्कअराउंड के लिए मेरा अन्य उत्तर देखें।
मुझे क्या करना चाहिए?
मॉडल प्रदर्शन की तुलना बनाम संकलित के रूप में मैं नीचे कोड में है।
- संकलित तेजी से होता है :
predict
संकलित मॉडल पर चलता है ।
- संकलित धीमी है :
predict
एक असंचित मॉडल पर चलाएँ ।
हां, दोनों संभव हैं, और यह (1) डेटा आकार पर निर्भर करेगा; (2) मॉडल का आकार; (३) हार्डवेयर। नीचे स्थित कोड वास्तव में संकलित मॉडल को तेजी से दिखाता है , लेकिन 10 पुनरावृत्तियों एक छोटा नमूना है। "कैसे-करें" के लिए मेरे दूसरे उत्तर में "वर्कअराउंड" देखें।
विवरण :
यह डिबग करने में थोड़ा समय लगा, लेकिन मजेदार था। नीचे मैंने अपने द्वारा खोजे गए प्रमुख दोषियों का वर्णन किया है, कुछ प्रासंगिक दस्तावेज़ीकरण का हवाला देते हैं, और प्रोफाइलर परिणाम दिखाते हैं जो अंतिम अड़चन का कारण बनते हैं।
( FLAG == self.experimental_run_tf_function
, संक्षिप्तता के लिए)
Model
के साथ डिफ़ॉल्ट को दर्शाता है द्वारा FLAG=False
। compile()
इसे सेट करता है True
।
predict()
भविष्यवाणी समारोह प्राप्त करना शामिल है, func = self._select_training_loop(x)
- बिना किसी विशेष कावड़ के पास
predict
और compile
, अन्य सभी झंडे ऐसे हैं:
- (ए)
FLAG==True
->func = training_v2.Loop()
- (बी)
FLAG==False
->func = training_arrays.ArrayLikeTrainingLoop()
- से स्रोत कोड docstring , (ए) से भारी मात्रा में ग्राफ निर्भर है और अधिक वितरण रणनीति का उपयोग करता है, और ऑप्स बनाने और ग्राफ तत्व है, जो (कर) "हो सकता है" प्रभाव प्रदर्शन को नष्ट करने से ग्रस्त हैं।
सच्चा अपराधी :, 81% रनटाइम के_process_inputs()
लिए लेखांकन । इसका प्रमुख घटक? , 72% रनटाइम । यह विधि (B) के लिए भी मौजूद नहीं है । एक मध्यम आकार के मॉडल का उपयोग, तथापि, शामिल हैं क्रम के 1% से कम । नीचे कोड, और प्रोफाइलिंग परिणाम का पालन करें।_create_graph_function()
_process_inputs
डेटा प्रोसेसर :
(ए) :, <class 'tensorflow.python.keras.engine.data_adapter.TensorLikeDataAdapter'>
में इस्तेमाल किया _process_inputs()
। प्रासंगिक स्रोत कोड
(बी) :, numpy.ndarray
द्वारा लौटाया गया convert_eager_tensors_to_numpy
। प्रासंगिक स्रोत कोड , और यहां
मॉडल एक्सेल्यूशन फंक्शन (उदाहरण के लिए)
(ए) : वितरण समारोह , और यहां
(बी) : वितरण समारोह (अलग) , और यहां
PROFILER : मेरे अन्य उत्तर में कोड के लिए परिणाम, "छोटे मॉडल", और इस उत्तर में, "मध्यम मॉडल":
छोटे मॉडल : 1000 पुनरावृत्तियों,compile()
छोटे मॉडल : 1000 पुनरावृत्तियों, नहीं compile()
मध्यम मॉडल : 10 पुनरावृत्तियों
प्रलेखन (परोक्ष रूप से) के प्रभाव पर compile()
: स्रोत
अन्य TensorFlow संचालन के विपरीत, हम अजगर संख्यात्मक इनपुट को दहाई में नहीं बदलते हैं। इसके अलावा, उदाहरण के लिए, प्रत्येक विशिष्ट अजगर संख्यात्मक मूल्य के लिए एक नया ग्राफ़ उत्पन्न होता है g(2)
और g(3)
दो नए ग्राफ़ उत्पन्न करेगा
function
इनपुट आकृतियों और डेटाटिप्स के हर अनूठे सेट के लिए एक अलग ग्राफ को इंस्टेंट करता है । उदाहरण के लिए, निम्न कोड स्निपेट का परिणाम तीन अलग-अलग ग्राफ़ों में पता लगाया जाएगा, क्योंकि प्रत्येक इनपुट का एक अलग आकार होता है
एक एकल tf.function ऑब्जेक्ट को हुड के तहत कई कम्प्यूटेशन ग्राफ़ पर मैप करने की आवश्यकता हो सकती है। यह केवल प्रदर्शन के रूप में दिखाई देना चाहिए (अनुरेखण रेखांकन में एक गैर-कम्प्यूटेशनल और मेमोरी लागत है ) लेकिन कार्यक्रम की शुद्धता को प्रभावित नहीं करना चाहिए
COUNTEREXAMPLE :
from tensorflow.keras.layers import Input, Dense, LSTM, Bidirectional, Conv1D
from tensorflow.keras.layers import Flatten, Dropout
from tensorflow.keras.models import Model
import numpy as np
from time import time
def timeit(func, arg, iterations):
t0 = time()
for _ in range(iterations):
func(arg)
print("%.4f sec" % (time() - t0))
batch_size = 32
batch_shape = (batch_size, 400, 16)
ipt = Input(batch_shape=batch_shape)
x = Bidirectional(LSTM(512, activation='relu', return_sequences=True))(ipt)
x = LSTM(512, activation='relu', return_sequences=True)(ipt)
x = Conv1D(128, 400, 1, padding='same')(x)
x = Flatten()(x)
x = Dense(256, activation='relu')(x)
x = Dropout(0.5)(x)
x = Dense(128, activation='relu')(x)
x = Dense(64, activation='relu')(x)
out = Dense(1, activation='sigmoid')(x)
model = Model(ipt, out)
X = np.random.randn(*batch_shape)
timeit(model.predict, X, 10)
model.compile('adam', loss='binary_crossentropy')
timeit(model.predict, X, 10)
आउटपुट :
34.8542 sec
34.7435 sec