सहायता Kaggle पर TensorFlow साथ ग्रेट बैरियर रीफ की रक्षा चैलेंज में शामिल हों

रेखांकन और tf.function का परिचय

TensorFlow.org पर देखें GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

अवलोकन

यह मार्गदर्शिका TensorFlow और Keras की सतह के नीचे जाकर प्रदर्शित करती है कि TensorFlow कैसे काम करता है। आप के बजाय तुरंत Keras साथ आरंभ करने के लिए चाहते हैं, बाहर की जाँच Keras गाइड का संग्रह

इस गाइड में, आप सीखेंगे कि कैसे TensorFlow आपको ग्राफ़ प्राप्त करने के लिए अपने कोड में सरल परिवर्तन करने की अनुमति देता है, ग्राफ़ को कैसे संग्रहीत और प्रदर्शित किया जाता है, और आप अपने मॉडल को गति देने के लिए उनका उपयोग कैसे कर सकते हैं।

यह एक बड़ा चित्र सिंहावलोकन कि कवर कैसे है tf.function आप ग्राफ निष्पादन करने के लिए उत्सुक निष्पादन से स्विच करने की अनुमति देता है। को अधिक अच्छी तरह विवरण के लिए tf.function , करने के लिए जाना tf.function गाइड

रेखांकन क्या हैं?

पिछले तीन गाइड में, आप TensorFlow बेसब्री से भाग गया। इसका मतलब है कि TensorFlow संचालन पायथन द्वारा निष्पादित किया जाता है, संचालन द्वारा संचालन, और परिणाम वापस पायथन में लौटाता है।

जबकि उत्सुक निष्पादन के कई अनूठे फायदे हैं, ग्राफ निष्पादन पायथन के बाहर पोर्टेबिलिटी को सक्षम बनाता है और बेहतर प्रदर्शन की पेशकश करता है। ग्राफ़ निष्पादन का मतलब है कि टेन्सर संगणना एक TensorFlow ग्राफ, कभी कभी एक के रूप में भेजा के रूप में क्रियान्वित कर रहे हैं tf.Graph या बस एक "ग्राफ।"

रेखांकन डेटा संरचनाओं का एक सेट शामिल हैं tf.Operation वस्तुओं, जो गणना की इकाइयों प्रतिनिधित्व करते हैं, और tf.Tensor वस्तुओं, जो डेटा की इकाइयों कि आपरेशन के बीच प्रवाह प्रतिनिधित्व करते हैं। वे एक में परिभाषित कर रहे हैं tf.Graph संदर्भ। चूंकि ये ग्राफ़ डेटा संरचनाएं हैं, इसलिए इन्हें मूल पायथन कोड के बिना सहेजा, चलाया और पुनर्स्थापित किया जा सकता है।

यह एक दो-परत तंत्रिका नेटवर्क का प्रतिनिधित्व करने वाला एक TensorFlow ग्राफ जैसा दिखता है जब TensorBoard में देखा जाता है।

एक साधारण TensorFlow ग्राफ

रेखांकन के लाभ

ग्राफ़ के साथ, आपके पास बहुत अधिक लचीलापन है। आप अपने TensorFlow ग्राफ़ का उपयोग उन वातावरणों में कर सकते हैं जिनमें Python दुभाषिया नहीं है, जैसे मोबाइल एप्लिकेशन, एम्बेडेड डिवाइस और बैकएंड सर्वर। TensorFlow के लिए प्रारूप के रूप में रेखांकन का उपयोग करता बचाया मॉडल जब यह उनके अजगर से निर्यात करता है।

ग्राफ़ को भी आसानी से अनुकूलित किया जाता है, जिससे कंपाइलर को ट्रांसफ़ॉर्मेशन करने की अनुमति मिलती है जैसे:

  • स्थिर अपने गणना में लगातार नोड्स तह ( "निरंतर तह") द्वारा tensors के मूल्य का अनुमान लगा।
  • एक गणना के अलग-अलग उप-भाग जो स्वतंत्र हैं और उन्हें थ्रेड्स या उपकरणों के बीच विभाजित करते हैं।
  • सामान्य उप-अभिव्यक्तियों को हटाकर अंकगणितीय संक्रियाओं को सरल बनाएं।

वहाँ एक पूरी अनुकूलन प्रणाली है, Grappler , इस और अन्य speedups प्रदर्शन करने के लिए।

संक्षेप में, रेखांकन अत्यंत उपयोगी हैं और अपने TensorFlow तेजी से चलाने के लिए, समानांतर में चलाने, और कई उपकरणों पर कुशलता से चलाते हैं।

हालाँकि, आप अभी भी सुविधा के लिए अपने मशीन लर्निंग मॉडल (या अन्य संगणना) को पायथन में परिभाषित करना चाहते हैं, और फिर जरूरत पड़ने पर स्वचालित रूप से ग्राफ़ का निर्माण करते हैं।

सेट अप

import tensorflow as tf
import timeit
from datetime import datetime

रेखांकन का लाभ उठाना

आप बना सकते हैं और का उपयोग करके TensorFlow में एक ग्राफ चलाने 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 समाहित कई tf.Graph एक एपीआई के पीछे रों यही कारण है कि कैसे है Function आप देने में सक्षम है ग्राफ निष्पादन के लाभ , गति और deployability की तरह।

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 संचालन और अजगर तर्क, if-then खंड, छोरों, break , return , continue और भी बहुत कुछ। TensorFlow संचालन आसानी से एक द्वारा कब्जा कर लिया जाता है, जबकि tf.Graph आदेश ग्राफ का हिस्सा बनने के लिए एक अतिरिक्त कदम से गुजरना, अजगर विशेष तर्क की जरूरत है। tf.function एक पुस्तकालय हस्ताक्षर (बुलाया का उपयोग करता 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
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const"
      }
    }
    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
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_1"
      }
    }
    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
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_2"
      }
    }
    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
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_3"
      }
    }
    node_def {
      name: "cond/Identity"
      op: "Identity"
      input: "cond/Const_3:output:0"
      attr {
        key: "T"
        value {
          type: DT_BOOL
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity"
      }
    }
    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
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const_4"
      }
    }
    node_def {
      name: "cond/Identity_1"
      op: "Identity"
      input: "cond/Const_4:output:0"
      attr {
        key: "T"
        value {
          type: DT_INT32
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity_1"
      }
    }
    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
          }
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Const"
      }
    }
    node_def {
      name: "cond/Identity"
      op: "Identity"
      input: "cond/Const:output:0"
      attr {
        key: "T"
        value {
          type: DT_BOOL
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity"
      }
    }
    node_def {
      name: "cond/Identity_1"
      op: "Identity"
      input: "cond_identity_1_x"
      attr {
        key: "T"
        value {
          type: DT_INT32
        }
      }
      experimental_debug_info {
        original_node_names: "cond/Identity_1"
      }
    }
    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: 808
  min_consumer: 12
}

अधिकांश समय, tf.function विशेष विचार के बिना काम करेंगे। हालांकि, कुछ चेतावनियां हैं, और tf.function गाइड के साथ-साथ यहाँ मदद कर सकते हैं, पूरा हस्ताक्षर संदर्भ

बहुरूपता: एक Function , कई रेखांकन

एक tf.Graph आदानों की एक विशिष्ट प्रकार के लिए विशेष है (उदाहरण के लिए, एक विशिष्ट साथ tensors dtype या एक ही साथ वस्तुओं id() )।

हर बार जब आप एक आह्वान Function नए के साथ dtypes अपने तर्कों में और आकार, Function के लिए एक नया बनाता है tf.Graph नया तर्क के लिए। 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([6 1 7 8 0], shape=(5,), dtype=int32)
tf.Tensor([6 0 1 8 6], shape=(5,), dtype=int32)
get_MSE(y_true, y_pred)
<tf.Tensor: shape=(), dtype=int32, numpy=14>

सत्यापित करने के लिए कि आपके 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=14>
# 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.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 उत्सुक से ग्राफ निष्पादन के लिए जा रहा के साथ अनुभव प्राप्त करने के लिए।

डिजाइनिंग tf.function ग्राफ संगत TensorFlow कार्यक्रमों लिखने के लिए आपका सर्वश्रेष्ठ दांव हो सकता है। यहाँ कुछ युक्तियाँ हैं:

  • उत्सुक और ग्राफ निष्पादन के बीच टॉगल जल्दी और अक्सर साथ tf.config.run_functions_eagerly देने के लिए सटीक यदि / जब दो मोड वितरित हो जाते हैं।
  • बनाएं tf.Variable रों बाहर अजगर समारोह और अंदर से उन्हें संशोधित। एक ही वस्तुओं का उपयोग करने वाले के लिए चला जाता है tf.Variable , जैसे keras.layers , keras.Model और tf.optimizers
  • कार्यों कि लेखन से बचें बाहरी अजगर चर पर निर्भर करते हैं , को छोड़कर tf.Variable और 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.0122516460000384
power_as_graph = tf.function(power)
print("Graph execution:", timeit.timeit(lambda: power_as_graph(x, 100), number=1000))
Graph execution: 0.6084441319999883

tf.function आमतौर पर प्रशिक्षण छोरों तेजी लाने के लिए प्रयोग किया जाता है, और आप इसके बारे में अधिक सीख सकते हैं स्क्रैच से एक प्रशिक्षण पाश लेखन Keras साथ।

प्रदर्शन और ट्रेड-ऑफ

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

आपका मॉडल कितना भी बड़ा क्यों न हो, आप बार-बार ट्रेसिंग से बचना चाहते हैं। tf.function गाइड चर्चा कैसे सेट इनपुट विनिर्देशों और उपयोग टेन्सर तर्कों को retracing से बचने के लिए। यदि आप पाते हैं कि आपको असामान्य रूप से खराब प्रदर्शन मिल रहा है, तो यह जांचना एक अच्छा विचार है कि क्या आप गलती से पुन: ट्रेस कर रहे हैं।

जब एक है 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 API संदर्भ पृष्ठ पर और पालन करते हुए के साथ बेहतर प्रदर्शन tf.function गाइड।