일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 코테 문제
- 영상처리
- DP문제
- bfs문제
- dfs
- tflite
- DP
- BFS
- 다이나믹프로그래밍
- 알고리즘
- 삼성역테
- 포스코 ai 교육
- sort
- 그리디
- 컴퓨팅사고
- 자료구조
- 임베디드 딥러닝
- TensorFlow Lite
- dfs문제
- 코테
- 코딩테스트
- 삼성코테
- 삼성역량테스트
- 삼성코딩테스트
- 포스코 교육
- MCU 딥러닝
- 포스코 AI교육
- tinyml
- 초소형머신러닝
- 딥러닝
- Today
- Total
코딩뚠뚠
[머신러닝 공부] Tiny ML -9 / 음성인식 어플리케이션-2 본문
Chapter9. 음성인식(호출어 감지) 어플리케이션 만들기
"
저번챕터에 이어 TinyML을 좀더 생활에 밀접한 부분에 사용해본다.
"
목차 :
- TinyML을 이용한 호출어감지는 왜 필요할까? -> 이전장 참고
- 만들고자 하는 시스템 -> 이전장 참고
- 어플리케이션 아키텍처 -> 이전장 참고
- 테스트코드 분석 -> 이전장 참고
- 호출어 듣기
- MCU에 배포하기
이전장은 아래 링크에..
5. 호출어 듣기
아래부터의 코드는 main_function.cc에 해당한다.
main_functions.cc는 setup()과 loop() 를 정의한다.
코드분석 :
> 사용하고자 하는 Op 를 나열
> 전역변수를 설정
> setup() 함수에서 모델을 로드, 인터프리터 설정, op 추가, 텐서 할당
void setup() {
tflite::InitializeTarget();
// 로깅 설정
static tflite::MicroErrorReporter micro_error_reporter;
error_reporter = µ_error_reporter;
// 모델을 사용 가능한 데이터 구조에 매핑한다.
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.",
model->version(), TFLITE_SCHEMA_VERSION);
return;
}
// 필요한 Op 로드
static tflite::MicroMutableOpResolver<4> micro_op_resolver(error_reporter);
if (micro_op_resolver.AddDepthwiseConv2D() != kTfLiteOk) {
return;
}
if (micro_op_resolver.AddFullyConnected() != kTfLiteOk) {
return;
}
if (micro_op_resolver.AddSoftmax() != kTfLiteOk) {
return;
}
if (micro_op_resolver.AddReshape() != kTfLiteOk) {
return;
}
// 인터프리터 빌드
static tflite::MicroInterpreter static_interpreter(
model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter);
interpreter = &static_interpreter;
// 모델 텐서에 tensor_arena의 메모리를 할당
TfLiteStatus allocate_status = interpreter->AllocateTensors();
if (allocate_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
return;
}
> 입력 텐서의 유형과 형태가 올바른지 확인
> FeatureProvider를 인스턴스화 하여 입력텐서를 가리킨다.
// 입력 제공하는 마이크 에서 오디오 스펙트로그램에 접근할 준비를 한다.
static FeatureProvider static_feature_provider(kFeatureElementCount, feature_buffer);
feature_provider = &static_feature_provider;
> RecognizeCommands 인스턴스를 생성하고 previous_time 변수를 초기화한다.
static RecognizeCommands static_recognizer(error_reporter);
recognizer = &static_recognizer;
previous_time = 0;
}
- 이렇게 setup 함수가 끝났다.
> loop 함수의 시작이다. 이 함수는 무한정 반복동작한다.
> 루프 내에서 특징추출기를 사용하여 스펙트로그램을 생성한다.
void loop() {
// 현 시간의 스펙트로그램을 가져온다.
const int32_t current_time = LatestAudioTimestamp();
int how_many_new_slices = 0;
TfLiteStatus feature_status = feature_provider->PopulateFeatureData(
error_reporter, previous_time, current_time, &how_many_new_slices);
if (feature_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "Feature generation failed");
return;
}
previous_time = current_time;
// 마지막 시간 이후 새로운 오디오 샘플 수신되지 않은 경우 return (네트워크 모델 실행X)
if (how_many_new_slices == 0) {
return;
}
- 마지막 반복 이후 새로운 데이터가 없는 경우 더이상 추론을 실행하지 않는다.
> 입력을 받으면 인터프리터를 호출하고 성공했는지 확인한다.
TfLiteStatus invoke_status = interpreter->Invoke();
if (invoke_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed");
return;
}
- 모델의 출력 텐서가 각 카테고리의 확률로 채워졌다.
> 확률 해석을 위해 Recognize Commands 인스턴스를 사용한다.
// 출력텐서의 포인터를 얻는다.
TfLiteTensor* output = interpreter->output(0);
// 출력 기반으로 명령이 인식됐는지 확인한다.
const char* found_command = nullptr;
uint8_t score = 0;
bool is_new_command = false;
TfLiteStatus process_status = recognizer->ProcessLatestResults(
output, current_time, &found_command, &score, &is_new_command);
if (process_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "RecognizeCommands::ProcessLatestResults() failed");
return;
}
> RespondToCommmand 를 호출하여 호출어가 감지되면 사용자에게 알리는 기능을 수행한다.
RespondToCommand(error_reporter, current_time, found_command, score,
is_new_command);
}
// loop 함수 종료
이렇게 분석해본 setup(), loop() 함수는 main.cc에 정의된 main() 함수에 의해 호출된다.
test 어플리케이션 실행 :
> 우선 아래 명령을 사용해 빌드한다
make -f tensorflow/lite/micro/tools/make/Makefile micro_speech_test
> 완료되면 아래 명령으로 예제를 실행할 수 있다.
//ubuntu 20.04 기준
./tensorflow/lite/micro/tools/make/gen/linux_x86_64_default/bin/micro_speech_test
> 실행결과
6. MCU에 배포하기
이전에도 사용했던 sparkfun edge MCU를 사용한다.
sparkfun edge 에는 마이크가 내장되어있고 출력을 나타낼 수 있는 4 개의 LED가 있어 응답을 간편히 볼 수 있다.
yes : 노란색 LED
no : 빨간색 LED
알 수 없는 명령 : 초록색 LED
코드분석 :
github - tensorflow 에서 micro 를 분리하기 전의 repo에서 코드를 참고한다. (micro 폴더의 history - 2021/7/29 버전)
> am_devices_led_array_init 함수를 Apollo3 SDK에서 호출하여 출력모드로 설정한다.
void RespondToCommand(tflite::ErrorReporter* error_reporter,
int32_t current_time, const char* found_command,
uint8_t score, bool is_new_command) {
static bool is_initialized = false;
if (!is_initialized) {
// Setup LED's as outputs
#ifdef AM_BSP_NUM_LEDS
am_devices_led_array_init(am_bsp_psLEDs, AM_BSP_NUM_LEDS);
am_devices_led_array_out(am_bsp_psLEDs, AM_BSP_NUM_LEDS, 0x00000000);
#endif
is_initialized = true;
}
> am_devices_led_toggle을 통해 추론이 수행될 때마다 파란색 LED를 토글한다.
am_devices_led_toggle(am_bsp_psLEDs, AM_BSP_LED_BLUE);
> 모든 LED를 off로 초기화하고, 결과에 따라 LED가 켜지도록 선언한다.
am_devices_led_off(am_bsp_psLEDs, AM_BSP_LED_RED);
am_devices_led_off(am_bsp_psLEDs, AM_BSP_LED_YELLOW);
am_devices_led_off(am_bsp_psLEDs, AM_BSP_LED_GREEN);
> 명령에 따라 켜질 LED를 설정한다.
if (is_new_command) {
TF_LITE_REPORT_ERROR(error_reporter, "Heard %s (%d) @%dms", found_command,
score, current_time);
if (found_command[0] == 'y') {
am_devices_led_on(am_bsp_psLEDs, AM_BSP_LED_YELLOW);
}
if (found_command[0] == 'n') {
am_devices_led_on(am_bsp_psLEDs, AM_BSP_LED_RED);
}
if (found_command[0] == 'u') {
am_devices_led_on(am_bsp_psLEDs, AM_BSP_LED_GREEN);
}
}
- is_new_command는 RespondToCommand()가 새로운 명령으로 호출된 경우에만 true.
- 새 명령을 듣지 않는다면 LED는 상태 유지한다.
- 새 명령이라면 am_devices_led_on() 함수를 이용하여 적절한 LED를 켠다.
실행 :
> 바이너리 빌드
make -f tensorflow/lite/micro/tools/make/Makefile TARGET=sparkfun_edge micro_speech_bin
> 바이너리 파일 위치
tensorflow/tensorflow/lite/micro/tools/make/gen/sparkfun_edge_cortex-m4_micro/bin/micro_speech.bin
> 개발에 사용할 수 있는 더미 암호화 키 설정
cp tensorflow/lite/micro/tools/make/downloads/AmbiqSuite-Rel2.2.0/tools/ \
apollo3_scripts/keys_info0.py \
tensorflow/lite/micro/tools/make/downloads/AmbiqSuite-Rel2.2.0/tools/ \
apollo3_scripts/keys_info.py
> 바이너리 생성
python3 tensorflow/lite/micro/tools/make/downloads/AmbiqSuite-Rel2.2.0/ \
tools/apollo3_scripts/create_cust_image_blob.py --bin tensorflow/lite/micro/ \
tools/make/gen/sparkfun_edge_cortex-m4_micro/bin/micro_speech.bin \
--load-address 0xC000 --magic-num 0xCB -o main_nonsecure_ota --version 0x0
- main_nonsecure_ota.bin 파일이 생성되었다.
> 장치를 플래시 하는 데 사용할 수 있는 파일의 최종버전을 생성한다.
python3 tensorflow/lite/micro/tools/make/downloads/AmbiqSuite-Rel2.2.0/ \
tools/apollo3_scripts/create_cust_wireupdate_blob.py --load-address 0x20000 \
--bin main_nonsecure_ota.bin -i 6 -o main_nonsecure_wire --options 0x1
- main_nonsecure_wire_bin 파일이 생성되었다.
> 장치 연결을 확인 (리눅스)
ls /dev/tty*
> 장치 이름과 BAUD_RATE를 설정해주고 접근 권한을 부여해준다.
export DEVICENAME=/dev/ttyUSB0
export BAUD_RATE=921600
sudo chmod 666 /dev/ttyUSB0
> 보드 14번 버튼을 누른 채로 RST버튼을 눌렀다 떼어 RESET을 실행해준다.
> 14버튼을 유지한채로 아래 명령어를 실행해준다.
python3 tensorflow/lite/micro/tools/make/downloads/AmbiqSuite-Rel2.2.0/ \
ools/apollo3_scripts/uart_wired_update.py -b ${BAUD_RATE} ${DEVICENAME} \
-r 1 -f main_nonsecure_wire.bin -i 6
> 실제 동작 (기본 동작 - BLUE LED만 반짝인다)
> 실제동작 (음성 인식 - GREEN LED가 반짝인다)
다음장에서는 yes, no 이외의 호출어를 구분해내는 작업을 진행해보려 한다.
끝
'공부 > ML&DL' 카테고리의 다른 글
[머신러닝 공부] Tiny ML -11 / 음성인식 모델훈련하기 -2 (0) | 2022.02.07 |
---|---|
[머신러닝 공부] Tiny ML -10 / 음성인식 모델훈련하기 -1 (0) | 2022.02.02 |
[머신러닝 공부] Tiny ML -8 / 음성인식 어플리케이션-1 (0) | 2022.01.13 |
[머신러닝 공부] Tiny ML -7 / MCU에 배포하기 (0) | 2022.01.08 |
[머신러닝 공부] Tiny ML -6 / 어플리케이션 구축-2 (0) | 2021.12.21 |