Main Content

웨이블릿 분석 및 딥러닝을 사용하여 시계열 분류하기

이 예제에서는 CWT(연속 웨이블릿 변환) 및 심층 CNN(컨벌루션 신경망)을 사용하여 사람의 ECG(심전도) 신호를 분류하는 방법을 보여줍니다.

처음부터 심층 CNN을 훈련하려면 계산량이 많이 필요하고 다량의 훈련 데이터가 필요합니다. 충분한 양의 훈련 데이터를 사용할 수 없고 실제에 가까운 새로운 훈련 표본을 합성하기 어려운 다양한 응용 사례가 존재합니다. 그러한 경우 개념적으로 유사한 작업을 위해 대규모 데이터 세트에 대해 훈련된 기존 신경망을 활용하는 것이 바람직합니다. 이같이 기존 신경망을 활용하는 것을 전이 학습이라고 합니다. 이 예제에서는 영상 인식을 위해 사전 훈련된 두 개의 심층 CNN인 GoogLeNet과 SqueezeNet을 조정하여 시간-주파수 표현을 기반으로 ECG 파형을 분류합니다.

원래 GoogLeNet 및 SqueezeNet은 영상을 1000개의 범주로 분류하도록 설계된 심층 CNN입니다. 여기서는 CNN의 신경망 아키텍처를 재사용하여 시계열 데이터의 CWT에서 얻은 영상을 기반으로 ECG 신호를 분류합니다. 이 예제에 사용된 데이터는 PhysioNet에서 공개적으로 사용 가능합니다.

데이터 설명

이 예제에서는 심장 부정맥(ARR: arrhythmia)이 있는 사람, 울혈성 심부전(CHF: congestive heart failure)이 있는 사람, 정상 동율동(NSR: normal sinus rhythms)을 가진 사람의 세 그룹에서 얻은 ECG 데이터를 사용합니다. 그리고 3개의 PhysioNet 데이터베이스에서 총 162개의 ECG 기록을 사용합니다. 그 데이터베이스는 MIT-BIH Arrhythmia Database [3][7],MIT-BIH Normal Sinus Rhythm Database [3], The BIDMC Congestive Heart Failure Database [1][3]입니다. 더 구체적으로는 부정맥이 있는 사람의 기록 96개, 울혈성 심부전이 있는 사람의 기록 30개, 정상 동율동을 가진 사람의 기록 36개를 사용합니다. 목표는 ARR, CHF, NSR을 구분하도록 분류기를 훈련시키는 것입니다.

데이터 다운로드하기

첫 번째 단계는 GitHub® 리포지토리에서 데이터를 다운로드하는 것입니다. 웹사이트에서 데이터를 다운로드하려면 Code를 클릭하고 Download ZIP을 선택합니다. physionet_ECG_data-main.zip 파일을 쓰기 권한이 있는 폴더에 저장합니다. 이 예제의 지침에서는 MATLAB®의 임시 디렉터리인 tempdir에 파일을 다운로드했다고 가정합니다. tempdir이 아닌 다른 폴더에 데이터를 다운로드하도록 선택할 경우, 데이터 압축 풀기 및 불러오기에 대한 다음 지침을 그에 맞게 수정하여 수행하십시오.

GitHub에서 데이터를 다운로드한 후 임시 디렉터리에서 파일의 압축을 풉니다.

unzip(fullfile(tempdir,"physionet_ECG_data-main.zip"),tempdir)

압축을 풀면 임시 디렉터리에 폴더 physionet-ECG_data-main이 생성됩니다. 이 폴더에는 텍스트 파일 README.mdECGData.zip이 있습니다. ECGData.zip 파일에는 다음이 들어 있습니다.

  • ECGData.mat

  • Modified_physionet_data.txt

  • License.txt

ECGData.mat에는 이 예제에 사용되는 데이터가 들어 있습니다. 텍스트 파일 Modified_physionet_data.txt는 PhysioNet의 복사 정책 때문에 필요하며, 데이터에 대한 출처 표시와 각 ECG 기록에 적용된 전처리 단계에 대한 설명을 제공합니다.

physionet-ECG_data-main에서 ECGData.zip의 압축을 풉니다. 데이터 파일을 MATLAB 작업 공간으로 불러옵니다.

unzip(fullfile(tempdir,"physionet_ECG_data-main","ECGData.zip"), ...
    fullfile(tempdir,"physionet_ECG_data-main"))
load(fullfile(tempdir,"physionet_ECG_data-main","ECGData.mat"))

ECGData는 두 개의 필드, 즉 DataLabels를 갖는 구조체형 배열입니다. Data 필드는 각 행이 128Hz로 샘플링된 ECG 기록인 162×65536 행렬입니다. Labels는 진단 레이블로 구성된 162×1 셀형 배열로, 레이블은 Data의 각 행에 대응합니다. 세 진단 범주는 'ARR', 'CHF', 'NSR'입니다.

각 범주의 전처리된 데이터를 저장하기 위해 먼저 tempdir 내부에 ECG 데이터 디렉터리 dataDir을 생성합니다. 그런 다음 'data'에 각 ECG 범주의 이름을 딴 3개의 서브디렉터리를 만듭니다. 헬퍼 함수 helperCreateECGDirectories가 이 작업을 수행합니다. helperCreateECGDirectoriesECGData, ECG 데이터 디렉터리의 이름, 부모 디렉터리의 이름을 입력 인수로 받습니다. tempdir을 쓰기 권한이 있는 다른 디렉터리로 바꿀 수 있습니다. 이 예제의 마지막 부분에 있는 지원 함수 섹션에서 이 헬퍼 함수의 소스 코드를 확인할 수 있습니다.

parentDir = tempdir;
dataDir = "data";
helperCreateECGDirectories(ECGData,parentDir,dataDir)

각 ECG 범주의 대표를 플로팅합니다. 헬퍼 함수 helperPlotReps가 이 작업을 수행합니다. helperPlotRepsECGData를 입력값으로 받습니다. 이 예제의 마지막 부분에 있는 지원 함수 섹션에서 이 헬퍼 함수의 소스 코드를 확인할 수 있습니다.

helperPlotReps(ECGData)

시간-주파수 표현 만들기

폴더를 만든 후 ECG 신호의 시간-주파수 표현을 만듭니다. 이러한 표현을 스케일로그램이라고 합니다. 스케일로그램은 신호의 CWT 계수의 절댓값입니다.

스케일로그램을 만들려면 CWT 필터 뱅크를 미리 계산합니다. CWT 필터 뱅크를 미리 계산하는 것은 동일한 파라미터를 사용하여 많은 신호의 CWT를 구할 때 권장되는 방법입니다.

스케일로그램을 만들기 전에 그중 하나를 검토합니다. 1000개 샘플을 갖는 신호에 대해 cwtfilterbank (Wavelet Toolbox)를 사용하여 CWT 필터 뱅크를 만듭니다. 그 필터 뱅크를 사용하여 신호의 처음 1000개 샘플의 CWT를 얻고 계수에서 스케일로그램을 구합니다.

Fs = 128;
fb = cwtfilterbank(SignalLength=1000, ...
    SamplingFrequency=Fs, ...
    VoicesPerOctave=12);
sig = ECGData.Data(1,1:1000);
[cfs,frq] = wt(fb,sig);
t = (0:999)/Fs;
figure
pcolor(t,frq,abs(cfs))
set(gca,"yscale","log")
shading interp
axis tight
title("Scalogram")
xlabel("Time (s)")
ylabel("Frequency (Hz)")

헬퍼 함수 helperCreateRGBfromTF를 사용하여 스케일로그램을 RGB 영상으로 만들고 dataDir의 적절한 서브디렉터리에 씁니다. 이 헬퍼 함수의 소스 코드는 이 예제의 마지막 부분에 있는 지원 함수 섹션에 있습니다. GoogLeNet 아키텍처와 호환되도록 각 RGB 영상은 224×224×3 크기의 배열입니다.

helperCreateRGBfromTF(ECGData,parentDir,dataDir)

훈련 데이터와 검증 데이터로 나누기

스케일로그램 영상을 영상 데이터저장소로 불러옵니다. imageDatastore 함수는 폴더 이름을 기준으로 영상에 자동으로 레이블을 지정하고 데이터를 ImageDatastore 객체로 저장합니다. 영상 데이터저장소를 사용하면 메모리에 담을 수 없는 데이터를 포함하여 다량의 영상 데이터를 저장할 수 있고 CNN 훈련 중에 영상 배치를 효율적으로 읽어 들일 수 있습니다.

allImages = imageDatastore(fullfile(parentDir,dataDir), ...
    "IncludeSubfolders",true, ...
    "LabelSource","foldernames");

무작위로 영상을 두 그룹으로 나눕니다. 하나는 훈련용이고 다른 하나는 검증용입니다. 영상의 80%를 훈련용으로 사용하고 나머지를 검증용으로 사용합니다.

[imgsTrain,imgsValidation] = splitEachLabel(allImages,0.8,"randomized");
disp("Number of training images: "+num2str(numel(imgsTrain.Files)))
Number of training images: 130
disp("Number of validation images: "+num2str(numel(imgsValidation.Files)))
Number of validation images: 32

GoogLeNet

불러오기

사전 훈련된 GoogLeNet 신경망을 불러옵니다. Deep Learning Toolbox™ Model for GoogLeNet Network 지원 패키지가 설치되어 있지 않은 경우, 필요한 지원 패키지로 연결되는 애드온 탐색기 링크가 제공됩니다. 지원 패키지를 설치하려면 링크를 클릭한 다음 설치를 클릭하십시오.

net = imagePretrainedNetwork("googlenet");

신경망에서 계층 그래프를 추출하고 표시합니다.

numberOfLayers = numel(net.Layers);
figure("Units","normalized","Position",[0.1 0.1 0.8 0.8])
plot(net)
title("GoogLeNet Layer Graph: "+num2str(numberOfLayers)+" Layers")

신경망의 Layers 속성의 첫 번째 요소를 검사합니다. GoogLeNet에 224×224×3 크기의 RGB 영상이 필요함을 확인합니다.

net.Layers(1)
ans = 
  ImageInputLayer with properties:

                      Name: 'data'
                 InputSize: [224 224 3]
        SplitComplexInputs: 0

   Hyperparameters
          DataAugmentation: 'none'
             Normalization: 'zerocenter'
    NormalizationDimension: 'auto'
                      Mean: [224×224×3 single]

GoogLeNet 신경망 파라미터 수정하기

신경망 아키텍처의 각 계층은 필터로 간주될 수 있습니다. 앞쪽 계층은 블롭, 가장자리, 색 등 영상의 보다 일반적인 특징을 식별합니다. 뒤에 오는 계층은 범주를 구별하기 위해 보다 구체적인 특징에 중점을 둡니다. GoogLeNet은 영상을 1,000가지 사물 범주로 분류하도록 사전 훈련되었습니다. ECG 분류 문제에 맞게 GoogLeNet을 다시 훈련시켜야 합니다.

신경망의 마지막 4개 계층을 검사합니다.

net.Layers(end-3:end)
ans = 
  4×1 Layer array with layers:

     1   'pool5-7x7_s1'        2-D Global Average Pooling   2-D global average pooling
     2   'pool5-drop_7x7_s1'   Dropout                      40% dropout
     3   'loss3-classifier'    Fully Connected              1000 fully connected layer
     4   'prob'                Softmax                      softmax

과적합을 방지하기 위해 드롭아웃 계층이 사용됩니다. 드롭아웃 계층은 주어진 확률에 따라 입력 요소를 무작위로 0으로 설정합니다. 자세한 내용은 dropoutLayer 항목을 참조하십시오. 디폴트 확률은 0.5입니다. 신경망의 마지막 드롭아웃 계층 pool5-drop_7x7_s1을 확률 0.6의 드롭아웃 계층으로 교체합니다.

newDropoutLayer = dropoutLayer(0.6,"Name","new_Dropout");
net = replaceLayer(net,"pool5-drop_7x7_s1",newDropoutLayer);

신경망의 컨벌루션 계층은 영상 특징을 추출합니다. 그런 다음 GoogLeNet의 마지막 학습 가능한 계층인 loss3-classifier에는 신경망이 추출한 특징을 클래스 확률로 조합하는 방법에 대한 정보를 포함시킵니다. GoogLeNet이 RGB 영상을 분류하도록 다시 훈련시키려면, 이 계층을 해당 데이터에 적합한 계층으로 교체합니다.

완전 연결 계층 loss3-classifier를 필터의 개수가 클래스 개수와 같은 새로운 완전 연결 계층으로 교체합니다. 전이된 계층보다 새로운 계층에서 더 빠르게 학습할 수 있도록 하려면 완전 연결 계층의 학습률 인자 값을 높이십시오.

numClasses = numel(categories(imgsTrain.Labels));
newConnectedLayer = fullyConnectedLayer(numClasses,"Name","new_fc", ...
    "WeightLearnRateFactor",5,"BiasLearnRateFactor",5);
net = replaceLayer(net,"loss3-classifier",newConnectedLayer);

마지막 5개의 계층을 검사합니다. 드롭아웃 계층, 컨벌루션 계층, 완전 연결 계층이 교체되었는지 확인합니다.

net.Layers(end-3:end)
ans = 
  4×1 Layer array with layers:

     1   'pool5-7x7_s1'   2-D Global Average Pooling   2-D global average pooling
     2   'new_Dropout'    Dropout                      60% dropout
     3   'new_fc'         Fully Connected              3 fully connected layer
     4   'prob'           Softmax                      softmax

훈련 옵션을 설정하고 GoogLeNet 훈련시키기

신경망 훈련에는 손실 함수를 최소화하는 반복 수행이 필요합니다. 손실 함수를 최소화하기 위해 경사하강법 알고리즘이 사용됩니다. 각 반복에서 손실 함수의 기울기가 계산되고 경사하강법 알고리즘의 가중치가 업데이트됩니다.

다양한 옵션을 설정하여 훈련을 조정할 수 있습니다. InitialLearnRate는 손실 함수에 대한 음의 기울기 방향으로 초기 스텝 크기를 지정합니다. MiniBatchSize는 각 반복에 사용할 훈련 세트의 서브셋 크기를 지정합니다. Epoch 1회는 훈련 알고리즘이 전체 훈련 세트를 완전히 한 번 통과하는 것을 의미합니다. MaxEpochs는 훈련에 사용할 최대 Epoch 횟수를 지정합니다. 올바른 Epoch 횟수를 선택하는 일은 간단하지 않습니다. Epoch의 횟수를 줄이면 모델을 과소적합하는 효과가 있고 Epoch의 횟수를 늘리면 과적합이 발생합니다.

trainingOptions 함수를 사용하여 훈련 옵션을 지정할 수 있습니다. MiniBatchSize를 15로, MaxEpochs를 20으로, InitialLearnRate를 0.0001로 설정합니다. Plotstraining-progress로 설정하여 훈련 진행 상황을 시각화합니다. 모멘텀을 사용한 확률적 경사하강법 최적화 함수를 사용합니다. 기본적으로, 사용 가능한 GPU가 있으면 GPU에서 훈련시킵니다. GPU를 사용하려면 Parallel Computing Toolbox™가 필요합니다. 지원되는 GPU를 보려면 GPU 연산 요구 사항 (Parallel Computing Toolbox) 항목을 참조하십시오.

options = trainingOptions("sgdm", ...
    MiniBatchSize=15, ...
    MaxEpochs=20, ...
    InitialLearnRate=1e-4, ...
    ValidationData=imgsValidation, ...
    ValidationFrequency=10, ...
    Verbose=true, ...
    Plots="training-progress", ...
    Metrics="accuracy");

신경망을 훈련시킵니다. 훈련 과정은 일반적으로 데스크탑 CPU에서 1~5분 정도 걸립니다. GPU를 사용할 수 있으면 실행 시간이 더 빨라집니다. 실행 중에 훈련 정보가 명령 창에 표시됩니다. 결과에는 검증 데이터에 대한 Epoch 횟수, 반복 횟수, 경과 시간, 미니 배치 정확도, 검증 정확도, 손실 함수 값이 포함됩니다.

trainedGN = trainnet(imgsTrain,net,"crossentropy",options);
    Iteration    Epoch    TimeElapsed    LearnRate    TrainingLoss    ValidationLoss    TrainingAccuracy    ValidationAccuracy
    _________    _____    ___________    _________    ____________    ______________    ________________    __________________
            0        0       00:00:07       0.0001                            1.3444                                    46.875
            1        1       00:00:07       0.0001          1.7438                                    40                      
           10        2       00:00:37       0.0001          1.7555            1.1047                  40                  62.5
           20        3       00:01:03       0.0001         0.75169           0.68252              66.667                 68.75
           30        4       00:01:27       0.0001         0.74739           0.52126              73.333                78.125
           40        5       00:01:50       0.0001         0.49647           0.43025                  80                84.375
           50        7       00:02:13       0.0001         0.27949           0.36374              93.333                  87.5
           60        8       00:02:33       0.0001         0.15129           0.36825              93.333                84.375
           70        9       00:02:50       0.0001         0.15792           0.29109                 100                  87.5
           80       10       00:03:07       0.0001          0.3697           0.30388              93.333                90.625
           90       12       00:03:28       0.0001           0.159           0.25558                 100                90.625
          100       13       00:03:47       0.0001         0.02107           0.25558                 100                90.625
          110       14       00:04:06       0.0001         0.17743            0.2531              93.333                90.625
          120       15       00:04:27       0.0001        0.086914           0.23932                 100                90.625
          130       17       00:04:48       0.0001         0.13208           0.24259              93.333                90.625
          140       18       00:05:12       0.0001        0.025648           0.20339                 100                 93.75
          150       19       00:05:36       0.0001         0.17878           0.19556              93.333                 93.75
          160       20       00:06:01       0.0001        0.050998           0.21189                 100                 93.75
Training stopped: Max epochs completed

GoogLeNet 정확도 평가하기

검증 데이터를 사용하여 신경망을 평가합니다.

classNames = categories(imgsTrain.Labels);
scores = minibatchpredict(trainedGN,imgsValidation);
YPred = scores2label(scores,classNames);
accuracy = mean(YPred==imgsValidation.Labels);
disp("GoogLeNet Accuracy: "+num2str(100*accuracy)+"%")
GoogLeNet Accuracy: 93.75%

정확도는 훈련 시각화 Figure에 보고된 검증 정확도와 동일합니다. 스케일로그램은 훈련 모음과 검증 모음으로 분할되었습니다. 이 두 모음은 GoogLeNet 훈련에 모두 사용되었습니다. 훈련 결과를 평가하는 이상적인 방법은 신경망이 인식한 적이 없는 데이터를 분류하도록 하는 것입니다. 훈련 데이터, 검증 데이터, 테스트 데이터로 나눌 만큼 데이터 양이 충분하지 않으므로 여기서는 계산된 검증 정확도를 신경망 정확도로 간주합니다.

GoogLeNet 활성화 결과 탐색하기

CNN의 각 계층은 입력 영상에 대한 응답, 즉 활성화 결과를 생성합니다. 그러나 CNN 내에서 영상 특징 추출에 적합한 계층은 몇 개 되지 않습니다. 훈련된 신경망의 처음 5개 계층을 검사합니다.

trainedGN.Layers(1:5)
ans = 
  5×1 Layer array with layers:

     1   'data'             Image Input                   224×224×3 images with 'zerocenter' normalization
     2   'conv1-7x7_s2'     2-D Convolution               64 7×7×3 convolutions with stride [2  2] and padding [3  3  3  3]
     3   'conv1-relu_7x7'   ReLU                          ReLU
     4   'pool1-3x3_s2'     2-D Max Pooling               3×3 max pooling with stride [2  2] and padding [0  1  0  1]
     5   'pool1-norm1'      Cross Channel Normalization   cross channel normalization with 5 channels per element

신경망 시작 부분에 있는 계층은 가장자리 및 블롭과 같은 기본 영상 특징을 캡처합니다. 이를 확인하기 위해 첫 번째 컨벌루션 계층의 신경망 필터 가중치를 시각화합니다. 첫 번째 계층에는 64개의 개별 가중치 세트가 있습니다.

wghts = trainedGN.Layers(2).Weights;
wghts = rescale(wghts);
wghts = imresize(wghts,8);
figure
I = imtile(wghts,GridSize=[8 8]);
imshow(I)
title("First Convolutional Layer Weights")

활성화 결과를 살펴보고 원본 영상과 활성화 영역을 비교해 보면 GoogLeNet이 어떤 특징을 학습했는지 알아낼 수 있습니다. 자세한 내용은 컨벌루션 신경망의 활성화 시각화하기 항목과 컨벌루션 신경망의 특징 시각화하기 항목을 참조하십시오.

ARR 클래스의 영상에서 컨벌루션 계층의 어느 영역이 활성화되었는지 확인합니다. 원본 영상의 대응하는 영역과 비교합니다. 컨벌루션 신경망의 각 계층은 여러 개의 2차원 배열로 이루어져 있습니다. 이러한 2차원 배열을 채널이라고 합니다. 영상을 신경망에 통과시킨 후 첫 번째 컨벌루션 계층 conv1-7x7_s2의 출력 활성화 결과를 살펴봅니다.

convLayer = "conv1-7x7_s2";

imgClass = "ARR";
imgName = "ARR_10.jpg";
imarr = imread(fullfile(parentDir,dataDir,imgClass,imgName));

trainingFeaturesARR = predict(trainedGN,single(imarr),Outputs=convLayer);
sz = size(trainingFeaturesARR);
trainingFeaturesARR = reshape(trainingFeaturesARR,[sz(1) sz(2) 1 sz(3)]);
figure
I = imtile(rescale(trainingFeaturesARR),GridSize=[8 8]);
imshow(I)
title(imgClass+" Activations")

이 영상에 대한 가장 강한 채널을 찾습니다. 가장 강한 채널을 원본 영상과 비교합니다.

imgSize = size(imarr);
imgSize = imgSize(1:2);
[~,maxValueIndex] = max(max(max(trainingFeaturesARR)));
arrMax = trainingFeaturesARR(:,:,:,maxValueIndex);
arrMax = rescale(arrMax);
arrMax = imresize(arrMax,imgSize);
figure
I = imtile({imarr,arrMax});
imshow(I)
title("Strongest "+imgClass+" Channel: "+num2str(maxValueIndex))

SqueezeNet

SqueezeNet은 아키텍처가 227×227×3 크기의 영상을 지원하는 심층 CNN입니다. GoogLeNet의 영상 차원과 다르더라도 SqueezeNet 차원에서 새 RGB 영상을 생성할 필요는 없습니다. 원본 RGB 영상을 사용할 수 있습니다.

불러오기

사전 훈련된 SqueezeNet 신경망을 불러옵니다. Deep Learning Toolbox™ Model for SqueezeNet Network 지원 패키지가 설치되어 있지 않은 경우, 필요한 지원 패키지로 연결되는 애드온 탐색기 링크가 제공됩니다. 지원 패키지를 설치하려면 링크를 클릭한 다음 설치를 클릭하십시오.

netsqz = imagePretrainedNetwork("squeezenet");

신경망에서 계층 그래프를 추출합니다. SqueezeNet의 계층 수가 GoogLeNet보다 적은지 확인합니다. 또한 SqueezeNet이 227×227×3 크기의 영상에 맞게 구성되었는지 확인합니다.

disp("Number of Layers: "+num2str(numel(netsqz.Layers)))
Number of Layers: 68
netsqz.Layers(1)
ans = 
  ImageInputLayer with properties:

                      Name: 'data'
                 InputSize: [227 227 3]
        SplitComplexInputs: 0

   Hyperparameters
          DataAugmentation: 'none'
             Normalization: 'zerocenter'
    NormalizationDimension: 'auto'
                      Mean: [1×1×3 single]

SqueezeNet 신경망 파라미터 수정하기

새 영상을 분류하도록 SqueezeNet을 다시 훈련시키려면 GoogLeNet에 대해 수행한 것과 유사하게 변경합니다.

마지막 5개의 신경망 계층을 검사합니다.

netsqz.Layers(end-4:end)
ans = 
  5×1 Layer array with layers:

     1   'conv10'         2-D Convolution              1000 1×1×512 convolutions with stride [1  1] and padding [0  0  0  0]
     2   'relu_conv10'    ReLU                         ReLU
     3   'pool10'         2-D Global Average Pooling   2-D global average pooling
     4   'prob'           Softmax                      softmax
     5   'prob_flatten'   Flatten                      Flatten

신경망의 마지막 드롭아웃 계층을 확률 0.6의 드롭아웃 계층으로 교체합니다.

tmpLayer = netsqz.Layers(end-5);
newDropoutLayer = dropoutLayer(0.6,"Name","new_dropout");
netsqz = replaceLayer(netsqz,tmpLayer.Name,newDropoutLayer);

GoogLeNet과 달리 SqueezeNet의 마지막 학습 가능한 계층은 1×1 컨벌루션 계층(conv10)이며 완전 연결 계층이 아닙니다. 이 계층을 필터의 개수가 클래스 개수와 같은 새로운 컨벌루션 계층으로 교체합니다. GoogLeNet에서 한 것처럼, 새로운 계층의 학습률 인자를 높입니다.

numClasses = numel(categories(imgsTrain.Labels));
tmpLayer = netsqz.Layers(end-4);
newLearnableLayer = convolution2dLayer(1,numClasses, ...
        "Name","new_conv", ...
        "WeightLearnRateFactor",10, ...
        "BiasLearnRateFactor",10);
netsqz = replaceLayer(netsqz,tmpLayer.Name,newLearnableLayer);

신경망의 마지막 5개 계층을 검사합니다. 드롭아웃 계층과 컨벌루션 계층이 변경되었는지 확인합니다.

netsqz.Layers(end-4:end)
ans = 
  5×1 Layer array with layers:

     1   'new_conv'       2-D Convolution              3 1×1 convolutions with stride [1  1] and padding [0  0  0  0]
     2   'relu_conv10'    ReLU                         ReLU
     3   'pool10'         2-D Global Average Pooling   2-D global average pooling
     4   'prob'           Softmax                      softmax
     5   'prob_flatten'   Flatten                      Flatten

SqueezeNet을 위한 RGB 데이터 준비하기

RGB 영상의 차원은 GoogLeNet 아키텍처에 적합합니다. SqueezeNet 아키텍처에 맞도록 기존 RGB 영상의 크기를 자동으로 조정하는 증대 영상 데이터저장소를 생성합니다. 자세한 내용은 augmentedImageDatastore 항목을 참조하십시오.

augimgsTrain = augmentedImageDatastore([227 227],imgsTrain);
augimgsValidation = augmentedImageDatastore([227 227],imgsValidation);

훈련 옵션을 설정하고 SqueezeNet 훈련시키기

SqueezeNet과 함께 사용할 새 훈련 옵션 세트를 만들고 신경망을 훈련시킵니다.

ilr = 3e-4;
miniBatchSize = 10;
maxEpochs = 15;
valFreq = floor(numel(augimgsTrain.Files)/miniBatchSize);
opts = trainingOptions("sgdm", ...
    MiniBatchSize=miniBatchSize, ...
    MaxEpochs=maxEpochs, ...
    InitialLearnRate=ilr, ...
    ValidationData=augimgsValidation, ...
    ValidationFrequency=valFreq, ...
    Verbose=1, ...
    Plots="training-progress", ...
    Metrics="accuracy");

trainedSN = trainnet(augimgsTrain,netsqz,"crossentropy",opts);
    Iteration    Epoch    TimeElapsed    LearnRate    TrainingLoss    ValidationLoss    TrainingAccuracy    ValidationAccuracy
    _________    _____    ___________    _________    ____________    ______________    ________________    __________________
            0        0       00:00:01       0.0003                            2.7267                                        25
            1        1       00:00:01       0.0003          3.0502                                    30                      
           13        1       00:00:05       0.0003         0.93269           0.81717                  60                78.125
           26        2       00:00:10       0.0003          0.6929           0.62475                  70                 81.25
           39        3       00:00:15       0.0003         0.55664           0.54038                  70                84.375
           50        4       00:00:19       0.0003        0.075004                                   100                      
           52        4       00:00:20       0.0003         0.27402           0.51236                  90                 81.25
           65        5       00:00:25       0.0003         0.15558           0.72845                  90                 81.25
           78        6       00:00:27       0.0003         0.29531           0.58038                  90                 81.25
           91        7       00:00:30       0.0003        0.053372           0.53191                 100                 81.25
          100        8       00:00:32       0.0003        0.019003                                   100                      
          104        8       00:00:33       0.0003         0.23475           0.22768                  80                 93.75
          117        9       00:00:37       0.0003        0.059982           0.15849                 100                96.875
          130       10       00:00:43       0.0003        0.038729           0.20219                 100                90.625
          143       11       00:00:46       0.0003       0.0059834           0.26095                 100                90.625
          150       12       00:00:47       0.0003        0.002025                                   100                      
          156       12       00:00:48       0.0003       0.0067973           0.16036                 100                96.875
          169       13       00:00:50       0.0003       0.0086382           0.17935                 100                96.875
          182       14       00:00:52       0.0003       0.0020118           0.21593                 100                 93.75
          195       15       00:00:54       0.0003       0.0061499           0.22566                 100                 93.75
Training stopped: Max epochs completed

SqueezeNet 정확도 평가하기

검증 데이터를 사용하여 신경망을 평가합니다.

scores = minibatchpredict(trainedSN,augimgsValidation);
YPred = scores2label(scores,classNames);
accuracy = mean(YPred==imgsValidation.Labels);
disp("SqueezeNet Accuracy: "+num2str(100*accuracy)+"%")
SqueezeNet Accuracy: 96.875%

결론

이 예제에서는 사전 훈련된 CNN GoogLeNet 및 SqueezeNet을 활용하여 ECG 신호의 세 가지 클래스를 분류하기 위해 전이 학습 및 연속 웨이블릿 분석을 사용하는 방법을 보여줍니다. ECG 신호의 웨이블릿 기반 시간-주파수 표현은 스케일로그램을 생성하는 데 사용됩니다. 스케일로그램의 RGB 영상이 생성됩니다. 영상은 두 심층 CNN을 미세 조정하는 데 사용됩니다. 서로 다른 신경망 계층의 활성화 결과도 살펴보았습니다.

이 예제에서는 사전 훈련된 CNN 모델을 사용하여, 신호를 분류하는 데 사용 가능한 하나의 워크플로를 보여줍니다. 다른 워크플로도 가능합니다. Deploy Signal Classifier on NVIDIA Jetson Using Wavelet Analysis and Deep Learning (Wavelet Toolbox)Deploy Signal Classifier Using Wavelets and Deep Learning on Raspberry Pi (Wavelet Toolbox)에서는 신호 분류를 위해 하드웨어에 코드를 배포하는 방법을 보여줍니다. GoogLeNet과 SqueezeNet은 ILSVRC(ImageNet Large-Scale Visual Recognition Challenge)[8]에서 사용되는 ImageNet 데이터베이스[10]의 서브셋에서 사전 훈련된 모델입니다. ImageNet 모음에는 물고기, 새, 가전 제품, 진균류와 같은 실제 사물의 영상이 포함되어 있습니다. 스케일로그램은 이러한 실제 사물들의 클래스에 속하지 않습니다. GoogLeNet 아키텍처와 SqueezeNet 아키텍처에 맞추기 위해 스케일로그램은 데이터 축소 과정도 거쳤습니다. 서로 다른 클래스의 스케일로그램을 구분하기 위해 사전 훈련된 CNN을 미세 조정하는 대신 원래의 스케일로그램 차원에서 CNN을 처음부터 훈련시킬 수도 있습니다.

참고 문헌

  1. Baim, D. S., W. S. Colucci, E. S. Monrad, H. S. Smith, R. F. Wright, A. Lanoue, D. F. Gauthier, B. J. Ransil, W. Grossman, and E. Braunwald. "Survival of patients with severe congestive heart failure treated with oral milrinone." Journal of the American College of Cardiology. Vol. 7, Number 3, 1986, pp. 661–670.

  2. Engin, M. "ECG beat classification using neuro-fuzzy network." Pattern Recognition Letters. Vol. 25, Number 15, 2004, pp.1715–1722.

  3. Goldberger A. L., L. A. N. Amaral, L. Glass, J. M. Hausdorff, P. Ch. Ivanov, R. G. Mark, J. E. Mietus, G. B. Moody, C.-K. Peng, and H. E. Stanley. "PhysioBank, PhysioToolkit,and PhysioNet: Components of a New Research Resource for Complex Physiologic Signals." Circulation. Vol. 101, Number 23: e215–e220. [Circulation Electronic Pages; http://circ.ahajournals.org/content/101/23/e215.full]; 2000 (June 13). doi: 10.1161/01.CIR.101.23.e215.

  4. Leonarduzzi, R. F., G. Schlotthauer, and M. E. Torres. "Wavelet leader based multifractal analysis of heart rate variability during myocardial ischaemia." In Engineering in Medicine and Biology Society (EMBC), Annual International Conference of the IEEE, 110–113. Buenos Aires, Argentina: IEEE, 2010.

  5. Li, T., and M. Zhou. "ECG classification using wavelet packet entropy and random forests." Entropy. Vol. 18, Number 8, 2016, p.285.

  6. Maharaj, E. A., and A. M. Alonso. "Discriminant analysis of multivariate time series: Application to diagnosis based on ECG signals." Computational Statistics and Data Analysis. Vol. 70, 2014, pp. 67–87.

  7. Moody, G. B., and R. G. Mark. "The impact of the MIT-BIH Arrhythmia Database." IEEE Engineering in Medicine and Biology Magazine. Vol. 20. Number 3, May-June 2001, pp. 45–50. (PMID: 11446209)

  8. Russakovsky, O., J. Deng, and H. Su et al. "ImageNet Large Scale Visual Recognition Challenge." International Journal of Computer Vision. Vol. 115, Number 3, 2015, pp. 211–252.

  9. Zhao, Q., and L. Zhang. "ECG feature extraction and classification using wavelet transform and support vector machines." In IEEE International Conference on Neural Networks and Brain, 1089–1092. Beijing, China: IEEE, 2005.

  10. ImageNet. http://www.image-net.org

지원 함수

helperCreateECGDataDirectories는 부모 디렉터리 내부에 데이터 디렉터리를 생성한 후 그 데이터 디렉터리 내부에 3개의 서브디렉터리를 생성합니다. 서브디렉터리는 ECGData에 있는 ECG 신호의 각 클래스의 이름을 따서 명명됩니다.

function helperCreateECGDirectories(ECGData,parentFolder,dataFolder)
% This function is only intended to support the ECGAndDeepLearningExample.
% It may change or be removed in a future release.

rootFolder = parentFolder;
localFolder = dataFolder;
mkdir(fullfile(rootFolder,localFolder))

folderLabels = unique(ECGData.Labels);
for i = 1:numel(folderLabels)
    mkdir(fullfile(rootFolder,localFolder,char(folderLabels(i))));
end
end

helperPlotRepsECGData에 있는 ECG 신호에 대한 각 클래스를 대표하는 처음 1000개 샘플을 플로팅합니다.

function helperPlotReps(ECGData)
% This function is only intended to support the ECGAndDeepLearningExample.
% It may change or be removed in a future release.

folderLabels = unique(ECGData.Labels);

for k=1:3
    ecgType = folderLabels{k};
    ind = find(ismember(ECGData.Labels,ecgType));
    subplot(3,1,k)
    plot(ECGData.Data(ind(1),1:1000));
    grid on
    title(ecgType)
end
end

helperCreateRGBfromTFcwtfilterbank (Wavelet Toolbox)를 사용하여 ECG 신호의 연속 웨이블릿 변환을 구하고 웨이블릿 계수에서 스케일로그램을 생성합니다. 이 헬퍼 함수는 스케일로그램의 크기를 조정하고 이를 디스크에 jpeg 영상으로 씁니다.

function helperCreateRGBfromTF(ECGData,parentFolder,childFolder)
% This function is only intended to support the ECGAndDeepLearningExample.
% It may change or be removed in a future release.

imageRoot = fullfile(parentFolder,childFolder);

data = ECGData.Data;
labels = ECGData.Labels;

[~,signalLength] = size(data);

fb = cwtfilterbank(SignalLength=signalLength,VoicesPerOctave=12);
r = size(data,1);

for ii = 1:r
    cfs = abs(fb.wt(data(ii,:)));
    im = ind2rgb(round(rescale(cfs,0,255)),jet(128));
    
    imgLoc = fullfile(imageRoot,char(labels(ii)));
    imFileName = char(labels(ii))+"_"+num2str(ii)+".jpg";
    imwrite(imresize(im,[224 224]),fullfile(imgLoc,imFileName));
end
end

참고 항목

(Wavelet Toolbox) | | | | | |

관련 항목