TensorFlow ऑपरेशन फ़्यूज़न

खास जानकारी

इस पेज में कंपोज़िट ऑपरेशन को बदलने के लिए ज़रूरी डिज़ाइन और तरीके के बारे में बताया गया है TensorFlow में, LiteRT में फ़्यूज़्ड ऑपरेशन के लिए. इस इन्फ़्रास्ट्रक्चर सामान्य उद्देश्य और TensorFlow में किसी भी कंपोज़िट ऑपरेशन को बदलने में मदद करता है LiteRT में, एक ही तरह के फ़्यूज़्ड ऑपरेशन को पूरा करता है.

इस इन्फ़्रास्ट्रक्चर के इस्तेमाल का एक उदाहरण TensorFlow RNN ऑपरेशन फ़्यूज़न है LiteRT के बारे में ज़्यादा जानकारी यहां दी गई है.

फ़्यूज़्ड ऑपरेशन क्या होते हैं

ड्रॉइंग

TensorFlow की कार्रवाइयां, शुरुआती ऑपरेशन हो सकती हैं, जैसे कि tf.add या ये ऐसा किया जा सकता है अन्य प्रिमिटिव ऑपरेशंस से मिलकर बना कॉन्टेंट, जैसे कि tf.einsum. प्रिमिटिव ऑपरेशन TensorFlow ग्राफ़ में सिंगल नोड के रूप में दिखता है, जबकि एक कंपोज़िट ऑपरेशन, TensorFlow ग्राफ़ में नोड का कलेक्शन होता है. एक्ज़ीक्यूट किया जा रहा है कंपोज़िट ऑपरेशन, अपने हर मूल घटक को लागू करने के बराबर होता है कार्रवाइयां.

फ़्यूज़्ड ऑपरेशन एक ऐसे ऑपरेशन को दिखाता है जिसमें सभी हर प्रिमिटिव ऑपरेशन की मदद से हुई गणना कंपोज़िट ऑपरेशन का इस्तेमाल करना.

अलग-अलग तरह के ऑपरेशन के फ़ायदे

फ़्यूज़्ड ऑपरेशन, अपने कर्नेल की परफ़ॉर्मेंस को बेहतर बनाने के लिए होते हैं लागू करने के लिए, सभी कंप्यूटेशन को ऑप्टिमाइज़ करके और मेमोरी को कम करके फ़ुटप्रिंट. यह बेहद अहम है. खास तौर पर, इंतज़ार का समय कम होने पर लगने वाले वर्कलोड के लिए और सीमित संसाधन वाले मोबाइल प्लैटफ़ॉर्म पर करते हैं.

फ़्यूज़न कार्रवाइयां, कॉम्प्लेक्स को परिभाषित करने के लिए हाई लेवल का इंटरफ़ेस भी उपलब्ध कराती हैं क्वांटाइज़ेशन जैसे बदलाव ज़्यादा बारीकी से बताना मुश्किल है.

LiteRT में, कई तरह की कार्रवाइयां एक साथ मौजूद हैं. ऐसा इन वजहों से होता है ऊपर साफ़ तौर पर बताया गया है. आम तौर पर, एक ही तरह से की गई ये कार्रवाइयां कंपोज़िट से जुड़ी होती हैं ये कार्रवाइयां, सोर्स TensorFlow प्रोग्राम में शामिल हैं. इसमें मिश्रित संक्रियाओं के उदाहरण ऐसे TensorFlow जिन्हें LiteRT में एक ही फ़्यूज़्ड ऑपरेशन के तौर पर लागू किया जाता है इसमें विभिन्न RNN संक्रियाएं शामिल होती हैं, जैसे एकतरफ़ा और द्विदिशात्मक अनुक्रम एलएसटीएम, कॉन्वोल्यूशन (कॉन्वलूशन (कॉन्वलूशन), बायस ऐड, रेलू), पूरी तरह से कनेक्ट (मैटमुल, बायस ऐड, relu) और बहुत कुछ. फ़िलहाल, LiteRT में एलएसटीएम को मापने की सुविधा सिर्फ़ एलएसटीएम के एक साथ इस्तेमाल किए जाने वाले ऑपरेशन में लागू किया गया.

अलग-अलग तरह से काम करने में आने वाली चुनौतियां

इसमें, कंपोज़िट ऑपरेशन को TensorFlow से फ़्यूज़्ड ऑपरेशन में बदलना LiteRT एक मुश्किल समस्या है. ऐसा इसलिए होता है, क्योंकि:

  1. कंपोज़िट ऑपरेशन को TensorFlow ग्राफ़ में, साफ़ तौर पर तय सीमा के बिना, पहले से इस्तेमाल किए जाने वाले ऑपरेशन. यह काम करने में सब-ग्राफ़ को पहचानना मुश्किल है (जैसे, पैटर्न मैचिंग की मदद से) जो ऐसे किसी कंपोज़िट ऑपरेशन के मुताबिक हो.

  2. फ़्यूज़ किए गए फ़ंक्शन को टारगेट करने के लिए, एक से ज़्यादा TensorFlow का इस्तेमाल किया जा सकता है LiteRT की कार्रवाई. उदाहरण के लिए, एलएसटीएम को कई तरीकों से लागू किया जाता है TensorFlow (केरस, बेबलफ़िश/लिंगवो वगैरह) में मौजूद है और इनमें से हर एक अलग-अलग आदिम संक्रियाएं हैं, लेकिन उन सभी को अभी भी LiteRT में एक जैसा एलएसटीएम ऑपरेशन.

इसलिए, कई तरह के ऑपरेशन को ग्राहक में बदलना काफ़ी चुनौती भरा साबित हुआ है.

कंपोज़िट ऑपरेशन को tf.function में रैप करें

कई मामलों में, मॉडल के कुछ हिस्से को एक ऑपरेशन में मैप किया जा सकता है TFLite. इससे, ऑप्टिमाइज़ किए गए तरीके की जानकारी लिखते समय, परफ़ॉर्मेंस बेहतर करने में मदद मिलती है खास कार्रवाइयों के लिए. TFLite में फ़्यूज़्ड ऑपरेशन बनाने के लिए, ग्राफ़ के उस हिस्से की पहचान करें जो फ़्यूज़्ड ऑपरेशन दिखाता है और फिर उसे किसी tf.function को "प्रायोगिक_लागू करता है" एट्रिब्यूट को tf.function को दिया गया, जिसमें एट्रिब्यूट है true मान वाली tfl_fusable_op. अगर पसंद के मुताबिक कार्रवाई की जाती है एट्रिब्यूट की वैल्यू के तौर पर इस्तेमाल किया जाता है.

उदाहरण के लिए,

def get_implements_signature():
  implements_signature = [
    # 'name' will be used as a name for the operation.
    'name: "my_custom_fused_op"',
    # attr "tfl_fusable_op" is required to be set with true value.
    'attr {key: "tfl_fusable_op" value { b: true } }',
    # Example attribute "example_option" that the op accepts.
    'attr {key: "example_option" value { i: %d } }' % 10
  ]
  return ' '.join(implements_signature)

@tf.function(experimental_implements=get_implements_signature())
def my_custom_fused_op(input_1, input_2):
  # An empty function that represents pre/post processing example that
  # is not represented as part of the Tensorflow graph.
  output_1 = tf.constant(0.0, dtype=tf.float32, name='first_output')
  output_2 = tf.constant(0.0, dtype=tf.float32, name='second_output')
  return output_1, output_2

class TestModel(tf.Module):
  def __init__(self):
    super(TestModel, self).__init__()
    self.conv_1 = tf.keras.layers.Conv2D(filters=1, kernel_size=(3, 3))
    self.conv_2 = tf.keras.layers.Conv2D(filters=1, kernel_size=(3, 3))

  @tf.function(input_signature=[
      tf.TensorSpec(shape=[1, 28, 28, 3], dtype=tf.float32),
      tf.TensorSpec(shape=[1, 28, 28, 3], dtype=tf.float32),
  ])
  def simple_eval(self, input_a, input_b):
    return my_custom_fused_op(self.conv_1(input_a), self.conv_2(input_b))

ध्यान दें कि आपको कन्वर्टर पर allow_custom_ops को इस रूप में सेट करने की ज़रूरत नहीं है tfl_fusable_op एट्रिब्यूट का मतलब है पहले ही.

पसंद के मुताबिक सेशन लागू करें और TFLite Translator के साथ रजिस्टर करें

एक साथ इस्तेमाल किए गए ऑपरेशन को TFLite कस्टम ऑपरेशन के तौर पर लागू करें - देखें निर्देश.

ध्यान दें कि कानूनी समझौते के लिए रजिस्टर करने के लिए दिया गया नाम, नाम से मिलता-जुलता होना चाहिए हस्ताक्षर लागू करता है, जिसमें name एट्रिब्यूट की वैल्यू दी गई है.

उदाहरण में सेशन का एक उदाहरण यह है

  TfLiteRegistration reg = {};
  // This name must match the name specified in the implements signature.
  static constexpr char kOpName[] = "my_custom_fused_op";
  reg.custom_name = kOpName;
  reg.prepare = [](TfLiteContext* context, TfLiteNode* node) -> TfLiteStatus {
    // Add your code.
    return kTfLiteOk;
  };
  reg.invoke = [](TfLiteContext* context, TfLiteNode* node) -> TfLiteStatus {
    // Add your code.
    return kTfLiteOk;
  };
  reg.builtin_code = kTfLiteCustom;
  resolver->AddCustom(kOpName, &reg);

कंपोज़िट से फ़्यूज़्ड ऑपरेशन में बदलना (ऐडवांस)

TensorFlow के कंपोज़िट ऑपरेशन को इसमें बदलने का पूरा आर्किटेक्चर LiteRT फ़्यूज़्ड ऑपरेशन की जानकारी नीचे दी गई है:

ड्रॉइंग

कंपोज़िट ऑपरेशन को tf.function में रैप करें

TensorFlow मॉडल के सोर्स कोड में, कंपोज़िट की पहचान करें और उसका ऐब्स्ट्रैक्ट निकालें की मदद से, tf.function भी सेट करें, experimental_implements फ़ंक्शन एनोटेशन. लुकअप एम्बेड करने का उदाहरण देखें. कॉन्टेंट बनाने फ़ंक्शन, इंटरफ़ेस को परिभाषित करता है और इसके आर्ग्युमेंट का इस्तेमाल कन्वर्ज़न लॉजिक की पहचान करता है.

कन्वर्ज़न कोड लिखें

कन्वर्ज़न कोड, फ़ंक्शन के इंटरफ़ेस के हिसाब से लिखा जाता है. implements एनोटेशन. एम्बेड करने की प्रक्रिया के लिए फ़्यूज़न का उदाहरण देखें देखें. सैद्धांतिक रूप से, रूपांतरण कोड कंपोज़िट को बदल देता है इस इंटरफ़ेस को फ़्यूज़ किए गए के साथ लागू करना.

तैयार-कंपोज़िट-फ़ंक्शन पास में, अपने कन्वर्ज़न में प्लगिन कोड.

ज़्यादा ऐडवांस इस्तेमाल में, मुश्किल बदलावों को लागू किया जा सकता है फ़्यूज़ के ऑपरेंड को पाने के लिए, कंपोज़िट ऑपरेशन के ऑपरेंड कार्रवाई. केरस देखें LSTM. कन्वर्ज़न कोड का उदाहरण देखें.

LiteRT में बदलें

इसका इस्तेमाल करें TFLiteConverter.from_saved_model LiteRT में बदलने के लिए एपीआई.

हुड के तहत

अब हम, फ़्यूज़ में बदलने के लिए पूरे डिज़ाइन की हाई लेवल जानकारी के बारे में बताते हैं LiteRT में कार्रवाइयां.

TensorFlow में कंपोज़िंग ऑपरेशन

tf.function का इस्तेमाल के साथ experimental_implements फ़ंक्शन एट्रिब्यूट की मदद से उपयोगकर्ता, TensorFlow प्रिमिटिव ऑपरेशन और उस इंटरफ़ेस के बारे में बताएं जिसे नतीजे के तौर पर कंपोज़िट ऑपरेशन लागू करता है. यह काफ़ी फ़ायदेमंद है, क्योंकि इससे ये सुविधाएं मिलती हैं:

  1. बुनियादी में कंपोज़िट ऑपरेशन की अच्छी तरह से तय सीमा TensorFlow ग्राफ़.
  2. उस इंटरफ़ेस के बारे में साफ़ तौर पर बताएं जिसे यह कार्रवाई लागू करती है. कॉन्टेंट बनाने के तर्क tf.function इस इंटरफ़ेस के आर्ग्युमेंट के हिसाब से होता है.

उदाहरण के लिए, लागू करने के लिए तय किए गए एक कंपोज़िट ऑपरेशन पर विचार करें एम्बेडिंग लुकअप. यह LiteRT में फ़्यूज़्ड ऑपरेशन पर मैप करता है.

  @tf.function(
        experimental_implements="embedding_lookup")
    def EmbFprop(embs, ids_vec):
      """Embedding forward prop.

      Effectively, it computes:
        num = size of ids_vec
        rets = zeros([num, embedding dim])
        for i in range(num):
          rets[i, :] = embs[ids_vec[i], :]
        return rets

      Args:
        embs: The embedding matrix.
        ids_vec: A vector of int32 embedding ids.

      Returns:
        The result of embedding lookups. A matrix of shape
        [num ids in ids_vec, embedding dims].
      """
      num = tf.shape(ids_vec)[0]
      rets = inplace_ops.empty([num] + emb_shape_suf, py_utils.FPropDtype(p))

      def EmbFpropLoop(i, embs, ids_vec, rets):
        # row_id = ids_vec[i]
        row_id = tf.gather(ids_vec, i)
        # row = embs[row_id]
        row = tf.reshape(tf.gather(embs, row_id), [1] + emb_shape_suf)
        # rets[i] = row
        rets = inplace_ops.alias_inplace_update(rets, [i], row)
        return embs, ids_vec, rets

      _, _, rets = functional_ops.For(
          start=0,
          limit=num,
          delta=1,
          inputs=[embs, ids_vec, rets],
          body=EmbFpropLoop,
          rewrite_with_while=compiled)
      if len(weight_shape) > 2:
        rets = tf.reshape(rets, [num, symbolic.ToStatic(p.embedding_dim)])
      return rets

मॉडल को इसके माध्यम से मिश्रित संक्रियाओं का उपयोग करके बनाना tf.function: ऊपर दी गई इमेज में बताया गया है कि ख़रीदारी के लिए एक सामान्य इन्फ़्रास्ट्रक्चर बनाना मुमकिन हो जाता है इस तरह की कार्रवाइयों की पहचान करके, उन्हें फ़्यूज़ की गई LiteRT की कार्रवाइयों में बदलें.

LiteRT कन्वर्टर को बढ़ाना

इस साल की शुरुआत में रिलीज़ किया गया LiteRT कन्वर्टर सिर्फ़ काम करता है TensorFlow के मॉडल को ग्राफ़ के रूप में इंपोर्ट करना, जिसमें सभी वैरिएबल की जगह संगत स्थिर मान. यह ऑपरेशन फ़्यूज़न के लिए काम नहीं करता है, क्योंकि ऐसे ग्राफ़ में सभी फ़ंक्शन इनलाइन होते हैं, ताकि वैरिएबल को स्थिरांक.

Google Ads API का इस्तेमाल करने से पहले tf.function भी सेट करें, experimental_implements सुविधा को कन्वर्ज़न प्रोसेस के दौरान, फ़ंक्शन को रूपांतरण प्रक्रिया में बाद तक बनाए रखना ज़रूरी है.

इसलिए, हमने TensorFlow को इंपोर्ट करने और बदलने का एक नया वर्कफ़्लो लागू किया कंपोज़िट ऑपरेशन फ़्यूज़न उपयोग के उदाहरण का समर्थन करने के लिए कन्वर्टर में मॉडल. खास तौर पर, जोड़ी गई नई सुविधाएं ये हैं:

  1. TensorFlow को MLIR में सेव किए गए मॉडल में इंपोर्ट करना
  2. फ़्यूज़ कंपोज़िट ऑपरेशन
  3. वैरिएबल म्यूटेबिलिटी ऐनलिसिस
  4. सभी रीड-ओनली वैरिएबल को फ़्रीज़ करना

इसकी मदद से, हम इनलाइनिंग और वैरिएबल फ़्रीज़िंग से पहले के कंपोज़िट ऑपरेशन का इस्तेमाल किया गया.

ऑपरेशन फ़्यूज़न को लागू करना

आइए, ऑपरेशन फ़्यूजन पास के बारे में ज़्यादा जानकारी पाएं. इस पास की मदद से, फ़ॉलो किया जा रहा है:

  1. MLIR मॉड्यूल में सभी फ़ंक्शन को लूप में चलाएं.
  2. अगर किसी फ़ंक्शन में एट्रिब्यूट के आधार पर tf._लागू करता है वैल्यू, सही ऑपरेशन फ़्यूज़न उपयोगिता कॉल करता है.
  3. ऑपरेशन फ़्यूजन यूटिलिटी फ़ंक्शन के ऑपरेंड पर काम करती है और एट्रिब्यूट (जो कन्वर्ज़न के लिए इंटरफ़ेस के तौर पर काम करते हैं) और फ़ंक्शन का मुख्य हिस्सा, जिसमें फ़ंक्शन के मुख्य हिस्से में अलग-अलग तरह से एक साथ काम करता है.
  4. कई मामलों में, बदले गए मुख्य भाग में अलग-अलग तरह से एक साथ काम करता है. ये कुछ स्टैटिक ट्रांसफ़ॉर्म के मुताबिक फ़ंक्शन के ऑपरेंड को, फ़्यूज़ किए गए ऑपरेशन के ऑपरेंड पाने के लिए इस्तेमाल किया जाता है. इन सभी कंप्यूटेशन को एक ही जगह पर फ़ोल्ड किया जा सकता है, इसलिए ये एक्सपोर्ट किए गए फ़्लैटबफ़र में मौजूद होता है, जहां सिर्फ़ फ़्यूज़ किया गया ऑपरेशन होता है मौजूद हैं.

यहां मुख्य वर्कफ़्लो को दिखाने वाले पास से लिया गया कोड स्निपेट दिया गया है:

void PrepareCompositeFunctionsPass::ConvertTFImplements(FuncOp func,
                                                        StringAttr attr) {
  if (attr.getValue() == "embedding_lookup") {
    func.eraseBody();
    func.addEntryBlock();
    // Convert the composite embedding_lookup function body to a
    // TFLite fused embedding_lookup op.
    ConvertEmbeddedLookupFunc convert_embedded_lookup(func);
    if (failed(convert_embedded_lookup.VerifySignature())) {
      return signalPassFailure();
    }
    convert_embedded_lookup.RewriteFunc();
  } else if (attr.getValue() == mlir::TFL::kKerasLstm) {
     func.eraseBody();
     func.addEntryBlock();
     OpBuilder builder(func.getBody());
     if (failed(ConvertKerasLSTMLayer(func, &builder))) {
       return signalPassFailure();
     }
  } else if (.....) /* Other fusions can plug in here */
}

यहां कोड स्निपेट दिखाया गया है. यह इस कंपोज़िट ऑपरेशन को फ़्यूज़ के साथ मैप करता हुआ दिखा रहा है LiteRT में इस फ़ंक्शन का इस्तेमाल करके, कन्वर्ज़न इंटरफ़ेस के तौर पर काम करता है.

void RewriteFunc() {
    Value lookup = func_.getArgument(1);
    Value value = func_.getArgument(0);
    auto output_type = func_.getType().getResult(0);

    OpBuilder builder(func_.getBody());
    auto op = builder.create<mlir::TFL::EmbeddingLookupOp>(
        func_.getLoc(), output_type, lookup, value);

    builder.create<mlir::ReturnOp>(func_.getLoc(), op.getResult());
  }