उत्सुक निष्पादन

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

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

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

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

उत्सुक निष्पादन अधिकांश TensorFlow संचालन और GPU त्वरण का समर्थन करता है।

सेटअप और बुनियादी उपयोग

import os

import tensorflow as tf

import cProfile

Tensorflow 2.0 में, उत्सुक निष्पादन डिफ़ॉल्ट रूप से सक्षम होता है।

tf.executing_eagerly()
True

अब आप TensorFlow संचालन चला सकते हैं और परिणाम तुरंत वापस आ जाएंगे:

x = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))
hello, [[4.]]

उत्सुक निष्पादन को सक्षम करने से TensorFlow संचालन कैसे व्यवहार करता है-अब वे तुरंत मूल्यांकन करते हैं और अपने मूल्यों को पायथन में वापस कर देते हैं। tf.Tensor एक कम्प्यूटेशनल ग्राफ में नोड्स के लिए प्रतीकात्मक हैंडल के बजाय संदर्भ ठोस मूल्यों वस्तुओं। के बाद से वहाँ का निर्माण करने के लिए एक कम्प्यूटेशनल ग्राफ और बाद में एक सत्र में नहीं चला है, यह आसान का उपयोग कर परिणाम का निरीक्षण करने के लिए print() या एक डिबगर। टेंसर मानों का मूल्यांकन, मुद्रण और जाँच करना ग्रेडिएंट की गणना के लिए प्रवाह को नहीं तोड़ता है।

उत्सुक निष्पादन के साथ अच्छी तरह से काम करता है NumPy । NumPy संचालन स्वीकार tf.Tensor तर्क। TensorFlow tf.math के संचालन पायथन वस्तुओं और NumPy सरणी परिवर्तित tf.Tensor वस्तुओं। tf.Tensor.numpy विधि एक NumPy के रूप में वस्तु की मान देता है ndarray

a = tf.constant([[1, 2],
                 [3, 4]])
print(a)
tf.Tensor(
[[1 2]
 [3 4]], shape=(2, 2), dtype=int32)
# Broadcasting support
b = tf.add(a, 1)
print(b)
tf.Tensor(
[[2 3]
 [4 5]], shape=(2, 2), dtype=int32)
# Operator overloading is supported
print(a * b)
tf.Tensor(
[[ 2  6]
 [12 20]], shape=(2, 2), dtype=int32)
# Use NumPy values
import numpy as np

c = np.multiply(a, b)
print(c)
[[ 2  6]
 [12 20]]
# Obtain numpy value from a tensor:
print(a.numpy())
# => [[1 2]
#     [3 4]]
[[1 2]
 [3 4]]

गतिशील नियंत्रण प्रवाह

उत्सुक निष्पादन का एक प्रमुख लाभ यह है कि आपका मॉडल निष्पादित होने के दौरान होस्ट भाषा की सभी कार्यक्षमता उपलब्ध है। तो, उदाहरण के लिए, यह लिखने के लिए आसान है fizzbuzz :

def fizzbuzz(max_num):
  counter = tf.constant(0)
  max_num = tf.convert_to_tensor(max_num)
  for num in range(1, max_num.numpy()+1):
    num = tf.constant(num)
    if int(num % 3) == 0 and int(num % 5) == 0:
      print('FizzBuzz')
    elif int(num % 3) == 0:
      print('Fizz')
    elif int(num % 5) == 0:
      print('Buzz')
    else:
      print(num.numpy())
    counter += 1
fizzbuzz(15)
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

इसमें सशर्त हैं जो टेंसर मानों पर निर्भर करते हैं और यह इन मानों को रनटाइम पर प्रिंट करता है।

उत्सुक प्रशिक्षण

कंप्यूटिंग ग्रेडियेंट

स्वचालित भेदभाव जैसे मशीन सीखने एल्गोरिदम को लागू करने के लिए उपयोगी है backpropagation तंत्रिका नेटवर्क को प्रशिक्षित करने के लिए। उत्सुक निष्पादन के दौरान, का उपयोग tf.GradientTape कंप्यूटिंग ढ़ाल बाद के लिए संचालन का पता लगाने के।

आप उपयोग कर सकते हैं tf.GradientTape उत्सुक में और / या गणना ढ़ाल प्रशिक्षित करने के लिए। यह जटिल प्रशिक्षण छोरों के लिए विशेष रूप से उपयोगी है।

चूंकि प्रत्येक कॉल के दौरान अलग-अलग ऑपरेशन हो सकते हैं, सभी फॉरवर्ड-पास ऑपरेशन "टेप" में रिकॉर्ड हो जाते हैं। ग्रेडिएंट की गणना करने के लिए, टेप को पीछे की ओर चलाएं और फिर त्यागें। एक विशेष tf.GradientTape केवल एक ढाल की गणना कर सकते हैं; बाद की कॉल एक रनटाइम त्रुटि फेंक देते हैं।

w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
  loss = w * w

grad = tape.gradient(loss, w)
print(grad)  # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
tf.Tensor([[2.]], shape=(1, 1), dtype=float32)

एक मॉडल को प्रशिक्षित करें

निम्न उदाहरण एक बहु-परत मॉडल बनाता है जो मानक MNIST हस्तलिखित अंकों को वर्गीकृत करता है। यह एक उत्सुक निष्पादन वातावरण में प्रशिक्षित ग्राफ बनाने के लिए अनुकूलक और परत एपीआई प्रदर्शित करता है।

# Fetch and format the mnist data
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()

dataset = tf.data.Dataset.from_tensor_slices(
  (tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
   tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
# Build the model
mnist_model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu',
                         input_shape=(None, None, 1)),
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])

प्रशिक्षण के बिना भी, मॉडल को कॉल करें और उत्सुक निष्पादन में आउटपुट का निरीक्षण करें:

for images,labels in dataset.take(1):
  print("Logits: ", mnist_model(images[0:1]).numpy())
Logits:  [[-0.01775933 -0.01194787 -0.08372174 -0.06535977  0.00338565 -0.01974326
  -0.04763228  0.00904049 -0.00144051 -0.01944664]]

जबकि keras मॉडल अंतर्निहित प्रशिक्षण लूप (का उपयोग कर fit विधि), कभी कभी आप अधिक अनुकूलन की जरूरत है। यहाँ एक उदाहरण है, उत्सुकता के साथ लागू किए गए प्रशिक्षण लूप का:

optimizer = tf.keras.optimizers.Adam()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

loss_history = []
def train_step(images, labels):
  with tf.GradientTape() as tape:
    logits = mnist_model(images, training=True)

    # Add asserts to check the shape of the output.
    tf.debugging.assert_equal(logits.shape, (32, 10))

    loss_value = loss_object(labels, logits)

  loss_history.append(loss_value.numpy().mean())
  grads = tape.gradient(loss_value, mnist_model.trainable_variables)
  optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))
def train(epochs):
  for epoch in range(epochs):
    for (batch, (images, labels)) in enumerate(dataset):
      train_step(images, labels)
    print ('Epoch {} finished'.format(epoch))
train(epochs = 3)
Epoch 0 finished
Epoch 1 finished
Epoch 2 finished
import matplotlib.pyplot as plt

plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')
Text(0, 0.5, 'Loss [entropy]')

पीएनजी

चर और अनुकूलक

tf.Variable वस्तुओं परिवर्तनशील स्टोर tf.Tensor स्वचालित भेदभाव आसान बनाने के लिए प्रशिक्षण के दौरान पहुँचा मूल्यों की तरह।

चरों के संग्रह को परतों या मॉडलों में इनकैप्सुलेट किया जा सकता है, साथ ही उन पर काम करने वाले तरीकों के साथ। देखें कस्टम Keras परतों और मॉडल जानकारी के लिए। परतों और मॉडलों के बीच मुख्य अंतर यह है कि मॉडल की तरह विधियों को जोड़ने है Model.fit , Model.evaluate , और Model.save

उदाहरण के लिए, ऊपर दिए गए स्वचालित विभेदन उदाहरण को फिर से लिखा जा सकता है:

class Linear(tf.keras.Model):
  def __init__(self):
    super(Linear, self).__init__()
    self.W = tf.Variable(5., name='weight')
    self.B = tf.Variable(10., name='bias')
  def call(self, inputs):
    return inputs * self.W + self.B
# A toy dataset of points around 3 * x + 2
NUM_EXAMPLES = 2000
training_inputs = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise

# The loss function to be optimized
def loss(model, inputs, targets):
  error = model(inputs) - targets
  return tf.reduce_mean(tf.square(error))

def grad(model, inputs, targets):
  with tf.GradientTape() as tape:
    loss_value = loss(model, inputs, targets)
  return tape.gradient(loss_value, [model.W, model.B])

अगला:

  1. मॉडल बनाएं।
  2. मॉडल पैरामीटर के संबंध में हानि फ़ंक्शन के डेरिवेटिव।
  3. डेरिवेटिव के आधार पर वेरिएबल को अपडेट करने की रणनीति।
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))

steps = 300
for i in range(steps):
  grads = grad(model, training_inputs, training_outputs)
  optimizer.apply_gradients(zip(grads, [model.W, model.B]))
  if i % 20 == 0:
    print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))
Initial loss: 69.909
Loss at step 000: 67.145
Loss at step 020: 30.170
Loss at step 040: 13.859
Loss at step 060: 6.659
Loss at step 080: 3.479
Loss at step 100: 2.074
Loss at step 120: 1.453
Loss at step 140: 1.178
Loss at step 160: 1.056
Loss at step 180: 1.003
Loss at step 200: 0.979
Loss at step 220: 0.968
Loss at step 240: 0.963
Loss at step 260: 0.961
Loss at step 280: 0.960
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
Final loss: 0.960
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
W = 2.9515867233276367, B = 2.0210201740264893

वस्तु आधारित बचत

एक tf.keras.Model एक सुविधाजनक शामिल save_weights विधि आप आसानी से एक चौकी बनाने के लिए अनुमति देता है:

model.save_weights('weights')
status = model.load_weights('weights')

का उपयोग करते हुए tf.train.Checkpoint आप इस प्रक्रिया पर पूरा नियंत्रण ले जा सकते हैं।

इस अनुभाग का एक संक्षिप्त संस्करण है प्रशिक्षण चौकियों के लिए गाइड

x = tf.Variable(10.)
checkpoint = tf.train.Checkpoint(x=x)
x.assign(2.)   # Assign a new value to the variables and save.
checkpoint_path = './ckpt/'
checkpoint.save(checkpoint_path)
'./ckpt/-1'
x.assign(11.)  # Change the variable after saving.

# Restore values from the checkpoint
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))

print(x)  # => 2.0
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=2.0>

बचाने के लिए और लोड मॉडल, करने के लिए tf.train.Checkpoint , वस्तुओं की आंतरिक स्थिति को संग्रहीत करता है छिपा चर की आवश्यकता के बिना। एक की स्थिति को रिकॉर्ड करने के लिए model , एक optimizer , और एक वैश्विक कदम है, उन्हें एक के पास tf.train.Checkpoint :

model = tf.keras.Sequential([
  tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
  tf.keras.layers.GlobalAveragePooling2D(),
  tf.keras.layers.Dense(10)
])
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint_dir = 'path/to/model_dir'
if not os.path.exists(checkpoint_dir):
  os.makedirs(checkpoint_dir)
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
                           model=model)

root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f4ba0648310>

ऑब्जेक्ट-ओरिएंटेड मेट्रिक्स

tf.keras.metrics वस्तुओं के रूप में जमा हो जाती है। प्रतिदेय के लिए नए डेटा पास करके एक मीट्रिक अद्यतन, और का उपयोग कर परिणाम पुनः प्राप्त tf.keras.metrics.result विधि, उदाहरण के लिए:

m = tf.keras.metrics.Mean("loss")
m(0)
m(5)
m.result()  # => 2.5
m([8, 9])
m.result()  # => 5.5
<tf.Tensor: shape=(), dtype=float32, numpy=5.5>

सारांश और टेंसरबोर्ड

TensorBoard , समझने डिबगिंग और मॉडल प्रशिक्षण प्रक्रिया के अनुकूलन के लिए एक दृश्य उपकरण है। यह सारांश घटनाओं का उपयोग करता है जो प्रोग्राम को निष्पादित करते समय लिखे जाते हैं।

आप उपयोग कर सकते हैं tf.summary उत्सुक निष्पादन में चर के रिकॉर्ड के सारांश के लिए। उदाहरण के लिए, का सारांश रिकॉर्ड करने के लिए loss हर 100 प्रशिक्षण चरणों एक बार:

logdir = "./tb/"
writer = tf.summary.create_file_writer(logdir)

steps = 1000
with writer.as_default():  # or call writer.set_as_default() before the loop.
  for i in range(steps):
    step = i + 1
    # Calculate loss with your real train function.
    loss = 1 - 0.001 * step
    if step % 100 == 0:
      tf.summary.scalar('loss', loss, step=step)
ls tb/
events.out.tfevents.1632342765.kokoro-gcp-ubuntu-prod-230753280.22287.0.v2

उन्नत स्वचालित विभेदीकरण विषय

गतिशील मॉडल

tf.GradientTape भी गतिशील मॉडल में इस्तेमाल किया जा सकता है। एक के लिए यह उदाहरण बैक ट्रैकिंग लाइन खोज सामान्य NumPy कोड की तरह एल्गोरिथ्म दिखता है, सिवाय इसके कि वहाँ ढ़ाल कर रहे हैं और जो विभेदक है, जटिल नियंत्रण प्रवाह के बावजूद:

def line_search_step(fn, init_x, rate=1.0):
  with tf.GradientTape() as tape:
    # Variables are automatically tracked.
    # But to calculate a gradient from a tensor, you must `watch` it.
    tape.watch(init_x)
    value = fn(init_x)
  grad = tape.gradient(value, init_x)
  grad_norm = tf.reduce_sum(grad * grad)
  init_value = value
  while value > init_value - rate * grad_norm:
    x = init_x - rate * grad
    value = fn(x)
    rate /= 2.0
  return x, value

कस्टम ग्रेडिएंट

कस्टम ग्रेडिएंट ग्रेडिएंट को ओवरराइड करने का एक आसान तरीका है। फॉरवर्ड फ़ंक्शन के भीतर, इनपुट, आउटपुट या मध्यवर्ती परिणामों के संबंध में ग्रेडिएंट को परिभाषित करें। उदाहरण के लिए, बैकवर्ड पास में ग्रेडिएंट के मानदंड को क्लिप करने का एक आसान तरीका यहां दिया गया है:

@tf.custom_gradient
def clip_gradient_by_norm(x, norm):
  y = tf.identity(x)
  def grad_fn(dresult):
    return [tf.clip_by_norm(dresult, norm), None]
  return y, grad_fn

कस्टम ग्रेडिएंट आमतौर पर संचालन के अनुक्रम के लिए संख्यात्मक रूप से स्थिर ग्रेडिएंट प्रदान करने के लिए उपयोग किया जाता है:

def log1pexp(x):
  return tf.math.log(1 + tf.exp(x))

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# The gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# However, x = 100 fails because of numerical instability.
grad_log1pexp(tf.constant(100.)).numpy()
nan

इधर, log1pexp समारोह विश्लेषणात्मक एक कस्टम ढाल के साथ सरल किया जा सकता। Reuses नीचे कार्यान्वयन के लिए मूल्य tf.exp(x) है कि आगे के दौरान की जाती है यह और अधिक कुशल पास लेने की अनावश्यक गणना को नष्ट करने से:

@tf.custom_gradient
def log1pexp(x):
  e = tf.exp(x)
  def grad(dy):
    return dy * (1 - 1 / (1 + e))
  return tf.math.log(1 + e), grad

def grad_log1pexp(x):
  with tf.GradientTape() as tape:
    tape.watch(x)
    value = log1pexp(x)
  return tape.gradient(value, x)
# As before, the gradient computation works fine at x = 0.
grad_log1pexp(tf.constant(0.)).numpy()
0.5
# And the gradient computation also works at x = 100.
grad_log1pexp(tf.constant(100.)).numpy()
1.0

प्रदर्शन

उत्सुक निष्पादन के दौरान संगणना स्वचालित रूप से GPU पर लोड हो जाती है। आपको इस पर नियंत्रण है, जहां एक गणना चलाता है आप एक में यह संलग्न कर सकते हैं tf.device('/gpu:0') ब्लॉक (या CPU समकक्ष):

import time

def measure(x, steps):
  # TensorFlow initializes a GPU the first time it's used, exclude from timing.
  tf.matmul(x, x)
  start = time.time()
  for i in range(steps):
    x = tf.matmul(x, x)
  # tf.matmul can return before completing the matrix multiplication
  # (e.g., can return after enqueing the operation on a CUDA stream).
  # The x.numpy() call below will ensure that all enqueued operations
  # have completed (and will also copy the result to host memory,
  # so we're including a little more than just the matmul operation
  # time).
  _ = x.numpy()
  end = time.time()
  return end - start

shape = (1000, 1000)
steps = 200
print("Time to multiply a {} matrix by itself {} times:".format(shape, steps))

# Run on CPU:
with tf.device("/cpu:0"):
  print("CPU: {} secs".format(measure(tf.random.normal(shape), steps)))

# Run on GPU, if available:
if tf.config.list_physical_devices("GPU"):
  with tf.device("/gpu:0"):
    print("GPU: {} secs".format(measure(tf.random.normal(shape), steps)))
else:
  print("GPU: not found")
Time to multiply a (1000, 1000) matrix by itself 200 times:
CPU: 1.007401466369629 secs
GPU: 0.04124784469604492 secs

एक tf.Tensor वस्तु अपने परिचालन निष्पादित करने के लिए किसी दूसरे डिवाइस पर कॉपी किया जा सकता:

if tf.config.list_physical_devices("GPU"):
  x = tf.random.normal([10, 10])

  x_gpu0 = x.gpu()
  x_cpu = x.cpu()

  _ = tf.matmul(x_cpu, x_cpu)    # Runs on CPU
  _ = tf.matmul(x_gpu0, x_gpu0)  # Runs on GPU:0
WARNING:tensorflow:From /tmp/ipykernel_22287/406964202.py:4: _EagerTensorBase.gpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.
WARNING:tensorflow:From /tmp/ipykernel_22287/406964202.py:5: _EagerTensorBase.cpu (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.identity instead.

मानक

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

कार्यों के साथ काम करें

जबकि उत्सुक निष्पादन विकास और डिबगिंग को अधिक इंटरैक्टिव बनाता है, TensorFlow 1.x शैली ग्राफ़ निष्पादन में वितरित प्रशिक्षण, प्रदर्शन अनुकूलन और उत्पादन परिनियोजन के फायदे हैं। इस खाई को पाटने के लिए, TensorFlow 2.0 प्रस्तुत किया जाने function के माध्यम से रों tf.function एपीआई। अधिक जानकारी के लिए, tf.function गाइड।