माइक्रोकंट्रोलर के साथ शुरुआत करें

यह दस्तावेज़ बताता है कि एक मॉडल को कैसे प्रशिक्षित किया जाए और एक माइक्रोकंट्रोलर का उपयोग करके अनुमान कैसे चलाया जाए।

हैलो वर्ल्ड उदाहरण

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

एंड-टू-एंड वर्कफ़्लो में निम्नलिखित चरण शामिल हैं:

  1. एक मॉडल को प्रशिक्षित करें (पायथन में): डिवाइस पर उपयोग के लिए एक मॉडल को प्रशिक्षित करने, परिवर्तित करने और अनुकूलित करने के लिए एक पायथन फ़ाइल।
  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 , यूनिट परीक्षण के माध्यम से चलते हैं जो दर्शाता है कि माइक्रोकंट्रोलर्स के लिए टेन्सरफ्लो लाइट का उपयोग करके अनुमान कैसे चलाया जाए। यह मॉडल को लोड करता है और कई बार अनुमान चलाता है।

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. मॉडल हेडर शामिल करें

माइक्रोकंट्रोलर्स दुभाषिया के लिए टेन्सरफ्लो लाइट को उम्मीद है कि मॉडल को C++ सरणी के रूप में प्रदान किया जाएगा। मॉडल को model.h और model.cc फ़ाइलों में परिभाषित किया गया है। शीर्षलेख निम्नलिखित पंक्ति के साथ शामिल है:

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

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

यूनिट परीक्षण बनाने के लिए, हम निम्नलिखित पंक्ति को शामिल करके माइक्रोकंट्रोलर्स यूनिट परीक्षण ढांचे के लिए टेन्सरफ्लो लाइट को शामिल करते हैं:

#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::ErrorReporter पॉइंटर को tflite::MicroErrorReporter इंस्टेंस के पॉइंटर का उपयोग करके बनाया जाता है:

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. स्मृति आवंटित करें

हमें इनपुट, आउटपुट और मध्यवर्ती सरणियों के लिए एक निश्चित मात्रा में मेमोरी पूर्व-आवंटित करने की आवश्यकता है। इसे tensor_arena_size आकार की uint8_t सरणी के रूप में प्रदान किया गया है:

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. इनपुट आकार मान्य करें

MicroInterpreter इंस्टेंस हमें .input(0) पर कॉल करके मॉडल के इनपुट टेंसर के लिए एक पॉइंटर प्रदान कर सकता है, जहां 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. मॉडल चलाएँ

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

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