डीबग TF2 माइग्रेट प्रशिक्षण पाइपलाइन

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

यह नोटबुक दर्शाता है कि TF2 में माइग्रेट करते समय प्रशिक्षण पाइपलाइन को कैसे डिबग करना है। इसमें निम्नलिखित घटक होते हैं:

  1. डिबगिंग प्रशिक्षण पाइपलाइन के लिए सुझाए गए चरण और कोड नमूने
  2. डिबगिंग के लिए उपकरण
  3. अन्य संबंधित संसाधन

एक धारणा यह है कि आपके पास तुलना के लिए TF1.x कोड और प्रशिक्षित मॉडल हैं, और आप एक TF2 मॉडल बनाना चाहते हैं जो समान सत्यापन सटीकता प्राप्त करता है।

यह नोटबुक प्रशिक्षण/अनुमान गति या स्मृति उपयोग के लिए डिबगिंग प्रदर्शन समस्याओं को कवर नहीं करता है।

डिबगिंग वर्कफ़्लो

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

  1. संकलन और रनटाइम त्रुटियों को ठीक करें

  2. सिंगल फॉरवर्ड पास सत्यापन (एक अलग गाइड में)

    ए। सिंगल सीपीयू डिवाइस पर

    • सत्यापित करें कि चर केवल एक बार बनाए गए हैं
    • वेरिएबल काउंट, नाम और शेप मैच चेक करें
    • सभी चर रीसेट करें, सभी यादृच्छिकता अक्षम के साथ संख्यात्मक तुल्यता की जांच करें
    • यादृच्छिक संख्या पीढ़ी को संरेखित करें, अनुमान में संख्यात्मक तुल्यता की जांच करें
    • (वैकल्पिक) चेक चौकियों को ठीक से लोड किया जाता है और TF1.x/TF2 मॉडल समान आउटपुट उत्पन्न करते हैं

    बी। सिंगल GPU/TPU डिवाइस पर

    सी। मल्टी-डिवाइस रणनीतियों के साथ

  3. कुछ चरणों के लिए मॉडल प्रशिक्षण संख्यात्मक तुल्यता सत्यापन (नीचे उपलब्ध कोड नमूने)

    ए। सिंगल सीपीयू डिवाइस पर छोटे और निश्चित डेटा का उपयोग करके सिंगल ट्रेनिंग स्टेप वेलिडेशन। विशेष रूप से, निम्नलिखित घटकों के लिए संख्यात्मक तुल्यता की जाँच करें

    • हानियों की गणना
    • मैट्रिक्स
    • सीखने की दर
    • ढाल गणना और अद्यतन

    बी। गति जैसे अनुकूलक व्यवहारों को सत्यापित करने के लिए 3 या अधिक चरणों के प्रशिक्षण के बाद आंकड़ों की जाँच करें, फिर भी एकल CPU डिवाइस पर निश्चित डेटा के साथ

    सी। सिंगल GPU/TPU डिवाइस पर

    डी। मल्टी-डिवाइस रणनीतियों के साथ (नीचे मल्टीप्रोसेसरनर के लिए परिचय देखें)

  4. वास्तविक डेटासेट पर एंड-टू-एंड कवरेज परीक्षण

    ए। TensorBoard के साथ प्रशिक्षण व्यवहार की जाँच करें

    • सरल ऑप्टिमाइज़र का उपयोग करें जैसे SGD और सरल वितरण रणनीतियाँ जैसे tf.distribute.OneDeviceStrategy पहले
    • प्रशिक्षण मेट्रिक्स
    • मूल्यांकन मेट्रिक्स
    • पता लगाएँ कि अंतर्निहित यादृच्छिकता के लिए उचित सहिष्णुता क्या है

    बी। उन्नत अनुकूलक/सीखने की दर अनुसूचक/वितरण रणनीतियों के साथ तुल्यता की जांच करें

    सी। मिश्रित परिशुद्धता का उपयोग करते समय तुल्यता की जाँच करें

  5. अतिरिक्त उत्पाद बेंचमार्क

सेट अप

pip uninstall -y -q tensorflow
# Install tf-nightly as the DeterministicRandomTestTool is only available in
# Tensorflow 2.8
pip install -q tf-nightly

सिंगल फॉरवर्ड पास सत्यापन

चेकपॉइंट लोडिंग सहित सिंगल फॉरवर्ड पास सत्यापन, एक अलग कोलाब में शामिल है।

import sys
import unittest
import numpy as np

import tensorflow as tf
import tensorflow.compat.v1 as v1

कुछ चरणों के लिए मॉडल प्रशिक्षण संख्यात्मक तुल्यता सत्यापन

मॉडल कॉन्फ़िगरेशन सेट करें और नकली डेटासेट तैयार करें।

params = {
    'input_size': 3,
    'num_classes': 3,
    'layer_1_size': 2,
    'layer_2_size': 2,
    'num_train_steps': 100,
    'init_lr': 1e-3,
    'end_lr': 0.0,
    'decay_steps': 1000,
    'lr_power': 1.0,
}

# make a small fixed dataset
fake_x = np.ones((2, params['input_size']), dtype=np.float32)
fake_y = np.zeros((2, params['num_classes']), dtype=np.int32)
fake_y[0][0] = 1
fake_y[1][1] = 1

step_num = 3

TF1.x मॉडल को परिभाषित करें।

# Assume there is an existing TF1.x model using estimator API
# Wrap the model_fn to log necessary tensors for result comparison
class SimpleModelWrapper():
  def __init__(self):
    self.logged_ops = {}
    self.logs = {
        'step': [],
        'lr': [],
        'loss': [],
        'grads_and_vars': [],
        'layer_out': []}

  def model_fn(self, features, labels, mode, params):
      out_1 = tf.compat.v1.layers.dense(features, units=params['layer_1_size'])
      out_2 = tf.compat.v1.layers.dense(out_1, units=params['layer_2_size'])
      logits = tf.compat.v1.layers.dense(out_2, units=params['num_classes'])
      loss = tf.compat.v1.losses.softmax_cross_entropy(labels, logits)

      # skip EstimatorSpec details for prediction and evaluation 
      if mode == tf.estimator.ModeKeys.PREDICT:
          pass
      if mode == tf.estimator.ModeKeys.EVAL:
          pass
      assert mode == tf.estimator.ModeKeys.TRAIN

      global_step = tf.compat.v1.train.get_or_create_global_step()
      lr = tf.compat.v1.train.polynomial_decay(
        learning_rate=params['init_lr'],
        global_step=global_step,
        decay_steps=params['decay_steps'],
        end_learning_rate=params['end_lr'],
        power=params['lr_power'])

      optmizer = tf.compat.v1.train.GradientDescentOptimizer(lr)
      grads_and_vars = optmizer.compute_gradients(
          loss=loss,
          var_list=graph.get_collection(
              tf.compat.v1.GraphKeys.TRAINABLE_VARIABLES))
      train_op = optmizer.apply_gradients(
          grads_and_vars,
          global_step=global_step)

      # log tensors
      self.logged_ops['step'] = global_step
      self.logged_ops['lr'] = lr
      self.logged_ops['loss'] = loss
      self.logged_ops['grads_and_vars'] = grads_and_vars
      self.logged_ops['layer_out'] = {
          'layer_1': out_1,
          'layer_2': out_2,
          'logits': logits}

      return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

  def update_logs(self, logs):
    for key in logs.keys():
      model_tf1.logs[key].append(logs[key])

निम्नलिखित v1.keras.utils.DeterministicRandomTestTool वर्ग एक संदर्भ प्रबंधक scope() प्रदान करता है जो स्टेटफुल रैंडम ऑपरेशंस को TF1 ग्राफ़ / सत्र और उत्सुक निष्पादन दोनों में एक ही बीज का उपयोग कर सकता है,

उपकरण दो परीक्षण मोड प्रदान करता है:

  1. constant जो हर एक ऑपरेशन के लिए एक ही बीज का उपयोग करता है, चाहे उसे कितनी भी बार कहा गया हो और,
  2. num_random_ops जो ऑपरेशन बीज के रूप में पहले देखे गए स्टेटफुल रैंडम ऑपरेशंस की संख्या का उपयोग करता है।

यह वैरिएबल बनाने और आरंभ करने के लिए उपयोग किए जाने वाले स्टेटफुल रैंडम ऑपरेशंस और गणना में उपयोग किए जाने वाले स्टेटफुल रैंडम ऑपरेशंस (जैसे ड्रॉपआउट लेयर्स के लिए) दोनों पर लागू होता है।

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
WARNING:tensorflow:From /tmp/ipykernel_26769/2689227634.py:1: The name tf.keras.utils.DeterministicRandomTestTool is deprecated. Please use tf.compat.v1.keras.utils.DeterministicRandomTestTool instead.

TF1.x मॉडल को ग्राफ़ मोड में चलाएँ। संख्यात्मक तुल्यता तुलना के लिए पहले 3 प्रशिक्षण चरणों के लिए आंकड़े एकत्र करें।

with random_tool.scope():
  graph = tf.Graph()
  with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
    model_tf1 = SimpleModelWrapper()
    # build the model
    inputs = tf.compat.v1.placeholder(tf.float32, shape=(None, params['input_size']))
    labels = tf.compat.v1.placeholder(tf.float32, shape=(None, params['num_classes']))
    spec = model_tf1.model_fn(inputs, labels, tf.estimator.ModeKeys.TRAIN, params)
    train_op = spec.train_op

    sess.run(tf.compat.v1.global_variables_initializer())
    for step in range(step_num):
      # log everything and update the model for one step
      logs, _ = sess.run(
          [model_tf1.logged_ops, train_op],
          feed_dict={inputs: fake_x, labels: fake_y})
      model_tf1.update_logs(logs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:14: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/legacy_tf_layers/core.py:261: UserWarning: `layer.apply` is deprecated and will be removed in a future version. Please use `layer.__call__` method instead.
  return layer.apply(inputs)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:15: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  from ipykernel import kernelapp as app
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:16: UserWarning: `tf.layers.dense` is deprecated and will be removed in a future version. Please use `tf.keras.layers.Dense` instead.
  app.launch_new_instance()

TF2 मॉडल को परिभाषित करें।

class SimpleModel(tf.keras.Model):
  def __init__(self, params, *args, **kwargs):
    super(SimpleModel, self).__init__(*args, **kwargs)
    # define the model
    self.dense_1 = tf.keras.layers.Dense(params['layer_1_size'])
    self.dense_2 = tf.keras.layers.Dense(params['layer_2_size'])
    self.out = tf.keras.layers.Dense(params['num_classes'])
    learning_rate_fn = tf.keras.optimizers.schedules.PolynomialDecay(
      initial_learning_rate=params['init_lr'],
      decay_steps=params['decay_steps'],
      end_learning_rate=params['end_lr'],
      power=params['lr_power'])  
    self.optimizer = tf.keras.optimizers.SGD(learning_rate_fn)
    self.compiled_loss = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
    self.logs = {
        'lr': [],
        'loss': [],
        'grads': [],
        'weights': [],
        'layer_out': []}

  def call(self, inputs):
    out_1 = self.dense_1(inputs)
    out_2 = self.dense_2(out_1)
    logits = self.out(out_2)
    # log output features for every layer for comparison
    layer_wise_out = {
        'layer_1': out_1,
        'layer_2': out_2,
        'logits': logits}
    self.logs['layer_out'].append(layer_wise_out)
    return logits

  def train_step(self, data):
    x, y = data
    with tf.GradientTape() as tape:
      logits = self(x)
      loss = self.compiled_loss(y, logits)
    grads = tape.gradient(loss, self.trainable_weights)
    # log training statistics
    step = self.optimizer.iterations.numpy()
    self.logs['lr'].append(self.optimizer.learning_rate(step).numpy())
    self.logs['loss'].append(loss.numpy())
    self.logs['grads'].append(grads)
    self.logs['weights'].append(self.trainable_weights)
    # update model
    self.optimizer.apply_gradients(zip(grads, self.trainable_weights))
    return

TF2 मॉडल को उत्सुक मोड में चलाएँ। संख्यात्मक तुल्यता तुलना के लिए पहले 3 प्रशिक्षण चरणों के लिए आंकड़े एकत्र करें।

random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
with random_tool.scope():
  model_tf2 = SimpleModel(params)
  for step in range(step_num):
    model_tf2.train_step([fake_x, fake_y])

पहले कुछ प्रशिक्षण चरणों के लिए संख्यात्मक तुल्यता की तुलना करें।

आप संख्यात्मक तुल्यता के लिए अतिरिक्त सलाह के लिए सत्यापन शुद्धता और संख्यात्मक तुल्यता नोटबुक भी देख सकते हैं।

np.testing.assert_allclose(model_tf1.logs['lr'], model_tf2.logs['lr'])
np.testing.assert_allclose(model_tf1.logs['loss'], model_tf2.logs['loss'])
for step in range(step_num):
  for name in model_tf1.logs['layer_out'][step]:
    np.testing.assert_allclose(
        model_tf1.logs['layer_out'][step][name],
        model_tf2.logs['layer_out'][step][name])

यूनिट परीक्षण

कुछ प्रकार के यूनिट परीक्षण हैं जो आपके माइग्रेशन कोड को डीबग करने में सहायता कर सकते हैं।

  1. सिंगल फॉरवर्ड पास सत्यापन
  2. कुछ चरणों के लिए मॉडल प्रशिक्षण संख्यात्मक तुल्यता सत्यापन
  3. बेंचमार्क अनुमान प्रदर्शन
  4. प्रशिक्षित मॉडल निश्चित और सरल डेटा बिंदुओं पर सही भविष्यवाणी करता है

आप विभिन्न कॉन्फ़िगरेशन वाले मॉडल का परीक्षण करने के लिए @parameterized.parameters का उपयोग कर सकते हैं। कोड नमूने के साथ विवरण

ध्यान दें कि सत्र एपीआई और एक ही परीक्षण मामले में उत्सुक निष्पादन चलाना संभव है। नीचे दिए गए कोड स्निपेट बताते हैं कि कैसे।

import unittest

class TestNumericalEquivalence(unittest.TestCase):

  # copied from code samples above
  def setup(self):
    # record statistics for 100 training steps
    step_num = 100

    # setup TF 1 model
    random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
    with random_tool.scope():
      # run TF1.x code in graph mode with context management
      graph = tf.Graph()
      with graph.as_default(), tf.compat.v1.Session(graph=graph) as sess:
        self.model_tf1 = SimpleModelWrapper()
        # build the model
        inputs = tf.compat.v1.placeholder(tf.float32, shape=(None, params['input_size']))
        labels = tf.compat.v1.placeholder(tf.float32, shape=(None, params['num_classes']))
        spec = self.model_tf1.model_fn(inputs, labels, tf.estimator.ModeKeys.TRAIN, params)
        train_op = spec.train_op

        sess.run(tf.compat.v1.global_variables_initializer())
        for step in range(step_num):
          # log everything and update the model for one step
          logs, _ = sess.run(
              [self.model_tf1.logged_ops, train_op],
              feed_dict={inputs: fake_x, labels: fake_y})
          self.model_tf1.update_logs(logs)

    # setup TF2 model
    random_tool = v1.keras.utils.DeterministicRandomTestTool(mode='num_random_ops')
    with random_tool.scope():
      self.model_tf2 = SimpleModel(params)
      for step in range(step_num):
        self.model_tf2.train_step([fake_x, fake_y])

  def test_learning_rate(self):
    np.testing.assert_allclose(
        self.model_tf1.logs['lr'],
        self.model_tf2.logs['lr'])

  def test_training_loss(self):
    # adopt different tolerance strategies before and after 10 steps
    first_n_step = 10

    # abosolute difference is limited below 1e-5
    # set `equal_nan` to be False to detect potential NaN loss issues
    abosolute_tolerance = 1e-5
    np.testing.assert_allclose(
        actual=self.model_tf1.logs['loss'][:first_n_step],
        desired=self.model_tf2.logs['loss'][:first_n_step],
        atol=abosolute_tolerance,
        equal_nan=False)

    # relative difference is limited below 5%
    relative_tolerance = 0.05
    np.testing.assert_allclose(self.model_tf1.logs['loss'][first_n_step:],
                               self.model_tf2.logs['loss'][first_n_step:],
                               rtol=relative_tolerance,
                               equal_nan=False)

डिबगिंग उपकरण

tf.प्रिंट

tf.print बनाम print/logging.info

  • विन्यास योग्य तर्कों के साथ, tf.print प्रिंटेड टेंसर के लिए प्रत्येक आयाम के पहले और अंतिम कुछ तत्वों को पुनरावर्ती रूप से प्रदर्शित कर सकता है। विवरण के लिए एपीआई दस्तावेज़ देखें।
  • उत्सुक निष्पादन के लिए, print और tf.print दोनों टेंसर के मान को प्रिंट करते हैं। लेकिन print में डिवाइस-टू-होस्ट कॉपी शामिल हो सकती है, जो संभावित रूप से आपके कोड को धीमा कर सकती है।
  • tf.function के अंदर उपयोग सहित ग्राफ़ मोड के लिए, आपको वास्तविक टेंसर मान को प्रिंट करने के लिए tf.print का उपयोग करने की आवश्यकता है। tf.print को ग्राफ़ में एक ऑप में संकलित किया जाता है, जबकि print और logging.info केवल ट्रेसिंग समय पर लॉग करते हैं, जो अक्सर वह नहीं होता जो आप चाहते हैं।
  • tf.print tf.RaggedTensor और tf.sparse.SparseTensor जैसे कंपोजिट टेंसर को प्रिंट करने का भी समर्थन करता है।
  • आप मेट्रिक्स और वेरिएबल की निगरानी के लिए कॉलबैक का भी उपयोग कर सकते हैं। कृपया जांचें कि लॉग्स dict और self.model विशेषता के साथ कस्टम कॉलबैक का उपयोग कैसे करें।

tf.print बनाम tf.function के अंदर प्रिंट करें

# `print` prints info of tensor object
# `tf.print` prints the tensor value
@tf.function
def dummy_func(num):
  num += 1
  print(num)
  tf.print(num)
  return num

_ = dummy_func(tf.constant([1.0]))

# Output:
# Tensor("add:0", shape=(1,), dtype=float32)
# [2]
Tensor("add:0", shape=(1,), dtype=float32)
[2]

tf.वितरित.रणनीति

  • यदि tf.function युक्त tf.print श्रमिकों पर निष्पादित किया जाता है, उदाहरण के लिए TPUStrategy या ParameterServerStrategy का उपयोग करते समय, आपको मुद्रित मानों को खोजने के लिए कार्यकर्ता/पैरामीटर सर्वर लॉग की जांच करने की आवश्यकता होती है।
  • print या logging.info के लिए, ParameterServerStrategy का उपयोग करते समय कोऑर्डिनेटर पर लॉग प्रिंट किए जाएंगे, और TPU का उपयोग करते समय वर्कर0 पर STDOUT पर लॉग प्रिंट किए जाएंगे।

tf.keras.मॉडल

  • अनुक्रमिक और कार्यात्मक एपीआई मॉडल का उपयोग करते समय, यदि आप कुछ परतों के बाद मूल्यों, जैसे, मॉडल इनपुट या मध्यवर्ती सुविधाओं को प्रिंट करना चाहते हैं, तो आपके पास निम्नलिखित विकल्प हैं।
    1. एक कस्टम परत लिखें जो इनपुट को tf.print
    2. उन मध्यवर्ती आउटपुट को शामिल करें जिनका आप मॉडल आउटपुट में निरीक्षण करना चाहते हैं।
  • tf.keras.layers.Lambda परतों में (डी) क्रमांकन सीमाएँ हैं। चेकपॉइंट लोडिंग समस्याओं से बचने के लिए, इसके बजाय एक कस्टम उपवर्गित परत लिखें। अधिक जानकारी के लिए API दस्तावेज़ देखें।
  • आप tf.print में इंटरमीडिएट आउटपुट को tf.keras.callbacks.LambdaCallback .प्रिंट नहीं कर सकते हैं यदि आपके पास वास्तविक मानों तक पहुंच नहीं है, बल्कि इसके बजाय केवल प्रतीकात्मक केरस टेंसर ऑब्जेक्ट्स तक पहुंच है।

विकल्प 1: एक कस्टम परत लिखें

class PrintLayer(tf.keras.layers.Layer):
  def call(self, inputs):
    tf.print(inputs)
    return inputs

def get_model():
  inputs = tf.keras.layers.Input(shape=(1,))
  out_1 = tf.keras.layers.Dense(4)(inputs)
  out_2 = tf.keras.layers.Dense(1)(out_1)
  # use custom layer to tf.print intermediate features
  out_3 = PrintLayer()(out_2)
  model = tf.keras.Model(inputs=inputs, outputs=out_3)
  return model

model = get_model()
model.compile(optimizer="adam", loss="mse")
model.fit([1, 2, 3], [0.0, 0.0, 1.0])
[[-0.327884018]
 [-0.109294668]
 [-0.218589336]]
1/1 [==============================] - 0s 280ms/step - loss: 0.6077
<keras.callbacks.History at 0x7f63d46bf190>
प्लेसहोल्डर17

विकल्प 2: उन मध्यवर्ती आउटपुट को शामिल करें जिनका आप मॉडल आउटपुट में निरीक्षण करना चाहते हैं।

ध्यान दें कि ऐसे मामले में, Model.fit का उपयोग करने के लिए आपको कुछ अनुकूलन की आवश्यकता हो सकती है।

def get_model():
  inputs = tf.keras.layers.Input(shape=(1,))
  out_1 = tf.keras.layers.Dense(4)(inputs)
  out_2 = tf.keras.layers.Dense(1)(out_1)
  # include intermediate values in model outputs
  model = tf.keras.Model(
      inputs=inputs,
      outputs={
          'inputs': inputs,
          'out_1': out_1,
          'out_2': out_2})
  return model

पीडीबी

डीबगिंग के लिए मध्यवर्ती मानों का निरीक्षण करने के लिए आप टर्मिनल और Colab दोनों में pdb का उपयोग कर सकते हैं।

TensorBoard के साथ ग्राफ़ विज़ुअलाइज़ करें

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

टेंसरफ्लो प्रोफाइलर

TensorFlow Profiler आपको GPU/TPU पर निष्पादन समयरेखा की कल्पना करने में मदद कर सकता है। आप इस Colab डेमो को इसके मूल उपयोग के लिए देख सकते हैं।

मल्टीप्रोसेसरनर

MultiWorkerMirroredStrategy और ParameterServerStrategy के साथ डिबगिंग करते समय MultiProcessRunner एक उपयोगी टूल है। आप इसके उपयोग के लिए इस ठोस उदाहरण पर एक नज़र डाल सकते हैं।

विशेष रूप से इन दो रणनीतियों के मामलों के लिए, आपको अनुशंसा की जाती है कि 1) न केवल उनके प्रवाह को कवर करने के लिए यूनिट परीक्षण हों, 2) बल्कि यूनिट परीक्षण में इसका उपयोग करके विफलताओं को पुन: उत्पन्न करने का प्रयास करने के लिए हर बार जब वे प्रयास करते हैं तो वास्तविक वितरित नौकरी लॉन्च करने से बचें। जोडना।