使用GoogleNet和AlexNet迁移学习ECG

今天的任务是依照这篇介绍的方法,使用GoogleNet和AlexNet迁移学习ECG。
Signal Classification with Wavelet Analysis and Convolutional Neural Networks


整个实现流程包括以下几步:

  1. 下载三个ECG Dataset;
  2. 整理数据集,包括降采样、截断、标签,存储到一个ECG_Data的structure里;
  3. Plot原始数据;
  4. 使用CWT,得到scalogram,作为该样本的输入特征图;
  5. 划分训练集和测试集;
  6. 使用GoogleNet进行训练;
  7. 使用AlexNet进行训练;

下载ECG Dataset

实验选用的数据集为以下三个:
The MIT-BIH Atrial Fibrillation Database
The MIT-BIH ST Change Database
The MIT-BIH Supraventricular Arrhythmia Database
由于网站提供的下载整个数据包的链接失效,所以使用wget工具来下载数据库,指令如下:

wget -r -np http://physionet.org/physiobank/database/afdb/
wget -r -np http://physionet.org/physiobank/database/stdb/
wget -r -np http://physionet.org/physiobank/database/svdb/

下载完成后,共得到23+28+78=129条记录,每个记录都包含双通道的心电信号。

整理数据集

  1. 使用WFDB工具箱中的rdsamp函数,新建一个id_list,数组内存储数据库的样本编号,按数组依次读取信号;
  2. 使用resample函数,将各个样本的采样率都降为128Hz;
  3. 直接截取信号的前65536个点(即512s信号);
  4. 分离信号的两个通道,存储在ECGData.data中,同时在ECGData.label中存储对应的病症标签,建立Data Structure,大小为(248, 65536)和(248, 1)。

stdb的第313-317,319-323文件只有一列数据。

经过整理后的ECGData Structure组成如下:
1-46:AF记录,共46条;
47-92:ST记录,共46条;
93-248,SV记录,共157条。

%% Load AFDB
start=1
flag={'AF'};
id_list=[04015,04043,04048,04126,04746,04908,04936,05091,05121,05261,06426,06453,06995,07162,07859,07879,07910,08215,08219,08378,08405,08434,08455];
for id = 1:23
    signal=rdsamp(['/database/afdb/', num2str(id_list(id), '%05d')]);
    resamp_signal=resample(signal, 128, 250);
    cutoff_signal=resamp_signal(1:65536, :);
    ECGData.Data(:,start)=cutoff_signal(1:65536,1);
    ECGData.Labels(start)=flag;
    ECGData.Data(:,start+1)=cutoff_signal(1:65536,2);
    ECGData.Labels(start+1)=flag;
    start=start+2;
    id
end

%% Load STDB
start=47
flag={'ST'};
% 313~317 319~323
id_list=[300,301,302,303,304,305,306,307,308,309,310,311,312,318,324,325,326,327];
for id = 1:18
    signal=rdsamp(['/database/stdb/', num2str(id_list(id))]);
    resamp_signal=resample(signal, 128, 360);
    cutoff_signal=resamp_signal(1:65536, :);
    ECGData.Data(:,start)=cutoff_signal(1:65536,1);
    ECGData.Labels(start)=flag;
    ECGData.Data(:,start+1)=cutoff_signal(1:65536,2);
    ECGData.Labels(start+1)=flag;
    start=start+2;
    id
end

id_list=[313,314,315,316,317,319,320,321,322,323];
for id = 1:10
    signal=rdsamp(['/database/stdb/', num2str(id_list(id))]);
    resamp_signal=resample(signal, 128, 360);
    cutoff_signal=resamp_signal(1:65536, :);
    ECGData.Data(:,start)=cutoff_signal(1:65536,1);
    ECGData.Labels(start)=flag;
    start=start+1;
    id
end

%% Load SVDB
start=93
flag={'SV'};
id_list=[800,801,802,803,804,805,806,807,808,809,810,811,812,820,821,822,823,824,825,826,827,828,829,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,879,880,881,882,883,884,885,886,887,888,889,890,891,892,893,894];
for id = 1:78
    signal=rdsamp(['/database/svdb/', num2str(id_list(id))]);
    resamp_signal=resample(signal, 128, 128);
    cutoff_signal=resamp_signal(1:65536, :);
    ECGData.Data(:,start)=cutoff_signal(1:65536,1);
    ECGData.Labels(start)=flag;
    ECGData.Data(:,start+1)=cutoff_signal(1:65536,2);
    ECGData.Labels(start+1)=flag;
    start=start+2;
    id
end

%% Rebuild
ECGData.Data=ECGData.Data';
ECGData.Labels=ECGData.Labels';

Plot原始数据

调用例程中的helperPlotReps()函数,看原始数据。很奇怪的是第三类问题好像采样率有些奇怪,但是找不到问题的原因。


原始信号1000点

特征提取与数据集划分

首先使用cwtfilterbank函数对原始信号进行CWT变换,得到的结果如图所示。


CWT_Result

然后使用helpCreateRGBfromTF()对整个数据集进行变换,并使用splitEachLabel进行训练集和测试集的分割,分割得到大小为199的训练集和大小为49的测试集,存储在ImageDatastore里。

helperCreateRGBfromTF(ECGData,parentDir,dataDir)
allImages = imageDatastore(fullfile(parentDir,dataDir),...
    'IncludeSubfolders',true,...
    'LabelSource','foldernames');

rng default
[imgsTrain,imgsValidation] = splitEachLabel(allImages,0.8,'randomized');
disp(['Number of training images: ',num2str(numel(imgsTrain.Files))]);
disp(['Number of validation images: ',num2str(numel(imgsValidation.Files))]);

使用GoogleNet进行训练

GoogleNet是使用ImageNet训练的对于1000分类的深层CNN网络,其结构如图所示,为了进行迁移学习,我们将最后四层修改为针对三分类问题的输出。

lgraph = removeLayers(lgraph,{'pool5-drop_7x7_s1','loss3-classifier','prob','output'});

numClasses = numel(categories(imgsTrain.Labels));
newLayers = [
    dropoutLayer(0.6,'Name','newDropout')
    fullyConnectedLayer(numClasses,'Name','fc','WeightLearnRateFactor',5,'BiasLearnRateFactor',5)
    softmaxLayer('Name','softmax')
    classificationLayer('Name','classoutput')];
lgraph = addLayers(lgraph,newLayers);

lgraph = connectLayers(lgraph,'pool5-7x7_s1','newDropout');
inputSize = net.Layers(1).InputSize;
googlenet

同时,设置GoogleNet训练的一些参数,开始训练,训练结果如图所示。

options = trainingOptions('sgdm',...
    'MiniBatchSize',15,...
    'MaxEpochs',20,...
    'InitialLearnRate',1e-4,...
    'ValidationData',imgsValidation,...
    'ValidationFrequency',10,...
    'ValidationPatience',Inf,...
    'Verbose',1,...
    'ExecutionEnvironment','cpu',...
    'Plots','training-progress');

rng default
trainedGN = trainNetwork(imgsTrain,lgraph,options);

trainedGN.Layers(end-2:end)
cNames = trainedGN.Layers(end).ClassNames
GoogleNet训练结果

result

使用GoogleNet训练的最终正确率为:71.429%
同时我们还观测了GoogleNet的激活函数、对于AF病症的激活函数以及最强的AF通道,如下图所示。


第一层Activations
AF Activations
strongest AF Channel

使用AlexNet进行训练

AlexNet共有25层,如下图所示。


AlexNet

针对本问题,我们修改了AlexNet的最后三层,同时改变图像的形状以匹配AlexNet的输入。

%% Load
alex=alexnet;
layers = alex.Layers

%% Modify AlexNet Network Parameters
layers(23) = fullyConnectedLayer(3);
layers(25) = classificationLayer;

%% Prepare RGB Data for AlexNet
inputSize = alex.Layers(1).InputSize;
augimgsTrain = augmentedImageDatastore(inputSize(1:2),imgsTrain);
augimgsValidation = augmentedImageDatastore(inputSize(1:2),imgsValidation);

同时,设置AlexNet训练的一些参数,开始训练,训练结果如图所示。


AlexNet训练结果

result

使用AlexNet训练的最终正确率为75.51%

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容