웨이블릿 분석 및 딥러닝을 사용하여 시계열 분류하기
이 예제에서는 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.md
와 ECGData.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
는 두 개의 필드, 즉 Data
와 Labels
를 갖는 구조체형 배열입니다. Data
필드는 각 행이 128Hz로 샘플링된 ECG 기록인 162×65536 행렬입니다. Labels
는 진단 레이블로 구성된 162×1 셀형 배열로, 레이블은 Data
의 각 행에 대응합니다. 세 진단 범주는 'ARR'
, 'CHF'
, 'NSR'
입니다.
각 범주의 전처리된 데이터를 저장하기 위해 먼저 tempdir
내부에 ECG 데이터 디렉터리 dataDir
을 생성합니다. 그런 다음 'data'
에 각 ECG 범주의 이름을 딴 3개의 서브디렉터리를 만듭니다. 헬퍼 함수 helperCreateECGDirectories
가 이 작업을 수행합니다. helperCreateECGDirectories
는 ECGData
, ECG 데이터 디렉터리의 이름, 부모 디렉터리의 이름을 입력 인수로 받습니다. tempdir
을 쓰기 권한이 있는 다른 디렉터리로 바꿀 수 있습니다. 이 예제의 마지막 부분에 있는 지원 함수 섹션에서 이 헬퍼 함수의 소스 코드를 확인할 수 있습니다.
parentDir = tempdir;
dataDir = "data";
helperCreateECGDirectories(ECGData,parentDir,dataDir)
각 ECG 범주의 대표를 플로팅합니다. 헬퍼 함수 helperPlotReps
가 이 작업을 수행합니다. helperPlotReps
는 ECGData
를 입력값으로 받습니다. 이 예제의 마지막 부분에 있는 지원 함수 섹션에서 이 헬퍼 함수의 소스 코드를 확인할 수 있습니다.
helperPlotReps(ECGData)
시간-주파수 표현 만들기
폴더를 만든 후 ECG 신호의 시간-주파수 표현을 만듭니다. 이러한 표현을 스케일로그램이라고 합니다. 스케일로그램은 신호의 CWT 계수의 절댓값입니다.
스케일로그램을 만들려면 CWT 필터 뱅크를 미리 계산합니다. CWT 필터 뱅크를 미리 계산하는 것은 동일한 파라미터를 사용하여 많은 신호의 CWT를 구할 때 권장되는 방법입니다.
스케일로그램을 만들기 전에 그중 하나를 검토합니다. 1000개 샘플을 갖는 신호에 대해 cwtfilterbank
를 사용하여 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
(Deep Learning Toolbox) 항목을 참조하십시오. 디폴트 확률은 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
(Deep Learning Toolbox) 함수를 사용하여 훈련 옵션을 지정할 수 있습니다. MiniBatchSize
를 15로, MaxEpochs
를 20으로, InitialLearnRate
를 0.0001로 설정합니다. Plots
를 training-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이 어떤 특징을 학습했는지 알아낼 수 있습니다. 자세한 내용은 컨벌루션 신경망의 활성화 시각화하기 (Deep Learning Toolbox) 항목과 컨벌루션 신경망의 특징 시각화하기 (Deep Learning Toolbox) 항목을 참조하십시오.
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
(Deep Learning Toolbox) 항목을 참조하십시오.
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 및 Deploy Signal Classifier Using Wavelets and Deep Learning on Raspberry Pi에서는 신호 분류를 위해 하드웨어에 코드를 배포하는 방법을 보여줍니다. GoogLeNet과 SqueezeNet은 ILSVRC(ImageNet Large-Scale Visual Recognition Challenge)[8]에서 사용되는 ImageNet 데이터베이스[10]의 서브셋에서 사전 훈련된 모델입니다. ImageNet 모음에는 물고기, 새, 가전 제품, 진균류와 같은 실제 사물의 영상이 포함되어 있습니다. 스케일로그램은 이러한 실제 사물들의 클래스에 속하지 않습니다. GoogLeNet 아키텍처와 SqueezeNet 아키텍처에 맞추기 위해 스케일로그램은 데이터 축소 과정도 거쳤습니다. 서로 다른 클래스의 스케일로그램을 구분하기 위해 사전 훈련된 CNN을 미세 조정하는 대신 원래의 스케일로그램 차원에서 CNN을 처음부터 훈련시킬 수도 있습니다.
참고 문헌
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.
Engin, M. "ECG beat classification using neuro-fuzzy network." Pattern Recognition Letters. Vol. 25, Number 15, 2004, pp.1715–1722.
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.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.
Li, T., and M. Zhou. "ECG classification using wavelet packet entropy and random forests." Entropy. Vol. 18, Number 8, 2016, p.285.
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.
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)
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.
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.
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
helperPlotReps는 ECGData
에 있는 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
helperCreateRGBfromTF는 cwtfilterbank
를 사용하여 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
참고 항목
cwtfilterbank
| imagePretrainedNetwork
(Deep Learning Toolbox) | trainnet
(Deep Learning Toolbox) | trainingOptions
(Deep Learning Toolbox) | imageDatastore
| augmentedImageDatastore
(Deep Learning Toolbox)