माइक्रोकंट्रोलर का इस्तेमाल शुरू करना

इस दस्तावेज़ में किसी मॉडल को ट्रेनिंग देने और माइक्रोकंट्रोलर का इस्तेमाल करके अनुमान चलाने का तरीका बताया गया है.

नमस्ते दुनिया का उदाहरण

Hello World का उदाहरण, माइक्रोकंट्रोलर के लिए TensorFlow Lite इस्तेमाल करने की बुनियादी बातें बताने के लिए डिज़ाइन किया गया है. हम एक ऐसे मॉडल को ट्रेनिंग देते हैं और चलाते हैं जो साइन फ़ंक्शन की नकल करता है. इसका मतलब है कि यह सिंगल नंबर को इसके इनपुट के तौर पर इस्तेमाल करता है और नंबर की sine वैल्यू दिखाता है. जब माइक्रोकंट्रोलर में डिप्लॉय किया जाता है, तो इसके अनुमान, एलईडी लाइटों को ब्लिंक करने या किसी ऐनिमेशन को कंट्रोल करने के लिए इस्तेमाल किए जाते हैं.

इस तरीके से, बातचीत शुरू की जा सकती है:

  1. मॉडल को ट्रेन करना (Python में): डिवाइस पर इस्तेमाल करने के लिए, मॉडल को ट्रेनिंग देने, बदलने, और ऑप्टिमाइज़ करने के लिए एक Python फ़ाइल.
  2. अनुमान चलाएं (C++ 17 में): एक एंड-टू-एंड यूनिट टेस्ट, जो C++ लाइब्रेरी का इस्तेमाल करके मॉडल पर अनुमान चलाता है.

ऐसा डिवाइस लें जिस पर यह सुविधा काम करती हो

हम जिस ऐप्लिकेशन का इस्तेमाल करेंगे, उसकी जांच इन डिवाइसों पर की गई है:

माइक्रोकंट्रोलर के लिए TensorFlow Lite में काम करने वाले प्लैटफ़ॉर्म के बारे में ज़्यादा जानें.

किसी मॉडल को ट्रेनिंग दें

साइनवेव पहचानने के लिए हैलो वर्ल्ड मॉडल ट्रेनिंग के लिए, train.py का इस्तेमाल करें

रन: bazel build tensorflow/lite/micro/examples/hello_world:train bazel-bin/tensorflow/lite/micro/examples/hello_world/train --save_tf_model --save_dir=/tmp/model_created/

अनुमान चलाएं

आपके डिवाइस पर मॉडल चलाने के लिए, हम README.md में दिए गए निर्देशों के बारे में बताएंगे:

नमस्ते विश्व README.md

यहां दिए गए सेक्शन में, उदाहरण के तौर पर दिए गए evaluate_test.cc यूनिट टेस्ट के बारे में बताया गया है. इसमें माइक्रोकंट्रोलर के लिए TensorFlow Lite की मदद से, अनुमान लगाने का तरीका बताया गया है. यह मॉडल लोड करता है और कई बार अनुमान लगाता है.

1. लाइब्रेरी के हेडर शामिल करें

माइक्रोकंट्रोलर लाइब्रेरी के लिए TensorFlow Lite का इस्तेमाल करने के लिए, हमें नीचे दी गई हेडर फ़ाइलें शामिल करनी होंगी:

#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/version.h"
  • micro_mutable_op_resolver.h इससे उन ऑपरेशन की जानकारी मिलती है जिनका इस्तेमाल, अनुवादक मॉडल को चलाने के लिए करता है.
  • micro_error_reporter.h डीबग की जानकारी देता है.
  • micro_interpreter.h इसमें मॉडल लोड करने और चलाने के लिए कोड होता है.
  • schema_generated.h इसमें TensorFlow Lite FlatBuffer मॉडल फ़ाइल फ़ॉर्मैट का स्कीमा शामिल होता है.
  • version.h से, TensorFlow Lite स्कीमा के वर्शन की जानकारी मिलती है.

2. मॉडल हेडर शामिल करें

माइक्रोकंट्रोलर के लिए TensorFlow Lite का मतलब है कि मॉडल C++ कलेक्शन के तौर पर होगा. मॉडल की जानकारी model.h और model.cc फ़ाइलों में दी गई है. हेडर में नीचे दी गई लाइन शामिल होती है:

#include "tensorflow/lite/micro/examples/hello_world/model.h"

3. यूनिट टेस्ट फ़्रेमवर्क हेडर शामिल करें

यूनिट टेस्ट को बनाने के लिए, हम माइक्रोकंट्रोलर यूनिट टेस्ट फ़्रेमवर्क के लिए TensorFlow Lite शामिल करते हैं. इसके लिए, हम यह लाइन शामिल करते हैं:

#include "tensorflow/lite/micro/testing/micro_test.h"

टेस्ट को नीचे दिए गए मैक्रो का इस्तेमाल करके तय किया जाता है:

TF_LITE_MICRO_TESTS_BEGIN

TF_LITE_MICRO_TEST(LoadModelAndPerformInference) {
  . // add code here
  .
}

TF_LITE_MICRO_TESTS_END

अब हम ऊपर मैक्रो में शामिल कोड पर चर्चा करते हैं.

4. लॉग इन करने की सुविधा सेट अप करें

लॉगिंग सेट अप करने के लिए, tflite::MicroErrorReporter इंस्टेंस के पॉइंटर का इस्तेमाल करके tflite::ErrorReporter पॉइंटर बनाया जाता है:

tflite::MicroErrorReporter micro_error_reporter;
tflite::ErrorReporter* error_reporter = &micro_error_reporter;

इस वैरिएबल को इंटरप्रेटर में पास किया जाएगा, जिससे यह लॉग लिख पाएगा. माइक्रोकंट्रोलर के पास अक्सर डेटा लॉग करने के लिए कई तरह के तरीके होते हैं. इसलिए, tflite::MicroErrorReporter को आपके डिवाइस के हिसाब से डिज़ाइन किया गया है.

5. मॉडल लोड करें

नीचे दिए गए कोड में, मॉडल को char कलेक्शन g_model के डेटा का इस्तेमाल करके इंस्टैंशिएट किया जाता है, जिसके बारे में model.h में बताया गया है. इसके बाद हम मॉडल की जांच करते हैं, ताकि यह पक्का कर सकें कि इसका स्कीमा वर्शन, इस्तेमाल किए जा रहे वर्शन के साथ काम करता है या नहीं:

const tflite::Model* model = ::tflite::GetModel(g_model);
if (model->version() != TFLITE_SCHEMA_VERSION) {
  TF_LITE_REPORT_ERROR(error_reporter,
      "Model provided is schema version %d not equal "
      "to supported version %d.\n",
      model->version(), TFLITE_SCHEMA_VERSION);
}

6. इंस्टैंशिएट ऑपरेशन रिज़ॉल्वर

एक MicroMutableOpResolver इंस्टेंस का एलान किया जाता है. इसका इस्तेमाल, मॉडल में इस्तेमाल की जाने वाली कार्रवाइयों को रजिस्टर और ऐक्सेस करने के लिए किया जाएगा:

using HelloWorldOpResolver = tflite::MicroMutableOpResolver<1>;

TfLiteStatus RegisterOps(HelloWorldOpResolver& op_resolver) {
  TF_LITE_ENSURE_STATUS(op_resolver.AddFullyConnected());
  return kTfLiteOk;

MicroMutableOpResolver के लिए एक टेंप्लेट पैरामीटर ज़रूरी होता है. यह पैरामीटर, रजिस्टर किए जाने वाले ऑपरेशन की संख्या दिखाता है. RegisterOps फ़ंक्शन, रिज़ॉल्वर के साथ ऑपरेशन को रजिस्टर करता है.

HelloWorldOpResolver op_resolver;
TF_LITE_ENSURE_STATUS(RegisterOps(op_resolver));

7. मेमोरी आवंटित करें

इनपुट, आउटपुट, और इंटरमीडिएट अरे के लिए, हमें एक तय मेमोरी पहले से तय करनी होती है. इसे uint8_t साइज़ tensor_arena_size के कलेक्शन के तौर पर दिया गया है:

const int tensor_arena_size = 2 * 1024;
uint8_t tensor_arena[tensor_arena_size];

आवश्यक आकार उस मॉडल पर निर्भर करेगा, जिसका आप उपयोग कर रहे हैं और उसे प्रयोग के आधार पर निर्धारित करने की आवश्यकता हो सकती है.

8. इंस्टैंशिएट करें, अनुवादक

हम एक tflite::MicroInterpreter इंस्टेंस बनाते हैं, जो पहले बनाए गए वैरिएबल को पास करता है:

tflite::MicroInterpreter interpreter(model, resolver, tensor_arena,
                                     tensor_arena_size, error_reporter);

9. टेंसर तय करें

हम अनुवादक को कहते हैं कि वह मॉडल के टेंसर के लिए, tensor_arena से मेमोरी तय करे:

interpreter.AllocateTensors();

10. इनपुट के आकार की पुष्टि करें

.input(0) को कॉल करके, MicroInterpreter इंस्टेंस हमें मॉडल के इनपुट टेंसर का पॉइंटर दे सकता है. इसमें 0 पहले और सिर्फ़ इनपुट टेंसर को दिखाता है:

  // Obtain a pointer to the model's input tensor
  TfLiteTensor* input = interpreter.input(0);

इसके बाद हम इस टेंसर की जांच करके यह पुष्टि करते हैं कि इसके आकार और टाइप के हिसाब से हमें यह उम्मीद की जा रही है:

// Make sure the input has the properties we expect
TF_LITE_MICRO_EXPECT_NE(nullptr, input);
// The property "dims" tells us the tensor's shape. It has one element for
// each dimension. Our input is a 2D tensor containing 1 element, so "dims"
// should have size 2.
TF_LITE_MICRO_EXPECT_EQ(2, input->dims->size);
// The value of each element gives the length of the corresponding tensor.
// We should expect two single element tensors (one is contained within the
// other).
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[0]);
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[1]);
// The input is a 32 bit floating point value
TF_LITE_MICRO_EXPECT_EQ(kTfLiteFloat32, input->type);

एनम वैल्यू kTfLiteFloat32, TensorFlow Lite के डेटा टाइप में से एक का रेफ़रंस है. इसकी जानकारी common.h में दी गई है.

11. इनपुट वैल्यू डालें

मॉडल को इनपुट देने के लिए, हम इनपुट टेंसर के कॉन्टेंट को इस तरह सेट करते हैं:

input->data.f[0] = 0.;

इस मामले में, हम 0 को दिखाने वाला फ़्लोटिंग पॉइंट वैल्यू डालते हैं.

12. मॉडल चलाएं

मॉडल को चलाने के लिए, हम Invoke() को अपने tflite::MicroInterpreter इंस्टेंस पर कॉल कर सकते हैं:

TfLiteStatus invoke_status = interpreter.Invoke();
if (invoke_status != kTfLiteOk) {
  TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed\n");
}

हम रिटर्न वैल्यू यानी TfLiteStatus की जांच करके पता लगा सकते हैं कि रन सफल रहा या नहीं. common.h में बताई गई TfLiteStatus की संभावित वैल्यू, kTfLiteOk और kTfLiteError हैं.

इस कोड ने पुष्टि की है कि वैल्यू kTfLiteOk है. इसका मतलब है कि अनुमान सही तरीके से चला.

TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status);

13. आउटपुट पाना

इस मॉडल का आउटपुट टेंसर, tflite::MicroInterpreter पर output(0) को कॉल करके हासिल किया जा सकता है. इसमें 0 पहले और सिर्फ़ आउटपुट टेंसर को दिखाता है.

उदाहरण में, मॉडल का आउटपुट, 2D टेंसर में मौजूद एक फ़्लोटिंग पॉइंट वैल्यू है:

TfLiteTensor* output = interpreter.output(0);
TF_LITE_MICRO_EXPECT_EQ(2, output->dims->size);
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[0]);
TF_LITE_MICRO_EXPECT_EQ(1, input->dims->data[1]);
TF_LITE_MICRO_EXPECT_EQ(kTfLiteFloat32, output->type);

हम आउटपुट टेंसर से वैल्यू को सीधे पढ़ सकते हैं और पुष्टि कर सकते हैं कि यह वही है जो हम उम्मीद करते हैं:

// Obtain the output value from the tensor
float value = output->data.f[0];
// Check that the output value is within 0.05 of the expected value
TF_LITE_MICRO_EXPECT_NEAR(0., value, 0.05);

14. अनुमान फिर से चलाएं

बाकी कोड, अनुमान को कई बार और चलाते हैं. हर इंस्टेंस में, हम इनपुट टेंसर को एक वैल्यू असाइन करते हैं, इंटरप्रेटर को शुरू करते हैं, और आउटपुट टेंसर से नतीजे को पढ़ते हैं:

input->data.f[0] = 1.;
interpreter.Invoke();
value = output->data.f[0];
TF_LITE_MICRO_EXPECT_NEAR(0.841, value, 0.05);

input->data.f[0] = 3.;
interpreter.Invoke();
value = output->data.f[0];
TF_LITE_MICRO_EXPECT_NEAR(0.141, value, 0.05);

input->data.f[0] = 5.;
interpreter.Invoke();
value = output->data.f[0];
TF_LITE_MICRO_EXPECT_NEAR(-0.959, value, 0.05);