이 문서에서는 모델을 학습시키고 다음을 사용하여 추론을 실행하는 방법을 설명합니다. 마이크로컨트롤러에 따라 다릅니다.
Hello World 예시
이 Hello World 이 예시는 LiteRT 사용의 절대적인 기본 사항을 보여주도록 고안되었습니다. 마이크로컨트롤러용이죠. 사인 함수를 복제하는 모델을 학습시키고 실행합니다. 즉, 숫자 하나를 입력으로 취하고 sine 값. 배포 시 마이크로컨트롤러의 경우, 그 예측은 LED를 깜박이거나 애니메이션을 적용할 수 있습니다.
엔드 투 엔드 워크플로에는 다음 단계가 포함됩니다.
- 모델 학습 (Python): 학습, 변환할 Python 파일입니다. 기기 내 사용을 위해 모델을 최적화할 수 있습니다.
- 추론 실행 (C++ 17): 다음을 실행하는 엔드 투 엔드 단위 테스트입니다. C++ 라이브러리를 사용하여 모델에서 추론을 실행합니다.
지원되는 기기 받기
사용할 예시 애플리케이션은 다음 기기에서 테스트되었습니다.
- Arduino Nano 33 BLE Sense (Arduino IDE 사용)
- SparkFun Edge (직접 빌드 출처에서 가져옴)
- STM32F746 Discovery 키트 (MBed 사용)
- Adafruit EdgeBadge (Arduino 사용) IDE)
- 마이크로컨트롤러용 Adafruit LiteRT 키트 (Arduino IDE 사용)
- Adafruit Circuit Playground Bluefruit (Arduino IDE 사용)
- Espressif ESP32-DevKitC (ESP IDF 사용)
- Espressif ESP-EYE (ESP IDF 사용)
지원되는 플랫폼 자세히 알아보기: 마이크로컨트롤러용 LiteRT입니다.
모델 학습
사용 train.py 사인파 인식용 Hello World 모델 학습용
실행: 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
:
다음 섹션에서는 이 예의
evaluate_test.cc
님,
LiteRT를 사용하여 추론을 실행하는 방법을 보여주는 단위 테스트
마이크로컨트롤러. 모델을 로드하고 추론을 여러 번 실행합니다.
1. 라이브러리 헤더 포함
LiteRT for Microcontrollers 라이브러리를 사용하려면 다음 헤더 파일:
#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
드림 LiteRT 스키마 포함FlatBuffer
모델 파일 형식입니다.version.h
드림 LiteRT 스키마의 버전 관리 정보를 제공합니다.
2. 모델 헤더 포함
LiteRT for Microcontrollers 인터프리터는 모델이 다음과 같을 것으로 예상합니다.
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 = µ_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. 입력 형태 검증
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
는 LiteRT 중 하나에 관한 참조입니다.
데이터 유형이며
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
를 확인하여 실행이
있습니다. 다음에 정의된 TfLiteStatus
의 가능한 값
common.h
,
kTfLiteOk
및 kTfLiteError
입니다.
다음 코드는 값이 kTfLiteOk
라고 어설션합니다. 즉, 추론이 다음과 같음을 의미합니다.
실행할 수 있습니다
TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, invoke_status);
13. 출력 얻기
모델의 출력 텐서는 다음에서 output(0)
를 호출하여 가져올 수 있습니다.
tflite::MicroInterpreter
, 여기서 0
는 첫 번째 (유일한) 출력을 나타냅니다.
텐서가 포함됩니다.
이 예시에서 모델의 출력은 2차원 텐서 내에서:
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);