इस पेज का अनुवाद Cloud Translation API से किया गया है.
Switch to English

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

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

अवलोकन

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

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

यह एक संक्षिप्त रूप है; इन अवधारणाओं के पूर्ण परिचय के लिए, tf.function गाइड देखें।

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

पिछले तीन गाइडों में, आपने TensorFlow को उत्सुकता से चलते देखा है। इसका मतलब है कि टेंसोरफ्लो का संचालन पायथन द्वारा किया जाता है, ऑपरेशन द्वारा ऑपरेशन, और परिणाम वापस पायथन में आते हैं। उत्सुक TensorFlow GPUs का लाभ उठाता है, जिससे आप GPU और TPU पर वैरिएबल, टेनसर्स और यहां तक ​​कि संचालन कर सकते हैं। डिबग करना भी आसान है।

कुछ उपयोगकर्ताओं के लिए, आपको पायथन छोड़ने की आवश्यकता नहीं हो सकती है।

हालाँकि, पाइथन में TensorFlow op-by-op चलाने से, अन्यथा उपलब्ध होने वाले गतिरोधों से बचा जा सकता है। यदि आप पायथन से टेनसर कम्प्यूटेशंस निकाल सकते हैं, तो आप उन्हें एक ग्राफ में बना सकते हैं।

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

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

एक दो-परत टेंसोफ़्लो ग्राफ

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

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

रेखांकन भी आसानी से अनुकूलित हो जाते हैं, जिससे कंपाइलर को रूपांतरण करने की अनुमति मिलती है:

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

यह और अन्य स्पीडअप करने के लिए एक संपूर्ण अनुकूलन प्रणाली, ग्रेप्लर है

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

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

अनुरेखण रेखांकन

जिस तरह से आप TensorFlow में एक ग्राफ बनाते हैं, वह tf.function का उपयोग tf.function , या तो सीधे कॉल के रूप में या डेकोरेटर के रूप में।

import tensorflow as tf
import timeit
from datetime import datetime
# Define a Python function
def function_to_get_faster(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Create a `Function` object that contains a graph
a_function_that_uses_a_graph = tf.function(function_to_get_faster)

# Make some tensors
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)

# It just works!
a_function_that_uses_a_graph(x1, y1, b1).numpy()
array([[12.]], dtype=float32)

tf.function -ized फ़ंक्शन Python callables हैं जो उनके Python समकक्षों के समान कार्य करते हैं। उनके पास एक विशेष वर्ग ( python.eager.def_function.Function ) है, लेकिन आप के लिए वे केवल गैर- python.eager.def_function.Function संस्करण के रूप में कार्य करते हैं।

tf.function किसी भी पायथन फ़ंक्शन को पुन: कॉल करता है।

def inner_function(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Use the decorator
@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.Sesssion को परिभाषित करने की आवश्यकता नहीं थी।

प्रवाह नियंत्रण और दुष्प्रभाव

प्रवाह नियंत्रण और लूप डिफ़ॉल्ट रूप से tf.autograph माध्यम से tf.autograph परिवर्तित हो जाते हैं। ऑटोग्राफ विधियों के संयोजन का उपयोग करता है, जिसमें लूप निर्माणों को मानकीकृत करना, अनरोल करना और एएसटी हेरफेर शामिल है।

def my_function(x):
  if tf.reduce_sum(x) <= 1:
    return x * x
  else:
    return x-1

a_function = tf.function(my_function)

print("First branch, with graph:", a_function(tf.constant(1.0)).numpy())
print("Second branch, with graph:", a_function(tf.constant([5.0, 5.0])).numpy())
First branch, with graph: 1.0
Second branch, with graph: [4. 4.]

आप सीधे ऑटोग्राफ रूपांतरण को यह देखने के लिए कॉल कर सकते हैं कि पायथन को टेंसोरफ्लो ऑप में कैसे परिवर्तित किया गया है। यह, ज्यादातर, अपठनीय है, लेकिन आप परिवर्तन देख सकते हैं।

# Don't read the output too carefully.
print(tf.autograph.to_code(my_function))
def tf__my_function(x):
    with ag__.FunctionScope('my_function', '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 do_return, retval_
            (do_return, retval_) = vars_

        def if_body():
            nonlocal do_return, retval_
            try:
                do_return = True
                retval_ = (ag__.ld(x) * ag__.ld(x))
            except:
                do_return = False
                raise

        def else_body():
            nonlocal do_return, retval_
            try:
                do_return = True
                retval_ = (ag__.ld(x) - 1)
            except:
                do_return = False
                raise
        ag__.if_stmt((ag__.converted_call(ag__.ld(tf).reduce_sum, (ag__.ld(x),), None, fscope) <= 1), if_body, else_body, get_state, set_state, ('do_return', 'retval_'), 2)
        return fscope.ret(retval_, do_return)


ऑटोग्राफ स्वचालित रूप से धर्मान्तरित if-then , लूप, break , return , continue , और बहुत कुछ।

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

देखते ही देखते गति बढ़ गई

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

जटिल संगणना के लिए, ग्राफ एक महत्वपूर्ण गति प्रदान कर सकता है। ऐसा इसलिए है क्योंकि ग्राफ़ पायथन-टू-डिवाइस संचार को कम करते हैं और कुछ स्पीडअप करते हैं।

कई छोटी परतों को चलाते समय स्पीडअप सबसे स्पष्ट है, जैसा कि नीचे दिए गए उदाहरण में है:

# Create an oveerride model to classify pictures
class SequentialModel(tf.keras.Model):
  def __init__(self, **kwargs):
    super(SequentialModel, self).__init__(**kwargs)
    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
    # Add a lot of small layers
    num_layers = 100
    self.my_layers = [tf.keras.layers.Dense(64, activation="relu")
                      for n in range(num_layers)]
    self.dropout = tf.keras.layers.Dropout(0.2)
    self.dense_2 = tf.keras.layers.Dense(10)

  def call(self, x):
    x = self.flatten(x)
    for layer in self.my_layers:
      x = layer(x)
    x = self.dropout(x)
    x = self.dense_2(x)
    return x
input_data = tf.random.uniform([20, 28, 28])
eager_model = SequentialModel()

# Don't count the time for the initial build.
eager_model(input_data)
print("Eager time:", timeit.timeit(lambda: eager_model(input_data), number=100))
Eager time: 2.185799148000001

# Wrap the call method in a `tf.function`
graph_model = SequentialModel()
graph_model.call = tf.function(graph_model.call)

# Don't count the time for the initial build and trace.
graph_model(input_data)
print("Graph time:", timeit.timeit(lambda: graph_model(input_data), number=100))
Graph time: 0.30396231500003523

बहुरूपी कार्य

जब आप किसी फ़ंक्शन का पता लगाते हैं, तो आप एक Function ऑब्जेक्ट बनाते हैं जो बहुरूपी है । एक पॉलीमॉर्फिक फ़ंक्शन एक पायथन कॉल योग्य है जो एक एपीआई के पीछे कई ठोस फ़ंक्शन ग्राफ़ को एन्क्रिप्ट करता है।

आप इस Function उपयोग सभी विभिन्न प्रकार के dtypes और आकृतियों पर कर सकते हैं। हर बार जब आप इसे एक नए तर्क हस्ताक्षर से जोड़ते हैं, तो मूल कार्य नए तर्कों के साथ फिर से पता लगाया जाता है। Function तो संग्रहीत करता tf.Graph एक में है कि पता लगाने के लिए इसी concrete_function । यदि फ़ंक्शन पहले से ही इस तरह के तर्क के साथ पता लगाया गया है, तो आपको बस अपना पूर्व-पताित ग्राफ़ मिल जाएगा।

वैचारिक रूप से, तब:

  • एक tf.Graph एक कम्प्यूटेशन का वर्णन करने वाला कच्चा, पोर्टेबल डेटा संरचना है
  • एक Function एक कैशिंग, ट्रेसिंग है, जो कंक्रीटफंक्शंस पर डिस्पैचर है
  • एक ConcreteFunction एक ग्राफ तुम अजगर से ग्राफ पर अमल देता है कि चारों ओर एक उत्सुक संगत आवरण है

बहुरूपी कार्यों का निरीक्षण करना

आप निरीक्षण कर सकते हैं a_function है, जो फोन करने का परिणाम है tf.function अजगर समारोह पर my_function । इस उदाहरण में, तीन प्रकार के तर्कों के साथ a_function को कॉल करने पर तीन अलग-अलग ठोस कार्य होते हैं।

print(a_function)

print("Calling a `Function`:")
print("Int:", a_function(tf.constant(2)))
print("Float:", a_function(tf.constant(2.0)))
print("Rank-1 tensor of floats", a_function(tf.constant([2.0, 2.0, 2.0])))
<tensorflow.python.eager.def_function.Function object at 0x7f90cc28e4a8>
Calling a `Function`:
Int: tf.Tensor(1, shape=(), dtype=int32)
Float: tf.Tensor(1.0, shape=(), dtype=float32)
Rank-1 tensor of floats tf.Tensor([1. 1. 1.], shape=(3,), dtype=float32)

# Get the concrete function that works on floats
print("Inspecting concrete functions")
print("Concrete function for float:")
print(a_function.get_concrete_function(tf.TensorSpec(shape=[], dtype=tf.float32)))
print("Concrete function for tensor of floats:")
print(a_function.get_concrete_function(tf.constant([2.0, 2.0, 2.0])))
Inspecting concrete functions
Concrete function for float:
ConcreteFunction my_function(x)
  Args:
    x: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()
Concrete function for tensor of floats:
ConcreteFunction my_function(x)
  Args:
    x: float32 Tensor, shape=(3,)
  Returns:
    float32 Tensor, shape=(3,)

# Concrete functions are callable
# Note: You won't normally do this, but instead just call the containing `Function`
cf = a_function.get_concrete_function(tf.constant(2))
print("Directly calling a concrete function:", cf(tf.constant(2)))
Directly calling a concrete function: tf.Tensor(1, shape=(), dtype=int32)

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

उत्सुकतापूर्वक निष्पादन के लिए

आप अपने आप को लंबे स्टैक के निशान देख सकते हैं, विशेष रूप से वे जो tf.Graph या with tf.Graph().as_default() देखें with tf.Graph().as_default() । इसका मतलब है कि आप एक ग्राफ संदर्भ में चल रहे हैं। TensorFlow में मुख्य कार्य ग्राफ़ के संदर्भों का उपयोग करते हैं, जैसे कि model.fit() का model.fit()

उत्सुक निष्पादन को डिबग करना अक्सर बहुत आसान होता है। स्टैक के निशान अपेक्षाकृत कम और समझने में आसान होने चाहिए।

उन स्थितियों में जहां ग्राफ डिबगिंग को मुश्किल बनाता है, आप डीबग करने के लिए उत्सुक निष्पादन का उपयोग करने के लिए वापस लौट सकते हैं।

यहां ऐसे तरीके हैं जिनसे आप यह सुनिश्चित कर सकते हैं कि आप उत्सुकता से भाग रहे हैं:

  • कॉल मॉडल और लेयर को सीधे कॉलबेल कहते हैं

  • कायर संकलन / फिट का उपयोग करते समय, संकलन समय पर model.compile(run_eagerly=True)

  • tf.config.run_functions_eagerly(True) माध्यम से वैश्विक निष्पादन मोड सेट करें

run_eagerly=True का उपयोग करना

# Define an identity layer with an eager side effect
class EagerLayer(tf.keras.layers.Layer):
  def __init__(self, **kwargs):
    super(EagerLayer, self).__init__(**kwargs)
    # Do some kind of initialization here

  def call(self, inputs):
    print("\nCurrently running eagerly", str(datetime.now()))
    return inputs
# Create an override model to classify pictures, adding the custom layer
class SequentialModel(tf.keras.Model):
  def __init__(self):
    super(SequentialModel, self).__init__()
    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
    self.dense_1 = tf.keras.layers.Dense(128, activation="relu")
    self.dropout = tf.keras.layers.Dropout(0.2)
    self.dense_2 = tf.keras.layers.Dense(10)
    self.eager = EagerLayer()

  def call(self, x):
    x = self.flatten(x)
    x = self.dense_1(x)
    x = self.dropout(x)
    x = self.dense_2(x)
    return self.eager(x)

# Create an instance of this model
model = SequentialModel()

# Generate some nonsense pictures and labels
input_data = tf.random.uniform([60, 28, 28])
labels = tf.random.uniform([60])

loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

सबसे पहले, बिना उत्सुकता के मॉडल का संकलन करें। ध्यान दें कि मॉडल का पता नहीं लगाया गया है; अपने नाम के बावजूद, compile केवल हानि कार्यों, अनुकूलन और अन्य प्रशिक्षण मापदंडों को निर्धारित करता है।

model.compile(run_eagerly=False, loss=loss_fn)

अब, fit कहते fit और देखते हैं कि फ़ंक्शन का पता लगाया गया है (दो बार) और फिर उत्सुक प्रभाव फिर से नहीं चलता है।

04aa8b380
Epoch 1/3

Currently running eagerly 2021-01-13 02:25:36.809205

Currently running eagerly 2021-01-13 02:25:36.941800
2/2 [==============================] - 0s 3ms/step - loss: 2.0352
Epoch 2/3
2/2 [==============================] - 0s 3ms/step - loss: 0.0045
Epoch 3/3
2/2 [==============================] - 0s 2ms/step - loss: 0.0026

<tensorflow.python.keras.callbacks.History at 0x7f90102f2550>

यदि आप उत्सुकता में एक भी युग चलाते हैं, हालांकि, आप दो बार उत्सुक दुष्प्रभाव देख सकते हैं।

print("Running eagerly")
# When compiling the model, set it to run eagerly
model.compile(run_eagerly=True, loss=loss_fn)

model.fit(input_data, labels, epochs=1)
Running eagerly

Currently running eagerly 2021-01-13 02:25:37.173159
1/2 [==============>...............] - ETA: 0s - loss: 0.0023
Currently running eagerly 2021-01-13 02:25:37.195392
2/2 [==============================] - 0s 13ms/step - loss: 0.0016

<tensorflow.python.keras.callbacks.History at 0x7f90101981d0>

run_functions_eagerly का उपयोग करना

आप विश्व स्तर पर भी उत्सुकता से चलाने के लिए सब कुछ निर्धारित कर सकते हैं। यह एक स्विच है जो पॉलीमॉर्फिक फ़ंक्शन के ट्रेस किए गए फ़ंक्शन को बायपास करता है और सीधे मूल फ़ंक्शन को कॉल करता है। आप डीबगिंग के लिए इसका उपयोग कर सकते हैं।

# Now, globally set everything to run eagerly
tf.config.run_functions_eagerly(True)
print("Run all functions eagerly.")

# Create a polymorphic function
polymorphic_function = tf.function(model)

print("Tracing")
# This does, in fact, trace the function
print(polymorphic_function.get_concrete_function(input_data))

print("\nCalling twice eagerly")
# When you run the function again, you will see the side effect
# twice, as the function is running eagerly.
result = polymorphic_function(input_data)
result = polymorphic_function(input_data)
Run all functions eagerly.
Tracing

Currently running eagerly 2021-01-13 02:25:37.594444
ConcreteFunction function(self)
  Args:
    self: float32 Tensor, shape=(60, 28, 28)
  Returns:
    float32 Tensor, shape=(60, 10)

Calling twice eagerly

Currently running eagerly 2021-01-13 02:25:37.600183

Currently running eagerly 2021-01-13 02:25:37.602196

# Don't forget to set it back when you are done
tf.config.experimental_run_functions_eagerly(False)
WARNING:tensorflow:From <ipython-input-1-782fe9ce7b18>:2: experimental_run_functions_eagerly (from tensorflow.python.eager.def_function) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.run_functions_eagerly` instead of the experimental version.

अनुरेखण और प्रदर्शन

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

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

आप एक उत्सुक-केवल साइड इफेक्ट जोड़ सकते हैं (जैसे कि पायथन तर्क को प्रिंट करना) ताकि आप देख सकें कि फ़ंक्शन कब पता लगाया जा रहा है। यहाँ, आप अतिरिक्त पुनर्प्राप्ति को देखते हैं क्योंकि नए पायथन तर्क हमेशा प्रतिगमन को ट्रिगर करते हैं।

# Use @tf.function decorator
@tf.function
def a_function_with_python_side_effect(x):
  print("Tracing!")  # This eager
  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)))

# 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)
tf.Tensor(11, shape=(), dtype=int32)
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
Tracing!
tf.Tensor(11, shape=(), dtype=int32)

अगला कदम

आप दोनों tf.function एपीआई संदर्भ पृष्ठ पर और गाइड पर अधिक गहन चर्चा पढ़ सकते हैं।