TensorFlow.org पर देखें | Google Colab में चलाएं | GitHub पर स्रोत देखें | नोटबुक डाउनलोड करें |
अवलोकन
यह मार्गदर्शिका TensorFlow और Keras की सतह के नीचे जाकर प्रदर्शित करती है कि TensorFlow कैसे काम करता है। यदि आप इसके बजाय तुरंत केरस के साथ शुरुआत करना चाहते हैं, तो केरस गाइड का संग्रह देखें।
इस गाइड में, आप सीखेंगे कि कैसे TensorFlow आपको ग्राफ़ प्राप्त करने के लिए अपने कोड में सरल परिवर्तन करने की अनुमति देता है, ग्राफ़ को कैसे संग्रहीत और प्रदर्शित किया जाता है, और आप अपने मॉडल को गति देने के लिए उनका उपयोग कैसे कर सकते हैं।
यह एक बड़े चित्र का अवलोकन है जो कवर करता है कि कैसे tf.function
आपको उत्सुक निष्पादन से ग्राफ़ निष्पादन पर स्विच करने की अनुमति देता है। tf.function
के अधिक पूर्ण विवरण के लिए, tf.function
गाइड पर जाएं।
रेखांकन क्या हैं?
पिछली तीन गाइडों में, आपने TensorFlow को उत्सुकता से चलाया। इसका मतलब है कि TensorFlow संचालन पायथन द्वारा निष्पादित किया जाता है, संचालन द्वारा संचालन, और परिणाम वापस पायथन में लौटाता है।
जबकि उत्सुक निष्पादन के कई अनूठे फायदे हैं, ग्राफ निष्पादन पायथन के बाहर पोर्टेबिलिटी को सक्षम बनाता है और बेहतर प्रदर्शन की पेशकश करता है। ग्राफ़ निष्पादन का अर्थ है कि टेंसर कंप्यूटेशंस को TensorFlow ग्राफ़ के रूप में निष्पादित किया जाता है, जिसे कभी-कभी tf.Graph
या केवल "ग्राफ़" के रूप में संदर्भित किया जाता है।
ग्राफ़ डेटा संरचनाएं हैं जिनमें tf.Operation
ऑब्जेक्ट्स का एक सेट होता है, जो गणना की इकाइयों का प्रतिनिधित्व करता है; और tf.Tensor
ऑब्जेक्ट, जो डेटा की इकाइयों का प्रतिनिधित्व करते हैं जो संचालन के बीच प्रवाहित होते हैं। उन्हें एक tf.Graph
संदर्भ में परिभाषित किया गया है। चूंकि ये ग्राफ़ डेटा संरचनाएं हैं, इसलिए इन्हें मूल पायथन कोड के बिना सहेजा जा सकता है, चलाया जा सकता है और सभी को पुनर्स्थापित किया जा सकता है।
यह एक दो-परत तंत्रिका नेटवर्क का प्रतिनिधित्व करने वाला एक TensorFlow ग्राफ जैसा दिखता है जब TensorBoard में देखा जाता है।
रेखांकन के लाभ
ग्राफ़ के साथ, आपके पास बहुत अधिक लचीलापन है। आप अपने TensorFlow ग्राफ़ का उपयोग ऐसे परिवेशों में कर सकते हैं जिनमें Python दुभाषिया नहीं है, जैसे मोबाइल एप्लिकेशन, एम्बेडेड डिवाइस और बैकएंड सर्वर। TensorFlow ग्राफ़ को सहेजे गए मॉडल के प्रारूप के रूप में उपयोग करता है जब यह उन्हें पायथन से निर्यात करता है।
ग्राफ़ को भी आसानी से अनुकूलित किया जाता है, जिससे कंपाइलर को ट्रांसफ़ॉर्मेशन करने की अनुमति मिलती है जैसे:
- अपनी गणना ("लगातार फोल्डिंग") में स्थिर नोड्स को फोल्ड करके टेनर्स के मान को स्थिर रूप से अनुमानित करें।
- एक गणना के अलग-अलग उप-भाग जो स्वतंत्र हैं और उन्हें थ्रेड्स या उपकरणों के बीच विभाजित करते हैं।
- सामान्य उप-अभिव्यक्तियों को हटाकर अंकगणितीय संक्रियाओं को सरल बनाएं।
इसे और अन्य स्पीडअप करने के लिए एक संपूर्ण अनुकूलन प्रणाली, ग्रेप्लर है।
संक्षेप में, ग्राफ़ अत्यंत उपयोगी हैं और आपके TensorFlow को तेजी से चलने देते हैं, समानांतर में चलते हैं, और कई उपकरणों पर कुशलता से चलते हैं।
हालाँकि, आप अभी भी सुविधा के लिए अपने मशीन लर्निंग मॉडल (या अन्य संगणना) को पायथन में परिभाषित करना चाहते हैं, और फिर जरूरत पड़ने पर स्वचालित रूप से ग्राफ़ का निर्माण करते हैं।
सेट अप
import tensorflow as tf
import timeit
from datetime import datetime
रेखांकन का लाभ उठाते हुए
आप सीधे कॉल या डेकोरेटर के रूप में tf.function का उपयोग करके tf.function
में एक ग्राफ बनाते और चलाते हैं। tf.function
इनपुट के रूप में एक नियमित फ़ंक्शन लेता है और एक Function
देता है। एक Function
एक पायथन कॉल करने योग्य है जो पायथन फ़ंक्शन से TensorFlow ग्राफ़ बनाता है। आप एक Function
का उसी तरह उपयोग करते हैं जैसे उसके पायथन समकक्ष।
# Define a Python function.
def a_regular_function(x, y, b):
x = tf.matmul(x, y)
x = x + b
return x
# `a_function_that_uses_a_graph` is a TensorFlow `Function`.
a_function_that_uses_a_graph = tf.function(a_regular_function)
# Make some tensors.
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)
orig_value = a_regular_function(x1, y1, b1).numpy()
# Call a `Function` like a Python function.
tf_function_value = a_function_that_uses_a_graph(x1, y1, b1).numpy()
assert(orig_value == tf_function_value)
बाहरी रूप से, Function
एक नियमित फ़ंक्शन की तरह दिखता है जिसे आप TensorFlow संचालन का उपयोग करके लिखते हैं। नीचे , हालांकि, यह बहुत अलग है। एक Function
एक API के पीछे कई tf.Graph
s को इनकैप्सुलेट करता है। इस प्रकार Function
आपको गति और परिनियोजन जैसे ग्राफ़ निष्पादन के लाभ देने में सक्षम है।
tf.function
एक फ़ंक्शन और अन्य सभी फ़ंक्शन पर लागू होता है जिसे वह कॉल करता है :
def inner_function(x, y, b):
x = tf.matmul(x, y)
x = x + b
return x
# Use the decorator to make `outer_function` a `Function`.
@tf.function
def outer_function(x):
y = tf.constant([[2.0], [3.0]])
b = tf.constant(4.0)
return inner_function(x, y, b)
# Note that the callable will create a graph that
# includes `inner_function` as well as `outer_function`.
outer_function(tf.constant([[1.0, 2.0]])).numpy()
array([[12.]], dtype=float32)
यदि आपने TensorFlow 1.x का उपयोग किया है, तो आप देखेंगे कि आपको कभी भी Placeholder
या tf.Session
को परिभाषित करने की आवश्यकता नहीं पड़ी।
पायथन कार्यों को ग्राफ़ में परिवर्तित करना
TensorFlow के साथ आप जो भी फंक्शन लिखते हैं, उसमें बिल्ट-इन TF ऑपरेशंस और Python लॉजिक का मिश्रण होगा, जैसे कि if-then
क्लॉज, लूप्स, break
, return
, continue
, और बहुत कुछ। जबकि TensorFlow संचालन आसानी से एक tf.Graph
द्वारा कब्जा कर लिया जाता है, ग्राफ़ का हिस्सा बनने के लिए पायथन-विशिष्ट तर्क को एक अतिरिक्त कदम से गुजरना पड़ता है। tf.function
Python कोड को ग्राफ-जनरेटिंग कोड में बदलने के लिए AutoGraph ( tf.autograph
) नामक लाइब्रेरी का उपयोग करता है।
def simple_relu(x):
if tf.greater(x, 0):
return x
else:
return 0
# `tf_simple_relu` is a TensorFlow `Function` that wraps `simple_relu`.
tf_simple_relu = tf.function(simple_relu)
print("First branch, with graph:", tf_simple_relu(tf.constant(1)).numpy())
print("Second branch, with graph:", tf_simple_relu(tf.constant(-1)).numpy())
First branch, with graph: 1 Second branch, with graph: 0
हालांकि यह संभावना नहीं है कि आपको सीधे ग्राफ़ देखने की आवश्यकता होगी, आप सटीक परिणामों की जांच के लिए आउटपुट का निरीक्षण कर सकते हैं। ये पढ़ने में आसान नहीं हैं, इसलिए ज्यादा ध्यान से देखने की जरूरत नहीं है!
# This is the graph-generating output of AutoGraph.
print(tf.autograph.to_code(simple_relu))
def tf__simple_relu(x): with ag__.FunctionScope('simple_relu', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope: do_return = False retval_ = ag__.UndefinedReturnValue() def get_state(): return (do_return, retval_) def set_state(vars_): nonlocal retval_, do_return (do_return, retval_) = vars_ def if_body(): nonlocal retval_, do_return try: do_return = True retval_ = ag__.ld(x) except: do_return = False raise def else_body(): nonlocal retval_, do_return try: do_return = True retval_ = 0 except: do_return = False raise ag__.if_stmt(ag__.converted_call(ag__.ld(tf).greater, (ag__.ld(x), 0), None, fscope), if_body, else_body, get_state, set_state, ('do_return', 'retval_'), 2) return fscope.ret(retval_, do_return)
# This is the graph itself.
print(tf_simple_relu.get_concrete_function(tf.constant(1)).graph.as_graph_def())
node { name: "x" op: "Placeholder" attr { key: "_user_specified_name" value { s: "x" } } attr { key: "dtype" value { type: DT_INT32 } } attr { key: "shape" value { shape { } } } } node { name: "Greater/y" op: "Const" attr { key: "dtype" value { type: DT_INT32 } } attr { key: "value" value { tensor { dtype: DT_INT32 tensor_shape { } int_val: 0 } } } } node { name: "Greater" op: "Greater" input: "x" input: "Greater/y" attr { key: "T" value { type: DT_INT32 } } } node { name: "cond" op: "StatelessIf" input: "Greater" input: "x" attr { key: "Tcond" value { type: DT_BOOL } } attr { key: "Tin" value { list { type: DT_INT32 } } } attr { key: "Tout" value { list { type: DT_BOOL type: DT_INT32 } } } attr { key: "_lower_using_switch_merge" value { b: true } } attr { key: "_read_only_resource_inputs" value { list { } } } attr { key: "else_branch" value { func { name: "cond_false_34" } } } attr { key: "output_shapes" value { list { shape { } shape { } } } } attr { key: "then_branch" value { func { name: "cond_true_33" } } } } node { name: "cond/Identity" op: "Identity" input: "cond" attr { key: "T" value { type: DT_BOOL } } } node { name: "cond/Identity_1" op: "Identity" input: "cond:1" attr { key: "T" value { type: DT_INT32 } } } node { name: "Identity" op: "Identity" input: "cond/Identity_1" attr { key: "T" value { type: DT_INT32 } } } library { function { signature { name: "cond_false_34" input_arg { name: "cond_placeholder" type: DT_INT32 } output_arg { name: "cond_identity" type: DT_BOOL } output_arg { name: "cond_identity_1" type: DT_INT32 } } node_def { name: "cond/Const" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Const_1" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Const_2" op: "Const" attr { key: "dtype" value { type: DT_INT32 } } attr { key: "value" value { tensor { dtype: DT_INT32 tensor_shape { } int_val: 0 } } } } node_def { name: "cond/Const_3" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Identity" op: "Identity" input: "cond/Const_3:output:0" attr { key: "T" value { type: DT_BOOL } } } node_def { name: "cond/Const_4" op: "Const" attr { key: "dtype" value { type: DT_INT32 } } attr { key: "value" value { tensor { dtype: DT_INT32 tensor_shape { } int_val: 0 } } } } node_def { name: "cond/Identity_1" op: "Identity" input: "cond/Const_4:output:0" attr { key: "T" value { type: DT_INT32 } } } ret { key: "cond_identity" value: "cond/Identity:output:0" } ret { key: "cond_identity_1" value: "cond/Identity_1:output:0" } attr { key: "_construction_context" value { s: "kEagerRuntime" } } arg_attr { key: 0 value { attr { key: "_output_shapes" value { list { shape { } } } } } } } function { signature { name: "cond_true_33" input_arg { name: "cond_identity_1_x" type: DT_INT32 } output_arg { name: "cond_identity" type: DT_BOOL } output_arg { name: "cond_identity_1" type: DT_INT32 } } node_def { name: "cond/Const" op: "Const" attr { key: "dtype" value { type: DT_BOOL } } attr { key: "value" value { tensor { dtype: DT_BOOL tensor_shape { } bool_val: true } } } } node_def { name: "cond/Identity" op: "Identity" input: "cond/Const:output:0" attr { key: "T" value { type: DT_BOOL } } } node_def { name: "cond/Identity_1" op: "Identity" input: "cond_identity_1_x" attr { key: "T" value { type: DT_INT32 } } } ret { key: "cond_identity" value: "cond/Identity:output:0" } ret { key: "cond_identity_1" value: "cond/Identity_1:output:0" } attr { key: "_construction_context" value { s: "kEagerRuntime" } } arg_attr { key: 0 value { attr { key: "_output_shapes" value { list { shape { } } } } } } } } versions { producer: 898 min_consumer: 12 }
अधिकांश समय, tf.function
बिना किसी विशेष विचार के काम करेगा। हालांकि, कुछ चेतावनी हैं, और tf.function गाइड यहां मदद कर सकता है, साथ ही संपूर्ण ऑटोग्राफ संदर्भ भी।
बहुरूपता: एक Function
, कई रेखांकन
एक tf.Graph
एक विशिष्ट प्रकार के इनपुट के लिए विशिष्ट है (उदाहरण के लिए, एक विशिष्ट dtype
वाले टेंसर या समान id()
वाले ऑब्जेक्ट)।
हर बार जब आप किसी Function
को उसके तर्कों में नए प्रकार और आकृतियों के साथ आमंत्रित करते हैं, तो Function
नए tf.Graph
dtypes
है। dtypes
के इनपुट के tf.Graph
और आकार को इनपुट सिग्नेचर या सिर्फ सिग्नेचर के रूप में जाना जाता है।
Function
उस हस्ताक्षर के अनुरूप tf.Graph
को ConcreteFunction
में संग्रहीत करता है। एक ConcreteFunction
एक tf.Graph
के चारों ओर एक आवरण है।
@tf.function
def my_relu(x):
return tf.maximum(0., x)
# `my_relu` creates new graphs as it observes more signatures.
print(my_relu(tf.constant(5.5)))
print(my_relu([1, -1]))
print(my_relu(tf.constant([3., -3.])))
tf.Tensor(5.5, shape=(), dtype=float32) tf.Tensor([1. 0.], shape=(2,), dtype=float32) tf.Tensor([3. 0.], shape=(2,), dtype=float32)
यदि Function
को उस हस्ताक्षर के साथ पहले ही बुलाया जा चुका है, तो Function
एक नया tf.Graph
नहीं बनाता है।
# These two calls do *not* create new graphs.
print(my_relu(tf.constant(-2.5))) # Signature matches `tf.constant(5.5)`.
print(my_relu(tf.constant([-1., 1.]))) # Signature matches `tf.constant([3., -3.])`.
tf.Tensor(0.0, shape=(), dtype=float32) tf.Tensor([0. 1.], shape=(2,), dtype=float32)
क्योंकि यह कई ग्राफ़ द्वारा समर्थित है, एक Function
बहुरूपी है। यह इसे एकल tf.Graph
की तुलना में अधिक इनपुट प्रकारों का समर्थन करने में सक्षम बनाता है, साथ ही बेहतर प्रदर्शन के लिए प्रत्येक tf.Graph
को अनुकूलित करने में सक्षम बनाता है।
# There are three `ConcreteFunction`s (one for each graph) in `my_relu`.
# The `ConcreteFunction` also knows the return type and shape!
print(my_relu.pretty_printed_concrete_signatures())
my_relu(x) Args: x: float32 Tensor, shape=() Returns: float32 Tensor, shape=() my_relu(x=[1, -1]) Returns: float32 Tensor, shape=(2,) my_relu(x) Args: x: float32 Tensor, shape=(2,) Returns: float32 Tensor, shape=(2,)
tf.function
का उपयोग करना
अब तक, आपने सीखा है कि कैसे एक डेकोरेटर या रैपर के रूप में tf.function
का उपयोग करके एक पायथन फ़ंक्शन को ग्राफ़ में परिवर्तित किया जाए। लेकिन व्यवहार में, tf.function
को सही ढंग से काम करना मुश्किल हो सकता है! निम्नलिखित अनुभागों में, आप सीखेंगे कि आप अपने कोड को tf.function
के साथ अपेक्षा के अनुरूप कैसे काम कर सकते हैं।
ग्राफ़ निष्पादन बनाम उत्सुक निष्पादन
Function
में कोड को उत्सुकता से और ग्राफ़ के रूप में निष्पादित किया जा सकता है। डिफ़ॉल्ट रूप से, Function
अपने कोड को ग्राफ़ के रूप में निष्पादित करता है:
@tf.function
def get_MSE(y_true, y_pred):
sq_diff = tf.pow(y_true - y_pred, 2)
return tf.reduce_mean(sq_diff)
y_true = tf.random.uniform([5], maxval=10, dtype=tf.int32)
y_pred = tf.random.uniform([5], maxval=10, dtype=tf.int32)
print(y_true)
print(y_pred)
tf.Tensor([1 0 4 4 7], shape=(5,), dtype=int32) tf.Tensor([3 6 3 0 6], shape=(5,), dtype=int32)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=11>
यह सत्यापित करने के लिए कि आपके Function
का ग्राफ इसके समकक्ष पायथन फ़ंक्शन के समान ही गणना कर रहा है, आप इसे tf.config.run_functions_eagerly(True)
के साथ उत्सुकता से निष्पादित कर सकते हैं। यह एक स्विच है जो सामान्य रूप से कोड निष्पादित करने के बजाय, ग्राफ़ बनाने और चलाने की Function
की क्षमता को बंद कर देता है ।
tf.config.run_functions_eagerly(True)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=11>
# Don't forget to set it back when you are done.
tf.config.run_functions_eagerly(False)
हालांकि, Function
ग्राफ और उत्सुक निष्पादन के तहत अलग तरह से व्यवहार कर सकता है। पायथन print
फ़ंक्शन एक उदाहरण है कि ये दो मोड कैसे भिन्न होते हैं। आइए देखें कि क्या होता है जब आप अपने फ़ंक्शन में एक print
स्टेटमेंट डालते हैं और इसे बार-बार कॉल करते हैं।
@tf.function
def get_MSE(y_true, y_pred):
print("Calculating MSE!")
sq_diff = tf.pow(y_true - y_pred, 2)
return tf.reduce_mean(sq_diff)
देखें कि क्या छपा है:
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
Calculating MSE!
क्या आउटपुट आश्चर्यजनक है? get_MSE
केवल एक बार मुद्रित किया गया था, भले ही इसे तीन बार बुलाया गया हो।
व्याख्या करने के लिए, print
स्टेटमेंट निष्पादित किया जाता है जब Function
"ट्रेसिंग" नामक प्रक्रिया में ग्राफ़ बनाने के लिए मूल कोड चलाता है। ट्रेसिंग TensorFlow संचालन को एक ग्राफ़ में कैप्चर करता है, और print
को ग्राफ़ में कैप्चर नहीं किया जाता है। उस ग्राफ को फिर कभी भी पायथन कोड को चलाए बिना तीनों कॉलों के लिए निष्पादित किया जाता है।
एक विवेकपूर्ण जाँच के रूप में, आइए तुलना करने के लिए ग्राफ़ निष्पादन को बंद करें:
# Now, globally set everything to run eagerly to force eager execution.
tf.config.run_functions_eagerly(True)
# Observe what is printed below.
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
error = get_MSE(y_true, y_pred)
Calculating MSE! Calculating MSE! Calculating MSE!
tf.config.run_functions_eagerly(False)
print
एक पायथन साइड इफेक्ट है , और ऐसे अन्य अंतर हैं जिनके बारे में आपको किसी Function
को फ़ंक्शन में कनवर्ट करते समय अवगत होना चाहिए। tf.function गाइड के साथ बेहतर प्रदर्शन के सीमा अनुभाग में और जानें।
गैर-सख्त निष्पादन
ग्राफ़ निष्पादन केवल अवलोकन योग्य प्रभाव उत्पन्न करने के लिए आवश्यक संचालन निष्पादित करता है, जिसमें निम्न शामिल हैं:
- फ़ंक्शन का रिटर्न मान
- प्रलेखित प्रसिद्ध दुष्प्रभाव जैसे:
- इनपुट/आउटपुट संचालन, जैसे
tf.print
- डिबगिंग ऑपरेशन, जैसे कि
tf.debugging
में मुखर कार्य -
tf.Variable
. के उत्परिवर्तन
- इनपुट/आउटपुट संचालन, जैसे
इस व्यवहार को आमतौर पर "गैर-सख्त निष्पादन" के रूप में जाना जाता है, और उत्सुक निष्पादन से अलग होता है, जो सभी प्रोग्राम संचालन के माध्यम से कदम उठाता है, आवश्यक है या नहीं।
विशेष रूप से, रनटाइम त्रुटि जाँच को एक अवलोकनीय प्रभाव के रूप में नहीं गिना जाता है। यदि कोई ऑपरेशन छोड़ दिया जाता है क्योंकि यह अनावश्यक है, तो यह किसी भी रनटाइम त्रुटियों को नहीं बढ़ा सकता है।
निम्नलिखित उदाहरण में, "अनावश्यक" ऑपरेशन tf.gather
को ग्राफ़ निष्पादन के दौरान छोड़ दिया जाता है, इसलिए रनटाइम त्रुटि InvalidArgumentError
को नहीं उठाया जाता है क्योंकि यह उत्सुक निष्पादन में होगा। ग्राफ़ निष्पादित करते समय उठाई जा रही त्रुटि पर भरोसा न करें।
def unused_return_eager(x):
# Get index 1 will fail when `len(x) == 1`
tf.gather(x, [1]) # unused
return x
try:
print(unused_return_eager(tf.constant([0.0])))
except tf.errors.InvalidArgumentError as e:
# All operations are run during eager execution so an error is raised.
print(f'{type(e).__name__}: {e}')
tf.Tensor([0.], shape=(1,), dtype=float32)
@tf.function
def unused_return_graph(x):
tf.gather(x, [1]) # unused
return x
# Only needed operations are run during graph exection. The error is not raised.
print(unused_return_graph(tf.constant([0.0])))
tf.Tensor([0.], shape=(1,), dtype=float32)
tf.function
सर्वोत्तम अभ्यास
Function
के व्यवहार के अभ्यस्त होने में कुछ समय लग सकता है। जल्दी से शुरू करने के लिए, पहली बार उपयोगकर्ताओं को ग्राफ़ निष्पादन के लिए उत्सुकता से अनुभव प्राप्त करने के लिए @tf.function
के साथ सजावटी खिलौनों के कार्यों के साथ खेलना चाहिए।
ग्राफ़-संगत TensorFlow प्रोग्राम लिखने के लिए tf.function
के लिए डिज़ाइन करना आपकी सबसे अच्छी शर्त हो सकती है। यहाँ कुछ युक्तियाँ हैं:
- उत्सुक और ग्राफ़ निष्पादन के बीच जल्दी और अक्सर
tf.config.run_functions_eagerly
के साथ टॉगल करें ताकि यह पता लगाया जा सके कि क्या/जब दो मोड अलग हो जाते हैं। - पायथन फ़ंक्शन के बाहर
tf.Variable
बनाएं और उन्हें अंदर से संशोधित करें। वही वस्तुओं के लिए जाता है जोtf.Variable
का उपयोग करते हैं, जैसेkeras.layers
,keras.Model
s औरtf.optimizers
। -
tf.Variable
s और Keras ऑब्जेक्ट्स को छोड़कर, बाहरी पायथन चर पर निर्भर कार्यों को लिखने से बचें। - ऐसे फ़ंक्शन लिखना पसंद करते हैं जो इनपुट के रूप में टेंसर और अन्य TensorFlow प्रकार लेते हैं। आप अन्य ऑब्जेक्ट प्रकारों में पास कर सकते हैं लेकिन सावधान रहें !
- प्रदर्शन लाभ को अधिकतम करने के लिए
tf.function
के तहत जितना संभव हो उतना संगणना शामिल करें। उदाहरण के लिए, एक संपूर्ण प्रशिक्षण चरण या संपूर्ण प्रशिक्षण लूप को सजाएं।
गति को देखते हुए
tf.function
आमतौर पर आपके कोड के प्रदर्शन में सुधार करता है, लेकिन गति-अप की मात्रा आपके द्वारा चलाए जा रहे गणना के प्रकार पर निर्भर करती है। ग्राफ़ को कॉल करने के ऊपरी हिस्से में छोटी गणनाओं का प्रभुत्व हो सकता है। आप प्रदर्शन में अंतर को इस प्रकार माप सकते हैं:
x = tf.random.uniform(shape=[10, 10], minval=-1, maxval=2, dtype=tf.dtypes.int32)
def power(x, y):
result = tf.eye(10, dtype=tf.dtypes.int32)
for _ in range(y):
result = tf.matmul(x, result)
return result
print("Eager execution:", timeit.timeit(lambda: power(x, 100), number=1000))
Eager execution: 2.5637862179974036
power_as_graph = tf.function(power)
print("Graph execution:", timeit.timeit(lambda: power_as_graph(x, 100), number=1000))
Graph execution: 0.6832536700021592
tf.function
का उपयोग आमतौर पर प्रशिक्षण लूप को गति देने के लिए किया जाता है, और आप इसके बारे में केरस के साथ स्क्रैच से एक प्रशिक्षण लूप लिखना सीख सकते हैं।
प्रदर्शन और ट्रेड-ऑफ
ग्राफ़ आपके कोड को तेज़ कर सकते हैं, लेकिन उन्हें बनाने की प्रक्रिया में कुछ ओवरहेड है। कुछ कार्यों के लिए, ग्राफ़ के निर्माण में ग्राफ़ के निष्पादन से अधिक समय लगता है। यह निवेश आमतौर पर बाद के निष्पादन के प्रदर्शन को बढ़ावा देने के साथ जल्दी से वापस भुगतान किया जाता है, लेकिन यह जानना महत्वपूर्ण है कि ट्रेसिंग के कारण किसी भी बड़े मॉडल प्रशिक्षण के पहले कुछ चरण धीमे हो सकते हैं।
आपका मॉडल कितना भी बड़ा क्यों न हो, आप बार-बार ट्रेसिंग से बचना चाहते हैं। tf.function
गाइड चर्चा करती है कि कैसे इनपुट विनिर्देशों को सेट किया जाए और रिट्रेसिंग से बचने के लिए टेंसर तर्कों का उपयोग किया जाए। यदि आप पाते हैं कि आपको असामान्य रूप से खराब प्रदर्शन मिल रहा है, तो यह जांचना एक अच्छा विचार है कि क्या आप गलती से पुन: ट्रेस कर रहे हैं।
Function
ट्रेसिंग कब होती है?
यह पता लगाने के लिए कि आपका Function
कब ट्रेस कर रहा है, इसके कोड में एक print
स्टेटमेंट जोड़ें। अंगूठे के एक नियम के रूप में, Function
हर बार ट्रेस होने पर print
स्टेटमेंट को निष्पादित करेगा।
@tf.function
def a_function_with_python_side_effect(x):
print("Tracing!") # An eager-only side effect.
return x * x + tf.constant(2)
# This is traced the first time.
print(a_function_with_python_side_effect(tf.constant(2)))
# The second time through, you won't see the side effect.
print(a_function_with_python_side_effect(tf.constant(3)))
Tracing! tf.Tensor(6, shape=(), dtype=int32) tf.Tensor(11, shape=(), dtype=int32)
# This retraces each time the Python argument changes,
# as a Python argument could be an epoch count or other
# hyperparameter.
print(a_function_with_python_side_effect(2))
print(a_function_with_python_side_effect(3))
Tracing! tf.Tensor(6, shape=(), dtype=int32) Tracing! tf.Tensor(11, shape=(), dtype=int32)
नए पायथन तर्क हमेशा एक नए ग्राफ के निर्माण को ट्रिगर करते हैं, इसलिए अतिरिक्त अनुरेखण।
अगले कदम
आप एपीआई संदर्भ पृष्ठ पर tf.function
के बारे में अधिक जान सकते हैं और tf.function
गाइड के साथ बेहतर प्रदर्शन का पालन कर सकते हैं।