AIoT

TinyML(1) - Beginning TinyML with W5500-evb-pico

민윤홍 2024. 12. 23. 09:00
반응형

안녕하세요 민윤홍입니다.

24년 1분기, Wiznet 회사에 있던 당시, 회사 동료분이 TinyML 분야를 공부해보는거 어떻냐고 추천해주셨고, 책 한권 사서 열심히 들여다보면서 구현해보았던 기억이 있습니다.

당시 반도체 회사였던 Wiznet에서 잘 알지도 못하는 챗봇을 개발하면서 AI 엔지니어 직군으로 있어도 되는걸까? 라는 의문이 들던 무렵, 저를 그래도 조금 더 오래 이 회사를 다니게 해주던 원동력인 스킬이였습니다.

 

아래 포스팅들은 maker.wiznet.io라는 사이트에도 동일하게 게시되었으나, 번역만 하여 제 블로그에 정리하려고 합니다.

 

 

 

TensorFlow Lite와 W5500-EVB-Pico를 사용한 사인파 예측 및 LED 제어

 

프로젝트 설명

Generate data

이 프로젝트는 실시간으로 사인파를 예측하고 LED를 제어하는 데 초점을 맞추고 있습니다. 주요 목표는 TensorFlow를 사용해 사인파를 예측하는 모델을 개발하고, 이를 TensorFlow Lite 형식으로 양자화하여 메모리 사용량과 계산 비용을 줄이는 것입니다. 이 과정을 통해 모델의 효율성을 극대화하고 실제 하드웨어에서 실시간으로 실행할 수 있게 합니다.

프로젝트의 핵심 부분은 W5500-EVB-Pico 보드를 사용해 예측된 사인파 데이터를 기반으로 LED를 제어하는 것입니다. 이 보드는 TensorFlow Lite 모델을 실행하며, 실시간 데이터 처리와 사인파 패턴으로 LED를 점등하기 위한 계산 성능을 제공합니다. 이를 통해 복잡한 데이터 처리와 실시간 응답이 필요한 애플리케이션에 적합한 솔루션을 제공합니다.

 


이 그래프는 평가 데이터와 예측 데이터를 나타냅니다. 예측 그래프를 보면, 사인파 형태를 띠고 있는 것을 확인할 수 있습니다.


Convert to quantized model

# Convert the model to the TensorFlow Lite format with quantization
converter = tf.lite.TFLiteConverter.from_keras_model(model_2)
converter.optimizations = [tf.lite.Optimize.OPTIMIZE_FOR_SIZE]
tflite_model = converter.convert()

# Save the model to disk
open("sine_model_quantized.tflite", "wb").write(tflite_model)

# Linux
# Install xxd if it is not available
!apt-get -qq install xxd
# Save the file as a C source file
!xxd -i sine_model_quantized.tflite > sine_model_quantized.cc
# Print the source file
!cat sine_model_quantized.cc

기존의 TensorFlow 모델은 정규화된 데이터를 32비트 부동소수점 숫자로 표현하지만, TensorFlow Lite 모델은 정규화된 데이터를 8비트 정수로 표현합니다. 데이터 정규화 정확도를 낮추는 대신, 이론적으로 최대 4배의 속도개선이 이루어집니다.

 

Quantized result

unsigned char sine_model_quantized_tflite[] = {
  0x18, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x00, 0x00, 0x0e, 0x00,
  0x18, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00,
  0x0e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x00,
  0xb8, 0x05, 0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
  0x0b, 0x00, 0x00, 0x00, 0x90, 0x05, 0x00, 0x00, 0x7c, 0x05, 0x00, 0x00,
  0x24, 0x05, 0x00, 0x00, 0xd4, 0x04, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00,
  0x74, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
  0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
  0x54, 0xf6, 0xff, 0xff, 0x58, 0xf6, 0xff, 0xff, 0x5c, 0xf6, 0xff, 0xff,
  0x60, 0xf6, 0xff, 0xff, 0xc2, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,

...
...
  0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00,
  0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x03, 0x00, 0x00, 0x00
};
unsigned int sine_model_quantized_tflite_len = 2640;

양자화된 데이터입니다. 데이터는 8비트 정수로 sine_model_quantized_tflite 배열에 입력됩니다.

 

Summary of major C functions

void setup() {
  // Set up logging. Google style is to avoid globals or statics because of
  // lifetime uncertainty, but since this has a trivial destructor it's okay.
  // NOLINTNEXTLINE(runtime-global-variables)
  static tflite::MicroErrorReporter micro_error_reporter;
  error_reporter = &micro_error_reporter;

  // Map the model into a usable data structure. This doesn't involve any
  // copying or parsing, it's a very lightweight operation.
  model = tflite::GetModel(g_sine_model_data);
  if (model->version() != TFLITE_SCHEMA_VERSION) {
    TF_LITE_REPORT_ERROR(error_reporter,
                         "Model provided is schema version %d not equal "
                         "to supported version %d.",
                         model->version(), TFLITE_SCHEMA_VERSION);
    return;
  }

  // This pulls in all the operation implementations we need.
  // NOLINTNEXTLINE(runtime-global-variables)
  static tflite::ops::micro::AllOpsResolver resolver;

  // Build an interpreter to run the model with.
  static tflite::MicroInterpreter static_interpreter(
      model, resolver, tensor_arena, kTensorArenaSize, error_reporter);
  interpreter = &static_interpreter;

  // Allocate memory from the tensor_arena for the model's tensors.
  TfLiteStatus allocate_status = interpreter->AllocateTensors();
  if (allocate_status != kTfLiteOk) {
    TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
    return;
  }
void loop() {
  // Calculate an x value to feed into the model. We compare the current
  // inference_count to the number of inferences per cycle to determine
  // our position within the range of possible x values the model was
  // trained on, and use this to calculate a value.
  float position = static_cast<float>(inference_count) /
                   static_cast<float>(kInferencesPerCycle);
  float x_val = position * kXrange;

  // Place our calculated x value in the model's input tensor
  input->data.f[0] = x_val;

  // Run inference, and report any error
  TfLiteStatus invoke_status = interpreter->Invoke();
  if (invoke_status != kTfLiteOk) {
    TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed on x_val: %f\n",
                         static_cast<double>(x_val));
    return;
  }

W5500-EVB-PICO를 setup 함수와 loop 함수에서 설정합니다. 로깅을 설정하고, 모델을 로드한 후 인터프리터를 설정하고 메모리를 할당합니다. 이후 코드는 loop 함수에서 반복적으로 실행됩니다.

 

 

Create makefile

make -f {tensorflow git directory} Makefile sinWaves


binary output


Makefile를 통해 빌드할 때, 사인파의 x값과 y값이 출력되는 것을 볼 수 있습니다.

 

Build on Arduino

Arduino IDE에서 실행한 결과입니다.

 

Result

 

사인파와 유사한 형태로 잘 출력됩니다!

 

'AIoT' 카테고리의 다른 글

TinyML(3) - WakeWord Detection  (1) 2024.12.27
TinyML(2) - using low-sensitivity sensor to predict high-performance sensor  (0) 2024.12.24
W5X00-EVB-Pico with SSL/TLS  (0) 2024.12.19
L2P - LLM to Pico  (1) 2024.12.18