TensorFlow 1 की तुलना में TensorFlow 2 बहुत धीमा क्यों है?


137

यह कई उपयोगकर्ताओं द्वारा पाइटोरच पर स्विच करने के कारण के रूप में उद्धृत किया गया है, लेकिन मुझे अभी तक उत्सुक निष्पादन के लिए सबसे महत्वपूर्ण व्यावहारिक गुणवत्ता, गति का त्याग करने का औचित्य / स्पष्टीकरण मिल गया है।

नीचे कोड बेंचमार्किंग प्रदर्शन है, TF1 बनाम TF2 - TF1 47% से 276% तेजी से कहीं भी चल रहा है

मेरा सवाल है: यह ग्राफ या हार्डवेयर स्तर पर ऐसा क्या है, जो इतनी महत्वपूर्ण मंदी देता है?


एक विस्तृत जवाब की तलाश में - मैं पहले से ही व्यापक अवधारणाओं से परिचित हूं। प्रासंगिक गिट

चश्मा : CUDA 10.0.130, cuDNN 7.4.2, पायथन 3.7.4, विंडोज 10, GTX 1070


बेंचमार्क परिणाम :


अद्यतन : नीचे दिए गए कोड के अनुसार ईगर निष्पादन को अक्षम करने से मदद नहीं मिलती है। व्यवहार, हालांकि, असंगत है: कभी-कभी ग्राफ मोड में चलने से काफी मदद मिलती है, अन्य समय यह ईगर के सापेक्ष धीमी गति से चलता है ।

चूंकि टीएफ देव कहीं भी दिखाई नहीं देते हैं, इसलिए मैं खुद इस मामले की जांच करूंगा - लिंक किए गए गितुब मुद्दे में प्रगति का पालन कर सकता हूं।

अद्यतन 2 : स्पष्टीकरण के साथ साझा करने के लिए प्रयोगात्मक परिणामों के टन; आज किया जाना चाहिए।


बेंचमार्क कोड :

# use tensorflow.keras... to benchmark tf.keras; used GPU for all above benchmarks
from keras.layers import Input, Dense, LSTM, Bidirectional, Conv1D
from keras.layers import Flatten, Dropout
from keras.models import Model
from keras.optimizers import Adam
import keras.backend as K
import numpy as np
from time import time

batch_shape = (32, 400, 16)
X, y = make_data(batch_shape)

model_small = make_small_model(batch_shape)
model_small.train_on_batch(X, y)  # skip first iteration which builds graph
timeit(model_small.train_on_batch, 200, X, y)

K.clear_session()  # in my testing, kernel was restarted instead

model_medium = make_medium_model(batch_shape)
model_medium.train_on_batch(X, y)  # skip first iteration which builds graph
timeit(model_medium.train_on_batch, 10, X, y)

उपयोग किए गए कार्य :

def timeit(func, iterations, *args):
    t0 = time()
    for _ in range(iterations):
        func(*args)
    print("Time/iter: %.4f sec" % ((time() - t0) / iterations))

def make_small_model(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(128, 400, strides=4, padding='same')(ipt)
    x     = Flatten()(x)
    x     = Dropout(0.5)(x)
    x     = Dense(64, activation='relu')(x)
    out   = Dense(1,  activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_medium_model(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Bidirectional(LSTM(512, activation='relu', return_sequences=True))(ipt)
    x     = LSTM(512, activation='relu', return_sequences=True)(x)
    x     = Conv1D(128, 400, strides=4, 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)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_data(batch_shape):
    return np.random.randn(*batch_shape), np.random.randint(0, 2, (batch_shape[0], 1))

क्या आपने कभी cProfile का उपयोग इस तरह के उपकरण का विश्लेषण करने के लिए किया है जो उन्हें अलग बनाता है?
१०:१५ पर zihaozhihao

@zihaozhihao मेरे पास है , हालांकि इसके लिए विशेष रूप से नहीं; पिछले लिंक के अनुसार और एक कस्टम ऑप्टिमाइज़र लिखते हुए, मैं पहले से ही कॉल में अंतर से परिचित हूं, लेकिन समझ में नहीं आता है कि दूसरे की तुलना में धीमा क्यों है - और न ही कोई गैर-टीएफ विशेषज्ञ इसे स्रोत से समझ सकता है, जो शीर्ष पर है एक उलझी हुई गड़बड़, सापेक्ष प्रदर्शन का दस्तावेज नहीं है। ग्राफ़ / हार्डवेयर-स्तरीय इंटेल की आवश्यकता होती है, जो प्रोफाइलर प्रदान नहीं करेंगे (जहाँ तक मैं उनका उपयोग करने में सक्षम हूँ)
OverLordGoldDragon

दोनों परीक्षणों में समान संस्करण है?
chabir

आउच .... यदि पुराने केरस पहले से ही प्योरटेक की तुलना में काफी धीमा था, तो अब कल्पना करें।
डैनियल मोलर

मॉडल के आकार के साथ समस्या का पैमाना क्या है? क्या आपने अन्य OS पर समान बेंचमार्क चलाने का प्रयास किया है?
ओकावो

जवाबों:


76

अद्यतन २/१18/२०२० : मैंने २.१ और २.१-रात्रिकालीन अवकाश लिया है; परिणाम मिश्रित हैं। सभी लेकिन एक कॉन्फ़िगर (मॉडल और डेटा आकार) TF2 & TF1 के सर्वश्रेष्ठ की तुलना में तेज़ या अधिक तेज़ है। वह जो धीमा है, और नाटकीय रूप से धीमा है, लार्ज-लार्ज - एस्प है। ग्राफ निष्पादन में ( 1.6x से 2.5x धीमी )।

इसके अलावा, मेरे द्वारा परीक्षण किए गए एक बड़े मॉडल के लिए ग्राफ़ और ईगर के बीच अत्यधिक प्रतिलिपि प्रस्तुत करने योग्य अंतर हैं - यादृच्छिकता / गणना-समानता के माध्यम से व्याख्या करने योग्य नहीं। मैं वर्तमान में इन दावों के लिए समय-सीमा के लिए प्रतिलिपि प्रस्तुत करने योग्य कोड प्रस्तुत नहीं कर सकता, इसलिए इसके बजाय मैं दृढ़ता से अपने स्वयं के मॉडल के लिए यह परीक्षण करने की सलाह देता हूं।

इन पर अभी तक एक Git मुद्दा नहीं खोला है, लेकिन मैंने मूल पर टिप्पणी की - अभी तक कोई प्रतिक्रिया नहीं हुई। एक बार प्रगति हो जाने के बाद मैं उत्तर (अपडेट) को अपडेट कर दूंगा।


VERDICT : यह नहीं है , यदि आप जानते हैं कि आप क्या कर रहे हैं। लेकिन अगर आप नहीं करते हैं , तो यह आपको बहुत खर्च कर सकता है - औसत पर कुछ जीपीयू अपग्रेड और कई जीपीयू सबसे खराब स्थिति में।


यह उत्तर : इस मुद्दे का उच्च-स्तरीय विवरण और साथ ही आपकी आवश्यकताओं के लिए प्रशिक्षण विन्यास पर निर्णय लेने के लिए दिशानिर्देश प्रदान करना है। एक विस्तृत, निम्न-स्तरीय विवरण के लिए, जिसमें सभी बेंचमार्किंग परिणाम + कोड का उपयोग किया जाता है, मेरा अन्य उत्तर देखें।

यदि मैं किसी भी संदर्भ को बुकमार्क / "स्टार" कर सकता हूं, तो मैं अपने उत्तर (अपडेट) w / अधिक जानकारी को अपडेट करता रहूंगा।


ISSUE SUMMARY : जैसा कि TensorFlow डेवलपर, Q. स्कॉट झू द्वारा पुष्टि की गई है, TF2 ने Eager एक्जीक्यूशन और टाइट इंटीग्रेशन w / Keras पर फोकस किया है, जिसमें TF सोर्स में व्यापक बदलाव शामिल हैं - ग्राफ-स्तर पर। लाभ: प्रसंस्करण, वितरण, डिबग, और परिनियोजन क्षमताओं का बहुत विस्तार किया। हालांकि, इनमें से कुछ की लागत गति है।

हालांकि, मामला काफी जटिल है। यह सिर्फ TF1 बनाम TF2 नहीं है - ट्रेन की गति में महत्वपूर्ण अंतर उत्पन्न करने वाले कारकों में शामिल हैं:

  1. TF2 बनाम TF1
  2. ईगर बनाम ग्राफ मोड
  3. keras बनाम tf.keras
  4. numpyबनाम tf.data.Dataset...
  5. train_on_batch() बनाम fit()
  6. GPU बनाम CPU
  7. model(x)बनाम model.predict(x)...

दुर्भाग्य से, उपरोक्त में से कोई भी दूसरे से स्वतंत्र नहीं है, और प्रत्येक दूसरे के सापेक्ष कम से कम दोहरी निष्पादन समय कर सकता है। सौभाग्य से, आप यह निर्धारित कर सकते हैं कि मैं व्यवस्थित रूप से क्या काम करूंगा, और कुछ शॉर्टकट के साथ - जैसा कि मैं दिखा रहा हूं।


मुझे क्या करना चाहिए? वर्तमान में, एकमात्र तरीका है - आपके विशिष्ट मॉडल, डेटा और हार्डवेयर के लिए प्रयोग। कोई एकल कॉन्फ़िगरेशन हमेशा सबसे अच्छा काम नहीं करेगा - लेकिन वहाँ हैं के करते हैं और नहीं अपनी खोज को आसान बनाने के लिए है कार्य करें:

>> DO:

  • train_on_batch()+ numpy+tf.keras + TF1 + उत्सुक / ग्राफ
  • train_on_batch()+ numpy+tf.keras + TF2 + ग्राफ़
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + ग्राफ़ + बड़े मॉडल और डेटा

>> नहीं:

  • fit()+ numpy+kerasछोटे और मध्यम मॉडल और डेटा के लिए
  • fit()+ numpy+ tf.keras+ TF1 / TF2 + उत्सुक
  • train_on_batch()+ numpy+ keras+ TF1 + उत्सुक

  • [प्रमुख] tf.python.keras ; यह 10-100x धीमी गति से चल सकता है, और w / काफी कीड़े; और जानकारी

    • यह भी शामिल है layers, models, optimizers, और संबंधित "आउट-ऑफ-बॉक्स" के उपयोग के आयात; ऑप्स, यूटिल्स, और संबंधित 'निजी' आयात ठीक हैं - लेकिन यह सुनिश्चित करने के लिए, अलर्ट्स की जांच करें, और क्या वे उपयोग में हैंtf.keras

उदाहरण बेंचमार्किंग सेटअप के लिए मेरे अन्य उत्तर के नीचे कोड का संदर्भ लें। ऊपर दी गई सूची मुख्य रूप से अन्य जवाब में "बेंचमार्क" तालिकाओं पर आधारित है।


उपरोक्त DO & DON'T की सीमाएँ :

  • इस सवाल का शीर्षक "टीएफ 1 की तुलना में टीएफ 2 बहुत धीमा क्यों है?", और जब इसके शरीर को स्पष्ट रूप से प्रशिक्षण की चिंता होती है, तो मामला इसके लिए सीमित नहीं है; आक्रमण , भी, एक ही TF संस्करण, आयात, डेटा प्रारूप, आदि के भीतर भी प्रमुख गति अंतर के अधीन है - देखें इस उत्तर को
  • RNN के डेटा ग्रिड को अन्य उत्तर में उल्लेखनीय रूप से बदलने की संभावना है, क्योंकि वे TF2 में सुधार किए गए हैं
  • मॉडल मुख्य रूप से इस्तेमाल किया Conv1D और Dense- कोई आरएनएन, विरल डेटा / लक्ष्य, 4/5 डी इनपुट, और अन्य कॉन्फ़िगरेशन
  • इनपुट डेटा तक सीमित numpytf.data.Dataset , और , जबकि कई अन्य प्रारूप मौजूद हैं; अन्य उत्तर देखें
  • GPU का उपयोग किया गया था; सीपीयू पर परिणाम अलग-अलग होंगे । वास्तव में, जब मैंने सवाल पूछा, तो मेरा CUDA ठीक से कॉन्फ़िगर नहीं किया गया था, और कुछ परिणाम सीपीयू-आधारित थे।

उत्सुक निष्पादन के लिए TF2 ने सबसे व्यावहारिक गुणवत्ता, गति का त्याग क्यों किया? यह स्पष्ट रूप से नहीं है - ग्राफ अभी भी उपलब्ध है। लेकिन अगर सवाल "आखिर क्यों उत्सुक हो":

  • सुपीरियर डिबगिंग : आप संभवतः "मैं मध्यवर्ती परत आउटपुट कैसे प्राप्त करूं" या "मैं भार का निरीक्षण कैसे करूं" पूछते हुए प्रश्नों के मल्टीट्यूड में आया हूं; उत्सुक के साथ, यह (लगभग) जितना सरल है .__dict__। ग्राफ, इसके विपरीत, विशेष बैकेंड कार्यों के साथ परिचित होने की आवश्यकता है - डिबगिंग और आत्मनिरीक्षण की पूरी प्रक्रिया को बहुत जटिल करना।
  • तेजी से प्रोटोटाइप : ऊपर के समान विचारों के अनुसार; तेजी से समझ = वास्तविक डीएल के लिए अधिक समय बचा है।

कैसे सक्षम / अक्षम करने के लिए?

tf.enable_eager_execution()  # TF1; must be done before any model/tensor creation
tf.compat.v1.disable_eager_execution() # TF2; above holds

अतिरिक्त जानकारी :

  • _on_batch()TF2 में विधियों के साथ सावधान ; टीएफ देव के अनुसार, वे अभी भी धीमी गति से कार्यान्वयन का उपयोग करते हैं, लेकिन जानबूझकर नहीं - यानी यह तय किया जाना है। विवरण के लिए अन्य उत्तर देखें।

दसियों डेविल्स की आवश्यकताएं :

  1. कृपया ठीक करें train_on_batch(), और fit()पुनरावृति को कॉल करने का प्रदर्शन पहलू ; कस्टम ट्रेन लूप कई के लिए महत्वपूर्ण हैं, खासकर मेरे लिए।
  2. उपयोगकर्ताओं के ज्ञान के लिए इन प्रदर्शन अंतरों के प्रलेखन / डॉकस्ट्रिंग का उल्लेख करें।
  3. Pytorch को hopping से peeps रखने के लिए सामान्य निष्पादन की गति में सुधार।

ACKNOWLEDGMENTS : धन्यवाद


अद्यतन :

  • 11/14/19 - एक ऐसा मॉडल (मेरे वास्तविक एप्लिकेशन में) मिला जो सभी * कॉन्फ़िगरेशन w / Numpy इनपुट डेटा के लिए TF2 पर धीमा चलता है । अंतर 17-19% था, औसत 17%। के बीच मतभेद kerasऔर tf.keras:, तथापि, अधिक नाटकीय थीं 18-40% , औसत। 32% (दोनों TF1 और 2)। (* - ईगर को छोड़कर, जिसके लिए TF2 OOM'd)

  • 11/17/19 - on_batch()एक हालिया प्रतिबद्ध में अपडेट की गई विधियों को गति में सुधार करने के लिए कहा गया है - TF 2.1 में जारी किया जाना है, या जैसा कि उपलब्ध है tf-nightly। जैसा कि मैं बाद में चलने में असमर्थ हूं, 2.1 तक बेंचिंग में देरी करेगा।

  • 2/20/20 - भविष्यवाणी का प्रदर्शन भी बैंचिंग के लायक है; TF2 में, उदाहरण के लिए, सीपीयू भविष्यवाणी समय आवधिक स्पाइक शामिल कर सकते हैं

3
किस बारे में fit_generator? ... मैं वास्तव में कभी नहीं चाहता था train_on_batchऔर अपने स्वयं के प्रशिक्षण लूप का प्रबंधन करना बहुत बड़ी कीमत पर भी बचने के लिए एक विशाल, विशाल विरोधी पैटर्न है।
Ely

@ हाल ही में इसका परीक्षण किया जाना बाकी है, जैसा कि मेरे अन्य उत्तर में उल्लेख किया गया है - लेकिन अगर कुछ भी मैं भविष्यवाणी करता हूं कि यह fitडब्ल्यू / छोटे अतिरिक्त डेटा प्रोसेसिंग ओवरहेड होगा। ट्रेन लूप के लिए, मैंने अपना स्वयं का कस्टम लिखा जो अंततः एपीआई के एक प्रकार में बदल गया; fit_generatorआत्मनिरीक्षण, कस्टमिज़ेबिलिटी, और सेव / लोड की कमी है - इसलिए मेरे लिए एक निरपेक्ष झंझट। मैं अपने प्रशिक्षण पाश को अंततः जीथब पर प्रकाशित करूंगा।
ओवरलॉर्डगोल्डड्रैगन

आत्मनिरीक्षण और अनुकूलनशीलता का अभाव मेरे लिए एक विशेषता है, बग नहीं। IDK सेव / लोड कमेंट किसका जिक्र कर रहा है? डेटा जनरेटर द्वारा नियंत्रित नहीं एक लूप के दौरान मध्यवर्ती बचत / लोडिंग? (मैं भी व्यक्तिगत रूप से केवल उस के लिए कॉलबैक पर भरोसा करके खुश हूं, और कोड गंध के रूप में किसी भी आगे के अनुकूलन की आवश्यकता होगी कि मेरे प्रशिक्षण लूप को गलत तरीके से डिज़ाइन किया गया है)।
ely

@ यह सरल नहीं है, लेकिन यह w / जटिल इनपुट डेटा पाइपलाइनों, उद्देश्य कार्यों और गैर-एपीआई मॉडल कॉन्फ़िगरेशन (जैसे ensembles) के प्रशिक्षण के लिए आवश्यक है। आत्मनिरीक्षण कई डिबगिंग और फीचर इंजीनियरिंग उद्देश्यों के लिए आवश्यक है। एक बाहरी बचत / भार को कम करना, और कम्प्यूटेशनल रूप से महंगे मॉडल के लिए लूप पॉज़ेबिलिटी और रेजुमेबिलिटी ट्रेन करना - एक बुरा सपना। भले ही, अंततः आपकी विशिष्ट आवश्यकताओं पर निर्भर हो, और ऑफ-टॉपिक हो; प्रदर्शन w / fit_generatorआप आवेदन के लिए परीक्षण करने के लिए सबसे अच्छा तरीका है , अच्छी तरह से, यह परीक्षण।
OverLordGoldDragon

47

यह उत्तर : TF2 बनाम TF1 ट्रेन लूप, इनपुट डेटा प्रोसेसर, और ईगर बनाम ग्राफ मोड निष्पादन सहित - इस मुद्दे का एक विस्तृत, ग्राफ / हार्डवेयर-स्तरीय विवरण प्रदान करना है। एक समस्या सारांश और संकल्प दिशानिर्देशों के लिए, मेरे अन्य उत्तर को देखें।


प्रदर्शन वर्धमान : कभी-कभी कॉन्फ़िगरेशन के आधार पर एक तेज़, कभी-कभी दूसरा होता है। जहाँ तक TF2 बनाम TF1 चला जाता है, वे औसत पर बराबर के बारे में हैं, लेकिन महत्वपूर्ण कॉन्फ़िगरेशन-आधारित अंतर मौजूद हैं, और TF1 TF2 को अक्सर इसके विपरीत से अधिक ट्रम्प करता है। नीचे "बेंचमार्किंग" देखें।


EAGER वी.एस. GRAPH : कुछ के लिए इस पूरे उत्तर का मांस: TF2 की उत्सुकता मेरे परीक्षण के अनुसार, TF1 की तुलना में धीमी है। विवरण नीचे दिया गया है।

दोनों के बीच मूलभूत अंतर है: ग्राफ एक कम्प्यूटेशनल नेटवर्क को लगातार सेट करता है, और निष्पादित करता है जब 'को बताया' - जबकि एगर निर्माण पर सब कुछ निष्पादित करता है। लेकिन कहानी केवल यहाँ से शुरू होती है:

  • उत्सुक ग्राफ से रहित नहीं है , और वास्तव में ज्यादातर ग्राफ हो सकता है , अपेक्षा के विपरीत। यह काफी हद तक है, ग्राफ़ निष्पादित किया गया है - इसमें मॉडल और ऑप्टिमाइज़र वेट शामिल हैं, जिसमें ग्राफ़ का एक बड़ा हिस्सा शामिल है।

  • एगर निष्पादन में खुद के ग्राफ के हिस्से का पुनर्निर्माण करता है ; ग्राफ़ का प्रत्यक्ष परिणाम पूरी तरह से निर्मित नहीं हो रहा है - प्रोफाइलर परिणाम देखें। यह एक कम्प्यूटेशनल उपरि है।

  • उत्सुक धीमी w / Numpy आदानों है ; इस Git टिप्पणी के अनुसार और कोड, उत्सुक में Numpy आदानों सीपीयू से GPU को tensors को कॉपी करने की अपनी अतिरिक्त लागत शामिल हैं। स्रोत कोड के माध्यम से कदम, डेटा हैंडलिंग अंतर स्पष्ट हैं; ईगर सीधे नेम्पी से गुजरता है, जबकि ग्राफ टेंसर्स से गुजरता है जो फिर नेम्पी का मूल्यांकन करता है; सटीक प्रक्रिया की अनिश्चितता, लेकिन बाद में GPU- स्तर के अनुकूलन शामिल होने चाहिए

  • TF2 Eager, TF1 Eager की तुलना में धीमा है - यह अप्रत्याशित है। नीचे दिए गए बेंचमार्किंग परिणाम देखें। मतभेद नगण्य से महत्वपूर्ण तक फैले हैं, लेकिन सुसंगत हैं। यह सुनिश्चित करें कि यह मामला क्यों है - यदि कोई टीएफ देव स्पष्ट करता है, तो उत्तर को अपडेट करेगा।


TF2 बनाम TF1 : TF देव, Q. स्कॉट झू की प्रतिक्रिया के प्रासंगिक अंशों को उद्धृत करते हुए - w / बिट ऑफ माई जोर एंड रीवॉर्डिंग:

उत्सुकता में, रनटाइम को ऑप्स को निष्पादित करने और अजगर कोड की प्रत्येक पंक्ति के लिए संख्यात्मक मान वापस करने की आवश्यकता होती है। एकल चरण निष्पादन की प्रकृति के कारण यह धीमा हो जाता है

TF2 में, Keras प्रशिक्षण, eval और भविष्यवाणी के लिए अपना ग्राफ बनाने के लिए tf.function का उपयोग करता है। हम उन्हें मॉडल के लिए "निष्पादन फ़ंक्शन" कहते हैं। TF1 में, "निष्पादन फ़ंक्शन" एक फ़ंक्ग्राफ़ था, जिसने कुछ सामान्य घटक को TF फ़ंक्शन के रूप में साझा किया था, लेकिन इसका एक अलग कार्यान्वयन है।

इस प्रक्रिया के दौरान, हमने किसी तरह से train_on_batch (), test_on_batch () और predict_on_batch () के लिए गलत कार्यान्वयन छोड़ दिया । वे अभी भी संख्यात्मक रूप से सही हैं , लेकिन x_on_batch के लिए निष्पादन फ़ंक्शन tf.function लिपटे अजगर फ़ंक्शन के बजाय एक शुद्ध पायथन फ़ंक्शन है। यह करेगा सुस्ती कारण

TF2 में, हम सभी इनपुट डेटा को एक tf.data.Dataset में परिवर्तित करते हैं, जिसके द्वारा हम एकल प्रकार के इनपुट को संभालने के लिए अपने निष्पादन फ़ंक्शन को एकजुट कर सकते हैं। डेटासेट रूपांतरण में कुछ ओवरहेड हो सकता है , और मुझे लगता है कि यह एक बार का ओवरहेड है, बजाय एक प्रति बैच लागत के

ऊपर अंतिम पैराग्राफ के अंतिम वाक्य के साथ, और नीचे पैराग्राफ के अंतिम खंड:

उत्सुक मोड में सुस्ती को दूर करने के लिए, हमारे पास @ tf.function है, जो एक अजगर फ़ंक्शन को एक ग्राफ में बदल देगा। जब एनपी सरणी की तरह संख्यात्मक मूल्य फ़ीड करते हैं, तो tf.function का शरीर स्थिर ग्राफ़ में परिवर्तित हो जाता है, अनुकूलित किया जाता है, और अंतिम मान लौटाता है, जो तेज़ है और TF1 ग्राफ़ मोड के समान प्रदर्शन होना चाहिए।

मैं असहमत हूं - मेरे प्रोफाइलिंग परिणामों के अनुसार, जो एगर के इनपुट डेटा प्रोसेसिंग को ग्राफ के मुकाबले काफी धीमा दिखाते हैं। इसके अलावा, tf.data.Datasetविशेष रूप से अनिश्चित , लेकिन ईगर बार-बार एक ही डेटा रूपांतरण विधियों के कई बार कॉल करता है - प्रोफाइलर देखें।

अंत में, देव की लिंक्ड कमिट: केरस v2 लूप्स का समर्थन करने के लिए परिवर्तनों की महत्वपूर्ण संख्या


ट्रेन लूप : (1) ईगर बनाम ग्राफ पर निर्भर करता है; (2) इनपुट डेटा फॉर्मेट, प्रशिक्षण एक अलग ट्रेन लूप के साथ आगे बढ़ेगा - TF2 _select_training_loop(),, training.py , में से एक:

training_v2.Loop()
training_distributed.DistributionMultiWorkerTrainingLoop(
              training_v2.Loop()) # multi-worker mode
# Case 1: distribution strategy
training_distributed.DistributionMultiWorkerTrainingLoop(
            training_distributed.DistributionSingleWorkerTrainingLoop())
# Case 2: generator-like. Input is Python generator, or Sequence object,
# or a non-distributed Dataset or iterator in eager execution.
training_generator.GeneratorOrSequenceTrainingLoop()
training_generator.EagerDatasetOrIteratorTrainingLoop()
# Case 3: Symbolic tensors or Numpy array-like. This includes Datasets and iterators 
# in graph mode (since they generate symbolic tensors).
training_generator.GeneratorLikeTrainingLoop() # Eager
training_arrays.ArrayLikeTrainingLoop() # Graph

प्रत्येक संसाधन आवंटन को अलग-अलग तरीके से संभालता है, और प्रदर्शन और क्षमता पर परिणाम को सहन करता है।


ट्रेन लूप: fitबनाम train_on_batch, kerasबनामtf.keras : चार में से प्रत्येक अलग रेल लूप का उपयोग करता है, हालांकि हर संभव संयोजन में नहीं। keras' fitउदाहरण के लिए, का एक रूप का उपयोग करता है fit_loop, उदाहरण के लिए training_arrays.fit_loop(), और इसके train_on_batchउपयोग कर सकते हैं K.function()tf.kerasपिछले अनुभाग में भाग में वर्णित एक अधिक परिष्कृत पदानुक्रम है।


ट्रेन लूप्स: प्रलेखन - विभिन्न निष्पादन विधियों में से कुछ पर प्रासंगिक स्रोत :

अन्य TensorFlow संचालन के विपरीत, हम अजगर संख्यात्मक इनपुट को दहाई में नहीं बदलते हैं। इसके अलावा, प्रत्येक अलग अजगर संख्यात्मक मूल्य के लिए एक नया ग्राफ उत्पन्न होता है

function इनपुट आकृतियों और डेटाटिप्स के हर अनूठे सेट के लिए एक अलग ग्राफ को इंस्टेंट करता है

एक एकल tf.function ऑब्जेक्ट को हुड के तहत कई कम्प्यूटेशन ग्राफ़ पर मैप करने की आवश्यकता हो सकती है। इसे केवल प्रदर्शन के रूप में देखा जाना चाहिए (अनुरेखण रेखांकन में एक गैर-कम्प्यूटेशनल और मेमोरी लागत है )


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


मॉडल आकार, डेटा आकार:

  • निर्णायक है; किसी भी एकल कॉन्फ़िगरेशन ने सभी मॉडल और डेटा आकार के साथ ताज पहनाया।
  • मॉडल आकार के सापेक्ष डेटा आकार महत्वपूर्ण है; छोटे डेटा और मॉडल के लिए, डेटा ट्रांसफर (जैसे CPU से GPU) ओवरहेड हावी हो सकता है। इसी तरह, छोटे ओवरहेड प्रोसेसर बड़े डेटा पर प्रति डेटा रूपांतरण समय पर हावी हो सकते हैं (देखें) convert_to_tensor "PROFILER" में )
  • स्पीड प्रति ट्रेन लूप में भिन्न होती है और इनपुट डेटा प्रोसेसर 'संसाधनों से निपटने के साधन अलग होते हैं।

बेंचमार्क : पीस मांस। - शब्द दस्तावेज़ - एक्सेल स्प्रेडशीट


शब्दावली :

  • %-रहित संख्याएँ सभी सेकंड हैं
  • % गणना के रूप में (1 - longer_time / shorter_time)*100; औचित्य: हम इस बात से दिलचस्पी रखते हैं कि कौन सा कारक दूसरे की तुलना में तेज़ है; shorter / longerवास्तव में एक गैर-रैखिक संबंध है, प्रत्यक्ष तुलना के लिए उपयोगी नहीं है
  • % संकेत निर्धारण:
    • TF2 बनाम TF1: + यदि TF2 तेज है
    • जीवीई (ग्राफ बनाम ईगर): +यदि ग्राफ तेज है
  • TF2 = TensorFlow 2.0.0 + केरस 2.3.1; टीएफ 1 = टेन्सरफ्लो 1.14.0 + केरस 2.2.5

PROFILER :


PROFILER - स्पष्टीकरण : स्पाइडर 3.3.6 आईडीई प्रोफाइलर।

  • कुछ कार्यों को दूसरों के घोंसले में दोहराया जाता है; इसलिए, "डेटा प्रोसेसिंग" और "प्रशिक्षण" कार्यों के बीच सटीक पृथक्करण को ट्रैक करना मुश्किल है, इसलिए कुछ ओवरलैप होंगे - जैसा कि बहुत अंतिम परिणाम में स्पष्ट किया गया है।

  • % आंकड़े ने wrt रनटाइम की गणना की माइनस समय का निर्माण करते हैं

  • सभी (अद्वितीय) रनटाइम को जोड़कर समय की गणना करें, जिन्हें 1 या 2 बार कहा गया था
  • ट्रेन के समय को सभी (अद्वितीय) रनटाइम से जोड़कर गणना की जाती है, जिन्हें एक ही समय में # पुनरावृत्तियों के # समान कहा जाता है, और उनके कुछ घोंसलों के रनटाइम
  • फ़ंक्शंस उनके मूल नामों के अनुसार प्रोफाइल किए जाते हैं , दुर्भाग्यवश (यानी _func = funcप्रोफ़ाइल के रूप में func), जो निर्माण समय में मिश्रण करता है - इसलिए इसे बाहर करने की आवश्यकता है

परीक्षण पर्यावरण :

  • नीचे w / न्यूनतम पृष्ठभूमि कार्यों में निष्पादित कोड चल रहा है
  • GPU इस समय में पुनरावृत्तियों से पहले w / कुछ पुनरावृत्तियों को "वार्म अप" कर रहा था, जैसा कि इस पोस्ट में सुझाया गया है
  • CUDA 10.0.130, cuDNN 7.6.0, TensorFlow 1.14.0, और TensorFlow 2.0.0 स्रोत से निर्मित, प्लस एनाकोंडा
  • पायथन 3.7.4, स्पाइडर 3.3.6 आईडीई
  • GTX 1070, विंडोज 10, 24GB DDR4 2.4-MHz RAM, i7-7700HQ 2.8-GHz CPU

विधि :

  • बेंचमार्क 'छोटा', ​​'मध्यम', और 'बड़े' मॉडल और डेटा आकार
  • प्रत्येक मॉडल आकार के लिए मापदंडों के # फिक्स, इनपुट डेटा आकार से स्वतंत्र
  • "बड़े" मॉडल में अधिक पैरामीटर और परतें हैं
  • "बड़े" डेटा का एक लंबा अनुक्रम है, लेकिन वही batch_sizeऔरnum_channels
  • मॉडल केवल उपयोग करते हैं Conv1D,Dense 'learnable' परतों; आरएनएन प्रति टीएफ-संस्करण के प्रतिरूप से बचते हैं। मतभेद
  • मॉडल और ऑप्टिमाइज़र ग्राफ़ बिल्डिंग को छोड़ने के लिए हमेशा बेंचमार्किंग लूप के बाहर एक ट्रेन फिट की गई
  • विरल डेटा (जैसे layers.Embedding()) या विरल लक्ष्य (जैसे) का उपयोग नहीं करनाSparseCategoricalCrossEntropy()

सीमाएं : एक "पूर्ण" उत्तर हर संभव ट्रेन लूप और पुनरावृत्त को समझाएगा, लेकिन यह निश्चित रूप से मेरे समय की क्षमता, कोई नहीं, पेचेक या सामान्य आवश्यकता से परे है। परिणाम केवल पद्धति के रूप में अच्छे हैं - एक खुले दिमाग के साथ व्याख्या।


कोड :

import numpy as np
import tensorflow as tf
import random
from termcolor import cprint
from time import time

from tensorflow.keras.layers import Input, Dense, Conv1D
from tensorflow.keras.layers import Dropout, GlobalAveragePooling1D
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import tensorflow.keras.backend as K
#from keras.layers import Input, Dense, Conv1D
#from keras.layers import Dropout, GlobalAveragePooling1D
#from keras.models import Model 
#from keras.optimizers import Adam
#import keras.backend as K

#tf.compat.v1.disable_eager_execution()
#tf.enable_eager_execution()

def reset_seeds(reset_graph_with_backend=None, verbose=1):
    if reset_graph_with_backend is not None:
        K = reset_graph_with_backend
        K.clear_session()
        tf.compat.v1.reset_default_graph()
        if verbose:
            print("KERAS AND TENSORFLOW GRAPHS RESET")

    np.random.seed(1)
    random.seed(2)
    if tf.__version__[0] == '2':
        tf.random.set_seed(3)
    else:
        tf.set_random_seed(3)
    if verbose:
        print("RANDOM SEEDS RESET")

print("TF version: {}".format(tf.__version__))
reset_seeds()

def timeit(func, iterations, *args, _verbose=0, **kwargs):
    t0 = time()
    for _ in range(iterations):
        func(*args, **kwargs)
        print(end='.'*int(_verbose))
    print("Time/iter: %.4f sec" % ((time() - t0) / iterations))

def make_model_small(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(128, 40, strides=4, padding='same')(ipt)
    x     = GlobalAveragePooling1D()(x)
    x     = Dropout(0.5)(x)
    x     = Dense(64, activation='relu')(x)
    out   = Dense(1,  activation='sigmoid')(x)
    model = Model(ipt, out)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_model_medium(batch_shape):
    ipt = Input(batch_shape=batch_shape)
    x = ipt
    for filters in [64, 128, 256, 256, 128, 64]:
        x  = Conv1D(filters, 20, strides=1, padding='valid')(x)
    x     = GlobalAveragePooling1D()(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)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_model_large(batch_shape):
    ipt   = Input(batch_shape=batch_shape)
    x     = Conv1D(64,  400, strides=4, padding='valid')(ipt)
    x     = Conv1D(128, 200, strides=1, padding='valid')(x)
    for _ in range(40):
        x = Conv1D(256,  12, strides=1, padding='same')(x)
    x     = Conv1D(512,  20, strides=2, padding='valid')(x)
    x     = Conv1D(1028, 10, strides=2, padding='valid')(x)
    x     = Conv1D(256,   1, strides=1, padding='valid')(x)
    x     = GlobalAveragePooling1D()(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)
    model.compile(Adam(lr=1e-4), 'binary_crossentropy')
    return model

def make_data(batch_shape):
    return np.random.randn(*batch_shape), \
           np.random.randint(0, 2, (batch_shape[0], 1))

def make_data_tf(batch_shape, n_batches, iters):
    data = np.random.randn(n_batches, *batch_shape),
    trgt = np.random.randint(0, 2, (n_batches, batch_shape[0], 1))
    return tf.data.Dataset.from_tensor_slices((data, trgt))#.repeat(iters)

batch_shape_small  = (32, 140,   30)
batch_shape_medium = (32, 1400,  30)
batch_shape_large  = (32, 14000, 30)

batch_shapes = batch_shape_small, batch_shape_medium, batch_shape_large
make_model_fns = make_model_small, make_model_medium, make_model_large
iterations = [200, 100, 50]
shape_names = ["Small data",  "Medium data",  "Large data"]
model_names = ["Small model", "Medium model", "Large model"]

def test_all(fit=False, tf_dataset=False):
    for model_fn, model_name, iters in zip(make_model_fns, model_names, iterations):
        for batch_shape, shape_name in zip(batch_shapes, shape_names):
            if (model_fn is make_model_large) and (batch_shape is batch_shape_small):
                continue
            reset_seeds(reset_graph_with_backend=K)
            if tf_dataset:
                data = make_data_tf(batch_shape, iters, iters)
            else:
                data = make_data(batch_shape)
            model = model_fn(batch_shape)

            if fit:
                if tf_dataset:
                    model.train_on_batch(data.take(1))
                    t0 = time()
                    model.fit(data, steps_per_epoch=iters)
                    print("Time/iter: %.4f sec" % ((time() - t0) / iters))
                else:
                    model.train_on_batch(*data)
                    timeit(model.fit, iters, *data, _verbose=1, verbose=0)
            else:
                model.train_on_batch(*data)
                timeit(model.train_on_batch, iters, *data, _verbose=1)
            cprint(">> {}, {} done <<\n".format(model_name, shape_name), 'blue')
            del model

test_all(fit=True, tf_dataset=False)

यदि आपका कोड सही है तो मैं अनिश्चित हूं। मुझे लगता है कि आपके मॉडल हमेशा ग्राफ़ मोड में चलते हैं क्योंकि आप model.compileबिना run_eagerly=Trueतर्क के कॉल करते हैं। यदि उत्सुक मोड में है, तो आप ग्राफ़ मोड का उपयोग करके अपने कोड का हिस्सा चला सकते हैं tf.function। इसलिए मुझे लगता है कि compileप्रदर्शन के कारणों के लिए डिफ़ॉल्ट रूप से क्रियान्वयन कम्प्यूटेशनल ग्राफ बनाना है। यह भी ध्यान दें कि यदि आपका मॉडल कंफर्टेबल है, तो आप ग्राफ मोड में स्पीडअप न देखें क्योंकि अजगर इंटरेक्शन न्यूनतम है। यदि आप कई गणित ऑप्स करते हैं तो इससे बड़ा अंतर (स्मृति उपयोग में भी) हो सकता है।
15:27 बजे user2781994

@OverLordGoldDragon लेकिन TF 2 में, उत्सुक मोड डिफ़ॉल्ट रूप से, लेकिन है model.compileबिना run_eagerly=Trueसुनिश्चित ग्राफ मोड, या नहीं?
user2781994

@OverLordGoldDragon मैं मानता हूं कि सभी आयातित तरीके ग्राफ़ मोड में नहीं चलते हैं, लेकिन मुझे लगता है कि या तो यह सुनिश्चित करना चाहिए कि प्रशिक्षण ग्राफ़ मोड में आंतरिक रूप से चलता है model.compileया नहीं model.fit
user2781994

@OverLordGoldDragon TRUE - "tf.keras.Model.compile में तीन महत्वपूर्ण तर्क दिए गए हैं: ... इसके अलावा, मॉडल ट्रेनों को सुनिश्चित करने और उत्सुकता से मूल्यांकन करने के लिए, आप run_eagerly=Trueकंपाइल करने के लिए एक पैरामीटर के रूप में पास करना सुनिश्चित कर सकते हैं ।" (स्रोत tanorflow.org/guide/keras/overview ) इसलिए यदि आप run_eagerly=Trueमॉडल पास नहीं करते हैं तो आप ग्राफ़ मोड में चला सकते हैं। मैं अनिश्चित हूं कि निर्णय लेने वाला कारक क्या है, लेकिन यदि यह उत्सुकता से अधिक कुशल है तो इसे ग्राफ मोड में क्यों नहीं चलाया जाएगा।
user2781994

क्या आपको और सबूत चाहिए? :) "डिफ़ॉल्ट रूप से, हम सर्वश्रेष्ठ निष्पादन निष्पादन देने के लिए आपके मॉडल को एक स्थिर ग्राफ़ पर संकलित करने का प्रयास करेंगे।" ( github.com/tensorflow/tensorflow/blob/r2.0/tensorflow/python/… )
user2781994
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.