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

संग्रह की मदद से व्यवस्थित रहें अपनी प्राथमिकताओं के आधार पर, कॉन्टेंट को सेव करें और कैटगरी में बांटें.

अवलोकन

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

इस बुनियादी ढांचे का एक उदाहरण उपयोग TensorFlow RNN ऑपरेशन फ्यूजन से TensorFlow Lite है, जैसा कि यहां विस्तृत है

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

चित्रकारी

TensorFlow संचालन या तो आदिम ऑप्स हो सकते हैं जैसे tf.add या उन्हें अन्य आदिम संचालन जैसे tf.einsum से बनाया जा सकता है। एक आदिम ऑपरेशन TensorFlow ग्राफ़ में एकल नोड के रूप में दिखाई देता है जबकि एक समग्र ऑपरेशन TensorFlow ग्राफ़ में नोड्स का एक संग्रह है। एक समग्र ऑपरेशन निष्पादित करना इसके प्रत्येक घटक आदिम संचालन को निष्पादित करने के बराबर है।

एक फ़्यूज्ड ऑपरेशन एक एकल ऑपरेशन से मेल खाता है जो प्रत्येक आदिम ऑपरेशन द्वारा संबंधित समग्र ऑपरेशन के भीतर किए गए सभी गणनाओं को सम्मिलित करता है।

फ़्यूज्ड ऑपरेशंस के लाभ

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

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

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

फ़्यूज्ड ऑपरेशंस के साथ चुनौतियां

TensorFlow लाइट में समग्र संचालन को TensorFlow से फ़्यूज़्ड संचालन में परिवर्तित करना एक कठिन समस्या है। यह है क्योंकि:

  1. TensorFlow ग्राफ़ में समग्र संचालन को एक अच्छी तरह से परिभाषित सीमा के बिना आदिम संचालन के एक सेट के रूप में दर्शाया गया है। इस तरह के एक संयुक्त ऑपरेशन के अनुरूप उप-ग्राफ की पहचान करना (उदाहरण के लिए पैटर्न मिलान के माध्यम से) बहुत चुनौतीपूर्ण हो सकता है।

  2. फ़्यूज़ किए गए TensorFlow लाइट ऑपरेशन को लक्षित करने वाले एक से अधिक TensorFlow कार्यान्वयन हो सकते हैं। उदाहरण के लिए, TensorFlow (Keras, Babelfish/lingvo आदि) में कई LSTM कार्यान्वयन हैं और इनमें से प्रत्येक अलग-अलग आदिम संचालन से बना है, लेकिन वे सभी अभी भी TensorFlow Lite में एक ही फ़्यूज्ड LSTM ऑपरेशन में परिवर्तित हो सकते हैं।

जैसे, फ़्यूज्ड ऑपरेशंस का रूपांतरण काफी चुनौतीपूर्ण साबित हुआ है।

एक tf.function में समग्र ऑपरेशन लपेटें

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

उदाहरण,

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 इंटरप्रेटर के साथ रजिस्टर करें

अपने फ़्यूज्ड ऑपरेशन को TFLite कस्टम ऑपरेशन के रूप में लागू करें - निर्देश देखें।

ध्यान दें कि, op को रजिस्टर करने के लिए नाम इम्प्लीमेंट सिग्नेचर में 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 coder.
    return kTfLiteOk;
  };
  reg.builtin_code = kTfLiteCustom;
  resolver->AddCustom(kOpName, &reg);

कंपोजिट से फ्यूज्ड ऑपरेशन में कनवर्ट करना (उन्नत)

TensorFlow कम्पोजिट ऑपरेशंस को TensorFlow Lite फ़्यूज्ड ऑपरेशंस में कनवर्ट करने के लिए समग्र आर्किटेक्चर नीचे है:

चित्रकारी

एक tf.function में समग्र ऑपरेशन लपेटें

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

रूपांतरण कोड लिखें

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

तैयार-समग्र-फ़ंक्शंस पास में, अपने रूपांतरण कोड में प्लग इन करें।

अधिक उन्नत उपयोगों में, फ़्यूज्ड ऑपरेशन के ऑपरेंड को प्राप्त करने के लिए समग्र ऑपरेशन के ऑपरेंड के जटिल परिवर्तनों को लागू करना संभव है। केरस LSTM देखें। एक उदाहरण के रूप में रूपांतरण कोड।

TensorFlow Lite में कनवर्ट करें

TensorFlow Lite में कनवर्ट करने के लिए TFLiteConverter.from_saved_model API का उपयोग करें।

हुड के नीचे

अब हम TensorFlow Lite में फ़्यूज़ किए गए संचालन में कनवर्ट करने के लिए समग्र डिज़ाइन के उच्च स्तरीय विवरण का वर्णन करते हैं।

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

प्रयोगात्मक_कार्यान्वयन फ़ंक्शन विशेषता के साथ tf.function का उपयोग उपयोगकर्ताओं को स्पष्ट रूप से TensorFlow आदिम संचालन का उपयोग करके नए संचालन की रचना करने और परिणामी समग्र संचालन लागू करने वाले इंटरफ़ेस को निर्दिष्ट करने की अनुमति देता है। यह बहुत उपयोगी है क्योंकि यह प्रदान करता है:

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

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

  @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 के माध्यम से समग्र संचालन का उपयोग करके, ऐसे संचालन की पहचान करने और उन्हें जुड़े हुए TensorFlow लाइट संचालन में बदलने के लिए एक सामान्य बुनियादी ढाँचा बनाना संभव हो जाता है।

TensorFlow लाइट कनवर्टर का विस्तार

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

रूपांतरण प्रक्रिया के दौरान experimental_implements सुविधा के साथ tf.function . फ़ंक्शन का लाभ उठाने के लिए, रूपांतरण प्रक्रिया में फ़ंक्शंस को बाद तक बनाए रखने की आवश्यकता होती है।

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

  1. TensorFlow सहेजे गए मॉडल को MLIR में आयात करना
  2. फ्यूज समग्र संचालन
  3. परिवर्तनीय परिवर्तनशीलता विश्लेषण
  4. सभी रीड-ओनली वैरिएबल को फ्रीज करें

यह हमें फ़ंक्शन इनलाइनिंग और वेरिएबल फ्रीजिंग से पहले समग्र संचालन का प्रतिनिधित्व करने वाले कार्यों का उपयोग करके ऑपरेशन फ़्यूज़न करने की अनुमति देता है।

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

आइए ऑपरेशन फ्यूजन पास को अधिक विस्तार से देखें। यह पास निम्न कार्य करता है:

  1. एमएलआईआर मॉड्यूल में सभी कार्यों के माध्यम से लूप।
  2. यदि किसी फ़ंक्शन में tf._implements विशेषता है, तो विशेषता मान के आधार पर, उपयुक्त ऑपरेशन फ़्यूज़न उपयोगिता को कॉल करता है।
  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 */
}

यहाँ कोड स्निपेट है जो इस समग्र ऑपरेशन को TensorFlow Lite में एक फ़्यूज़्ड ऑपरेशन के लिए मैपिंग दिखा रहा है जो फ़ंक्शन को रूपांतरण इंटरफ़ेस के रूप में उपयोग करता है।

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());
  }