Main Content

Raspberry Pi에 신호 분할 심층 신경망 배포하기

이 예제에서는 단시간 푸리에 변환과 양방향 장단기 기억(BiLSTM) 신경망을 사용하여 심전도(ECG) 신호를 파형 분할하는 워크플로를 자세히 설명합니다. 또한, 신호 분할에 사용되는 코드와 훈련된 BiLSTM 신경망을 생성하고 Raspberry Pi® 타깃(ARM® 기반 장치)에 배포하는 방법에 관한 정보도 제공합니다.

이 예제의 사전 훈련된 신경망은 딥러닝을 사용한 파형 분할 (Signal Processing Toolbox) 예제와 비슷합니다.

이 예제에서는 다음을 설명합니다.

  • 생성된 코드가 Raspberry Pi에 배포되어 실행되는 것을 MATLAB®에서 검증하는 PIL(Processor-in-the-Loop) 기반 워크플로

  • 독립형 실행 파일 생성

PIL 검증 과정은 독립형 실행 파일을 배포하기 전에 생성된 코드의 동작이 설계와 일치하는지 확인하는 설계 주기의 중요한 부분입니다.

심전도 데이터셋

이 예제에서는 공개적으로 사용 가능한 QT 데이터베이스의 심전도 신호를 사용합니다 [1] [2]. 이 데이터는 총 105명의 환자로부터 샘플 레이트 250Hz로 측정한 약 15분 분량의 레이블이 지정된 심전도 기록으로 구성되었습니다.

심전도 신호는 다음 심박 모폴로지로 나눌 수 있습니다 [3].

  • P파 — 심방 탈분극을 나타내는 QRS 복합파 이전의 작은 편향

  • QRS 복합파 — 심박의 최대 진폭 부분

  • T파 — 심실 재분극을 나타내는 QRS 복합파 이후의 작은 편향

심전도 파형의 이 영역을 분할하여 사람 심장의 전반적인 상태 및 이상 유무를 가늠하는 측정 기준을 마련할 수 있습니다.

선행 조건

지원되는 라이브러리 버전과 환경 변수 설정에 관한 정보는 Prerequisites for Deep Learning with MATLAB Coder (MATLAB Coder) 항목을 참조하십시오.

생성된 코드의 기능

생성된 실행 파일의 핵심 함수는 다음을 수행합니다.

  • 15,000개의 단정밀도 심전도 데이터 샘플을 입력값으로 사용합니다.

  • 신호에 대해 단시간 푸리에 변환을 계산합니다.

  • 출력값을 표준화 및 정규화합니다.

  • 사전 훈련된 BiLSTM 신경망을 사용하여 신호 영역에 레이블을 지정합니다.

  • 레이블이 있는 출력 파일을 생성합니다.

waveformSegmentation 함수

최상위 함수 또는 함수라고도 하는 진입점 함수는 코드 생성을 위해 정의하는 함수입니다. 코드 생성이 활성화된 함수를 호출하고 진입점 함수로부터 C/C++ 코드를 생성하는 진입점 함수를 정의해야 합니다. 진입점 함수 내의 모든 함수는 코드 생성을 지원해야 합니다.

이 예제에서는 waveformSegmentation이 진입점 함수입니다. 이 함수는 심전도 신호를 입력값으로 사용하고 예측을 위해 입력값을 훈련된 BiLSTM 신경망에 전달합니다. performPreprocessing 함수는 원시 신호를 전처리하고 단시간 푸리에 변환을 적용합니다. genClassifiedResults 함수는 전처리된 신호를 예측을 위해 신경망에 전달하고 분류 결과를 표시합니다.

type waveformSegmentation
function out = waveformSegmentation(in)
%#codegen
persistent net;

if isempty(net)
    net = coder.loadDeepLearningNetwork('trained-network-STFTBILSTM.mat', 'net');
end


preprocessedSignal = performPreprocessing(in);
out = cell(3,1);


for indx = 1:3
  out{indx,1} =  genClassifedResults(net.predict(preprocessedSignal{1,indx}));
end



end

Raspberry Pi에 대한 연결 생성하기

MATLAB Support Package for Raspberry Pi 함수 raspi를 사용하여 Raspberry Pi에 대한 연결을 생성합니다. 아래 코드를 다음과 같이 변경합니다.

  • 'raspiname'을 사용 중인 Raspberry Pi 이름으로 변경

  • 'pi'를 사용자 이름으로 변경

  • 'password'를 사용자 비밀번호로 변경

r = raspi('raspiname','pi','password');

이 예제에서는 코드와 설계의 검증을 위한 PIL 기반 워크플로를 살펴본 다음 독립형 실행 파일을 만들고 배포합니다. 선택적으로, 독립형 실행 파일을 직접 배포하려면 PIL 실행을 건너뛰고 독립형 실행 파일 만들기로 이동하면 됩니다.

PIL MEX 함수 생성하기

첫 번째 단계에서는 waveformSegmentation 함수용 MEX 함수를 생성하는 PIL 기반 워크플로를 알아봅니다.

정적 라이브러리를 위한 코드 생성 구성 객체 설정하기

정적 라이브러리를 위한 코드 구성 객체를 만들고 검증 모드를 'PIL'로 설정합니다. 타깃 언어를 'C++'로 설정합니다.

cfg = coder.config('lib','ecoder',true);
cfg.VerificationMode = 'PIL';
cfg.TargetLang = 'C++'; 

딥러닝 코드 생성을 위한 구성 객체 설정하기

coder.ARMNEONConfig 객체를 만듭니다. ARM Compute Library의 버전을 Raspberry Pi에 있는 버전으로 지정합니다. Raspberry Pi의 아키텍처를 지정합니다. (이 예제에서는 ARM Compute Library v19.05가 필요합니다.)

dlcfg = coder.DeepLearningConfig('arm-compute');
dlcfg.ArmComputeVersion = '19.05';
dlcfg.ArmArchitecture = 'armv7';

코드 생성 구성 객체의 DeepLearningConfig 속성을 딥러닝 구성 객체로 설정합니다. 코드 생성 시, MATLAB 소스 주석이 표시되도록 구성 객체를 설정합니다.

cfg.DeepLearningConfig = dlcfg;
cfg.MATLABSourceComments = 1;

Raspberry Pi를 위한 코드 생성 하드웨어 파라미터 구성하기

Raspberry Pi용 coder.Hardware 객체를 만들고 이를 코드 생성 구성 객체에 연결합니다.

hw = coder.hardware('Raspberry Pi');
cfg.Hardware = hw;

Raspberry Pi에 빌드 폴더를 지정합니다.

cfg.Hardware.BuildDir = '~/waveformSegmentation';

codegen 함수를 사용하여 소스 C++ 코드 생성하기

codegen 함수를 사용하여 C++ 코드를 생성합니다. MATLAB Support Package for Raspberry Pi Hardware와 함께 codegen을 사용하는 경우, 생성된 코드가 보드에 다운로드되어 컴파일됩니다. MATLAB과 Raspberry Pi에서 실행되는 생성된 코드 간의 통신을 위해 PIL MEX 함수가 생성됩니다.

Raspberry Pi에서 환경 변수 ARM_COMPUTELIBLD_LIBRARY_PATH를 설정해야 합니다. Prerequisites for Deep Learning with MATLAB Coder (MATLAB Coder)(MATLAB Coder) 항목을 참조하십시오.

codegen -config cfg waveformSegmentation -args {coder.typeof(single(ones(1,15000)),[1,15000],[0,0])} -report
### Target device has no native communication support. Checking connectivity configuration registrations...
 Deploying code. This may take a few minutes. 
### Target device has no native communication support. Checking connectivity configuration registrations...
### Connectivity configuration for function 'waveformSegmentation': 'Raspberry Pi'
Location of the generated elf : /home/pi/waveformSegmentation/MATLAB_ws/R2020b/C/Users/eshashah/OneDrive_-_MathWorks/Documents/MATLAB/Examples/deeplearning_shared-ex28372959/codegen/lib/waveformSegmentation/pil
Code generation successful: View report

Raspberry Pi에서 실행 프로그램 실행하기

MAT 파일 ecgsignal_test를 불러옵니다. 이 파일은 생성된 코드를 테스트할 수 있는 샘플 심전도 신호를 저장하고 있습니다.

테스트 신호에 대해 생성된 waveformSegmentation_pil MEX 함수를 실행합니다.

load ecgsignal_test.mat;
out = waveformSegmentation_pil(test);
### Starting application: 'codegen\lib\waveformSegmentation\pil\waveformSegmentation.elf'
    To terminate execution: clear waveformSegmentation_pil
### Launching application waveformSegmentation.elf...

예측된 레이블과 함께 신호를 표시합니다.

labels = categorical(out{1}(1,2000:3000));
msk = signalMask(labels);
plotsigroi(msk,test(1,2000:3000))
title('Predicted Labels')

PIL MEX 함수의 출력값을 확인한 후, waveformSegmentation 함수의 독립형 실행 파일을 만들 수 있습니다.

이어지는 부분에서는 MATLAB Coder 앱을 사용하여 독립형 실행 파일을 생성하고 Raspberry Pi에서 예측하기 위한 코드 내에 배포하는 코드 생성 워크플로를 보여줍니다.

MATLAB Coder 앱을 사용하여 독립형 실행 파일 만들기

MATLAB Coder 앱은 MATLAB® 코드로부터 C 코드나 C++ 코드를 생성합니다. 워크플로 기반의 사용자 인터페이스 단계에 따라 코드 생성 과정을 진행할 수 있습니다. 다음 단계에서는 MATLAB Coder 앱을 사용하는 간략한 워크플로를 설명합니다. 자세한 내용은 MATLAB Coder (MATLAB Coder) 항목과 Generate C Code by Using the MATLAB Coder App (MATLAB Coder) 항목을 참조하십시오.

진입점 함수 파일 선택하기

탭에서 툴스트립의 오른쪽 끝에 있는 아래쪽 화살표를 클릭하여 앱 갤러리를 확장합니다. 코드 생성 아래에 있는 MATLAB Coder를 클릭합니다. 앱에 Select Source Files 페이지가 열립니다. 진입점 함수 이름인 waveformSegmentation을 입력하거나 선택합니다.

Next를 클릭하여 Define Input Types 페이지로 이동합니다.

입력 유형 정의하기

1. Let me enter input or global types directly를 선택하고 입력값 in을 single형 (1x15000)으로 설정합니다.

2. Next를 클릭하여 Generate Code 단계로 이동합니다. ARM Compute Library를 사용한 코드 생성에서는 MEX 생성이 지원되지 않으므로 Check for Run-Time Issues 단계는 건너뜁니다.

코드 생성하기

1. 코드 생성 대화 상자에서 값을 설정합니다.

  • Build TypeExecutable (.exe)로 설정합니다.

  • LanguageC++로 설정합니다.

  • Hardware BoardRaspberry Pi로 설정합니다.

2. More Settings 버튼을 클릭합니다.

  • Custom Code 창에 있는 추가 소스 파일(Additional source files)에서 ecgsegmentation_main.cpp를 찾아서 선택합니다. C/C++ 메인 함수 작성에 대한 자세한 내용은 Structure of Generated Example C/C++ Main Function (MATLAB Coder) 항목을 참조하십시오.

  • Hardware 창에서 Raspberry Pi 보드의 usernamepassword를 설정합니다.

  • Deep Learning 창에서 Target libraryARM Compute로 설정합니다. ARM Compute Library 버전ARM Compute Architecture를 지정합니다.

3. 설정 창을 닫고 코드를 생성합니다.

4. Next를 클릭하여 Finish Workflow 페이지로 이동합니다.

생성된 실행 파일 디렉터리 가져오기

코드 생성이 완료된 후에는 Raspberry Pi에서 생성된 코드를 테스트할 수 있습니다. 첫 번째 단계로 입력 ECG 신호를 생성된 코드 디렉터리에 복사합니다. 디렉터리는 직접 찾거나 raspi.utils.getRemoteBuildDirectory API를 사용하여 찾을 수 있습니다. 이 함수는 codegen 함수를 사용하여 생성된 이진 파일의 디렉터리를 나열합니다. 이진 파일이 하나의 디렉터리에만 있다고 가정하고 다음을 입력합니다.

applicationDirPaths = ...

raspi.utils.getRemoteBuildDirectory('applicationName','waveformSegmentation');

targetDirPath = applicationDirPaths{1}.directory;

입력 파일을 Raspberry Pi에 복사하기

실행 프로그램을 실행하는 데 필요한 파일을 복사하려면 putFile을 사용합니다. 이 함수는 MATLAB Support Package for Raspberry Pi Hardware가 있어야 사용할 수 있습니다. input.csv 파일에는 배포된 코드를 테스트하는 데 사용되는 심전도 신호 샘플이 들어 있습니다.

r.putFile('input.csv',targetDirPath);

input = dlmread('input.csv');

Raspberry Pi에서 실행 프로그램 실행하기

MATLAB에서 Raspberry Pi에 있는 실행 프로그램을 실행하고 출력 파일을 MATLAB으로 가져옵니다. 입력 파일 이름을 실행 파일의 명령줄 인수로 전달해야 합니다.

exeName = 'waveformSegmentation.elf'; % Executable name

command = ['cd ' targetDirPath ';./' exeName];

system(r,command)

outputPath = strcat(targetDirPath,'/*.txt');

getFile(r,outputPath)

예측된 레이블과 함께 신호를 표시합니다. 출력값이 그림에 표시되어 있습니다.

load ecgsignal_test.mat;

labels = categorical(textread('out.txt','%s')');

msk = signalMask(labels(1,2000:3000));

plotsigroi(msk,test(1,2000:3000))

title('Predicted Labels')

참고 문헌

[1] McSharry, Patrick E., et al. "A dynamical model for generating synthetic electrocardiogram signals." IEEE® Transactions on Biomedical Engineering. Vol. 50, No. 3, 2003, pp. 289–294.

[2] Laguna, Pablo, Raimon Jané, Pere Caminal. "Automatic detection of wave boundaries in multilead ECG signals: Validation with the CSE database." Computers and Biomedical Research. Vol. 27, No. 1, 1994, pp. 45–60.

[3] Goldberger, Ary L., Luis A. N. Amaral, Leon Glass, Jeffery M. Hausdorff, Plamen Ch. Ivanov, Roger G. Mark, Joseph E. Mietus, George B. Moody, Chung-Kang Peng, H. Eugene Stanley. "PhysioBank, PhysioToolkit, and PhysioNet: Components of a New Research Resource for Complex Physiologic Signals." Circulation. Vol. 101, No. 23, 2000, pp. e215–e220. [Circulation Electronic Pages, http://circ.ahajournals.org/content/101/23/e215.full].

참고 항목

함수

관련 항목