GPU加速用于深度学习的标量图
这个例子展示了如何使用gpu加速标量图计算。将计算得到的标量图作为深度卷积神经网络(CNN)的输入特征,用于心电和语音数字分类。
使用GPU需要并行计算工具箱™。要查看支持哪些gpu,请参见金宝appGPU计算要求(并行计算工具箱).本例的音频部分要求audio Toolbox™使用音频数据存储和转换后的数据存储。
使用GPU计算标量图
在GPU上计算标量图最有效的方法是使用cwtfilterbank
.在GPU上计算标量图的步骤如下:
构造
cwtfilterbank
使用所需的属性设置。移动信号到GPU使用
gpuArray
.使用滤波器组
WT
连续小波变换(CWT)的计算方法。
第一次使用WT
方法,cwtfilterbank
在GPU上缓存小波滤波器。因此,当您使用相同的滤波器组和相同的数据类型获得多个信号的标度图时,可以节省大量的计算时间。下面演示推荐的工作流。例如,使用包含661,500个样本的吉他音乐样本。
[y,fs] = audioread(“guitartune.wav”);情节(y)网格在
由于大多数NVIDIA gpu在处理单精度数据时效率显著高于双精度数据,因此将信号转换为单精度。
Y =单(Y);
构造匹配信号长度和采样频率的滤波器组。对于深度学习,采样频率通常是不必要的,因此可以排除。
Fb = cwtfilterbank(“SignalLength”长度(y),“SamplingFrequency”fs);
最后将信号移动到GPU使用gpuArray
并计算数据的CWT。绘制结果的标量图。
[cfs,f] = fb.wt(gpuArray(y));T = 0:1/fs:(长度(y)*1/fs)-1/fs;显示亮度图像(t、f、abs (cfs))轴xyylabel (“赫兹”)包含(“秒”)
使用收集
将CWT系数和任何其他输出带回CPU。
CFS =收集(CFS);F =集合(F);
为了演示使用GPU获得的效率,请对相同信号在GPU和CPU上的CWT计算计时。这里的GPU计算时间是使用NVIDIA Titan V 7.0计算能力获得的。
ygpu = gpuArray(y);Fgpu = @()fb.wt(ygpu);Tgpu = gputimeit(fgpu)
Tgpu = 0.2658
在CPU上重复相同的测量,并检查GPU与CPU时间的比率,以查看计算时间的减少情况。
Fcpu = @()fb.wt(y);Tcpu = timeit(fcpu)
Tcpu = 3.7088
Tcpu / Tgpu
Ans = 13.9533
深度学习中的尺度图
CWT在深度学习中的一个常见应用是使用信号的标量图作为深度CNN的输入“图像”。这必然要求计算多个标度图,训练集、验证集和测试集中的每个信号一个标度图。虽然gpu通常用于加速深度网络中的训练和推理,但使用gpu来加速任何特征提取或数据预处理也很有益,这些特征提取或数据预处理需要使深度网络更加健壮。
为了说明这一点,下面一节将小波尺度图应用于人体心电图(ECG)分类。中处理的相同数据使用标量图基于小波分析和深度学习的时间序列分类.在该示例中,使用GoogLeNet和SqueezeNet的迁移学习将ECG波形分为三类之一。为了方便起见,这里重复对数据的描述以及如何获取数据。
心电数据描述和下载
心电图数据来自三组人:心律失常(ARR)、充血性心力衰竭(CHF)和窦性心律正常(NSR)的人。总共有162个ECG记录来自三个PhysioNet数据库:MIT-BIH心律失常数据库[2] [3],MIT-BIH正常窦性心律数据库[3]BIDMC充血性心力衰竭数据库[1][3]。更具体地说,来自心律失常患者的96次录音,来自充血性心力衰竭患者的30次录音,来自正常窦性心律患者的36次录音。目标是训练一个模型来区分ARR, CHF和NSR。
您可以从MathWorks中获取这些数据GitHub库.如需从网站下载数据,请单击代码
并选择下载ZIP
.保存文件physionet_ECG_data-main.zip
在您有写权限的文件夹中。本例的说明假设您已经将文件下载到临时目录,tempdir
,在MATLAB中。如果选择在不同的文件夹中下载数据,请修改解压缩和加载数据的后续说明tempdir
.
从GitHub下载数据后,在临时目录中解压缩文件。
解压缩(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记录的预处理步骤的描述。
解压缩ECGData.zip
在physionet-ECG_data-main
.将数据文件加载到MATLAB工作区中。
解压缩(fullfile (tempdir,“physionet_ECG_data-main”,“ECGData.zip”),...fullfile (tempdir“physionet_ECG_data-main”)加载(fullfile (tempdir“physionet_ECG_data-main”,“ECGData.mat”))
ECGData
是具有两个字段的结构数组:数据
而且标签
.的数据
field是一个162 × 65536的矩阵,其中每一行都是一个以128赫兹采样的ECG记录。标签
是一个162 × 1单元阵列的诊断标签,每行一个数据
.这三个诊断类别是:“加勒比海盗”
,瑞士法郎的
,“签约”
.使用helper函数,helperRandomSplit
,将数据分成训练集和验证集,其中80%的数据分配给训练集,20%分配给验证集。将ECG诊断标签转换为类别。
[trainData, validationData, trainLabels, validationLabels] = helperRandomSplit(80,ECGData);trainLabels = categorical(trainLabels);validationLabels = categorical(validationLabels);
有130条记录trainData
设置和32个记录验证数据
.根据设计,训练数据包含80.25%(130/162)的数据。回想一下,ARR类代表59.26%的数据(96/162),CHF类代表18.52% (30/162),NSR类代表22.22%(36/162)。检查每个类在训练集和测试集中的百分比。每个类别的百分比与数据集中的整体类别百分比一致。
Ctrain = countcats(trainLabels)./ nummel (trainLabels).*100
Ctrain =3×159.2308 18.4615 22.3077
Cvalid = countcats(validationLabels)./ nummel (validationLabels).*100
Cvalid =3×159.3750 18.7500 21.8750
带有深度CNN - ECG数据的标量图
GPU上的scalalogram计算
计算训练集和验证集的尺度图。集useGPU
来真正的
使用GPU和假
来计算CPU上的标量图。为了减轻大输入矩阵对CNN的影响,并创建更多的训练和验证示例,helperECGScalograms
将每个ECG波形分成四个不重叠的16384个样本片段,并为所有四个片段计算标量图。复制标签以匹配扩展的数据集。在这种情况下,获得所花费的计算时间的估计值。
frameLength = 16384;useGPU = true;抽搐;Xtrain = helperECGScalograms(trainData,frameLength,useGPU);
计算量图……处理了130个文件中的50个处理了130个文件中的100个…完成
T = toc;sprintf ('运行时间为%1.2f秒', T)
ans = '运行时间为4.22秒'
trainLabels = repelem(trainLabels,4);
使用Titan V GPU,在大约4.2秒内计算了502个标量图。设置useGPU
来假
并重复上述计算,演示了使用GPU获得的速度提升。在本例中,使用CPU需要33.3秒来计算标量图。GPU的计算速度快了7倍以上。
对验证数据重复相同的过程。
useGPU = true;Xvalid = helperECGScalograms(validationData,frameLength,useGPU);
计算标量... ...完成
validationLabels = repelem(validationLabels,4);
接下来设置一个深度CNN来处理训练集和验证集。这里使用的简单网络没有优化。这个CNN仅用于说明适用于内存中标量图的情况下的端到端工作流。
sz = size(Xtrain);specSize = sz(1:2);imageSize = [specSize 1];dropoutProb = 0.3;图层= [imageInputLayer(imageSize)卷积2dlayer (3,12,“填充”,“相同”maxPooling2dLayer(2,“步”20岁的,2)convolution2dLayer (3“填充”,“相同”maxPooling2dLayer(2,“步”32岁的,2)convolution2dLayer (3“填充”,“相同”) batchNormalizationLayer reluLayer dropoutLayer(dropoutProb) fullyConnectedLayer(3) softmaxLayer classificationLayer];
使用以下培训选项。
选项= trainingOptions(“个”,...“InitialLearnRate”1的军医,...“LearnRateDropPeriod”, 18岁,...“MiniBatchSize”, 20岁,...“MaxEpochs”25岁的...“L2Regularization”1 e 1,...“阴谋”,“训练进步”,...“详细”假的,...“洗牌”,“every-epoch”,...“ExecutionEnvironment”,“汽车”,...“ValidationData”, {Xvalid, validationLabels});
训练网络并测量验证误差。
trainNetwork (Xtrain、trainLabels层,选择);
尽管这里使用的简单CNN没有经过优化,但验证精度始终在80%到90%的范围内。中所示的更强大和优化的SqueezeNet所实现的验证精度与此相当基于小波分析和深度学习的时间序列分类的例子。此外,这是一种更有效的使用标量图的方法,因为在那个示例中,标量图必须被重新缩放为与SqueezeNet兼容的RGB图像,以适当的图像格式保存到磁盘,然后将其馈送到深度网络使用imageDatastore
.
语音数字识别- GPU计算使用转换数据存储
本节将展示如何在转换后的数据存储工作流中使用GPU加速标量图计算。
数据
克隆或下载免费语音数字数据集(FSDD),可在https://github.com/Jakobovski/free-spoken-digit-dataset。FSDD是一个开放的数据集,这意味着它可以随着时间的推移而增长。本例使用了2019年1月29日提交的版本,该版本由4位说话者提供的2000个英语数字0到9的录音组成。在这个版本中,有两个人的母语是美式英语,另两个人的母语是非英语,带有比利时、法国和德国口音。采样频率为8000hz。
有关此数据集的其他方法,包括小波散射,请参见基于小波散射和深度学习的语音数字识别.
使用audioDatastore
管理数据访问,确保录音随机分为训练集和测试集。设置位置
属性到您的计算机上的FSDD录音文件夹的位置,例如:
pathToRecordingsFolder =“/ home / user / free-spoken-digit-dataset /录音”;location = pathToRecordingsFolder;
点audioDatastore
去那个地方。
ads = audioDatastore(location);
辅助函数helpergenLabels
从FSDD文件创建标签的分类数组。列出类和每个类中的示例数量。
ads. labels = helpergenLabels(广告);总结(ads.Labels)
0 200 1 200 2 200 3 200 4 200 5 200 6 200 7 200 8 200 9 200
改变了数据存储
首先将FSDD分为训练集和测试集。将80%的数据分配给训练集,并保留20%的数据给测试集。
rng默认的;广告= shuffle(广告);[adsTrain,adsTest] = splitEachLabel(ads,0.8);countEachLabel (adsTrain)
ans =10×2表标签计数_____ _____ 0 160 1 160 2 160 3 160 4 160 5 160 6 160 7 160 8 160 9 160
接下来,使用助手函数为训练和测试数据创建CWT过滤器组和转换后的数据存储,helperDigitScalogram
.转换后的数据存储将每个记录转换为长度为8192的信号,在GPU上计算标量图,并将数据收集回CPU。
reset(gpuDevice(1)) fb = cwtfilterbank(“SignalLength”, 8192);adsSCTrain = transform(adsTrain,@(音频,信息)helperDigitScalogram(音频,信息,fb),“IncludeInfo”,真正的);adsSCTest = transform(adsTest,@(音频,信息)helperdigitscalalogram(音频,信息,fb),“IncludeInfo”,真正的);
CNN深处
构造一个深度CNN来训练转换后的数据存储,adscTrain
.与第一个示例一样,网络没有优化。重点是使用GPU上计算的内存不足数据的标量图来显示工作流。
numClasses = 10;dropoutProb = 0.2;numF = 12;层= [imageInputLayer([101 8192 1])卷积2dlayer (5,numF,“填充”,“相同”maxPooling2dLayer(3,“步”2,“填充”,“相同”) convolution2dLayer (3 2 * numF“填充”,“相同”maxPooling2dLayer(3,“步”2,“填充”,“相同”) convolution2dLayer(3、4 * numF,“填充”,“相同”maxPooling2dLayer(3,“步”2,“填充”,“相同”) convolution2dLayer(3、4 * numF,“填充”,“相同”(3,4*numF,“填充”,“相同”) batchNormalizationLayer reluLayer maxPooling2dLayer(2) dropoutLayer(dropoutProb) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer(“类”类别(ads.Labels));];
设置网络的培训选项。
miniBatchSize = 25;选项= trainingOptions(“亚当”,...“InitialLearnRate”1的军医,...“MaxEpochs”30岁的...“MiniBatchSize”miniBatchSize,...“洗牌”,“every-epoch”,...“阴谋”,“训练进步”,...“详细”假的,...“ExecutionEnvironment”,“图形”);
培训网络。
trainedNet = trainNetwork(adsSCTrain,layers,options);
在这个例子中,训练在25分10秒内完成。如果将调用注释掉gpuArray
在helperDigitScalogram
并利用CPU获取标度图,训练时间明显增加。在这种情况下,观察到从25分10秒增加到45分38秒。
使用训练好的网络预测测试集的数字标签。
ypredict = classid (trainedNet,adsSCTest,“ExecutionEnvironment”,“CPU”);cnnAccuracy = sum(yexpected == adsTest.Labels)/numel(yexpected)*100
cnnAccuracy = 96.2500
使用GPU的推断时间大约为22秒。使用CPU,推理时间翻倍至45秒。
训练后的网络在测试数据上的性能接近96%。这与在基于小波散射和深度学习的语音数字识别.
总结
这个例子展示了如何使用GPU来加速标量图的计算。该示例展示了使用转换后的数据存储从磁盘读取内存内数据和内存外数据时高效计算标量图的最佳工作流程。
参考文献
拜姆,D. S.科鲁奇,E. S.蒙拉德,H. S.史密斯,R. F.赖特,A.拉努,D. F.戈蒂耶,B. J.兰西尔,W.格罗斯曼和E.布劳恩瓦尔德。"口服米力农治疗严重充血性心力衰竭患者的存活率"美国心脏病学会杂志.第7卷,第3期,1986,第661-670页。
戈德伯格A. L, L. A. N.阿马拉尔,L.格拉斯,J. M.豪斯多夫,P. Ch.伊万诺夫,R. G.马克,J. E.米耶图斯,G. B.穆迪,c . k。彭先生和斯坦利先生。“PhysioBank, PhysioToolkit,和PhysioNet:复杂生理信号新研究资源的组成部分。”循环。卷101,第23号:e215-e220。[流通电子页;
http://circ.ahajournals.org/content/101/23/e215.full
];二年(六月十三日)。cir.101.23.e215 doi: 10.1161/01.。穆迪,g。B。和r。g。马克。“MIT-BIH心律失常数据库的影响。”IEEE医学与生物工程杂志.20卷。第三期,2001年5月至6月,第45-50页。(PMID: 11446209)
函数标签= helpergenLabels(广告)此函数仅在小波工具箱示例中使用。可能是这样%将在将来的版本中更改或删除。tmp = cell(数字(ads.Files),1);表达=“[0 - 9]+ _”;为nf = 1: number (ads.Files) idx = regexp(ads.Files{nf},表达式);tmp{nf} = ads.Files{nf}(idx);结束标签=分类(tmp);结束
函数X = helperECGScalograms(data,window,useGPU) disp(“计算量图……”);Nsig = size(data,1);Nsamp = size(data,2);Nsegment = Nsamp/window;Fb = cwtfilterbank(“SignalLength”窗口,“声音”10);Ns =长度(fb.Scales);X = 0 ([Ns,window,1,Nsig*Nsegment],“单一”);Start = 0;如果useGPU data = gpuArray(single(data'));其他的Data = single(Data ');结束为ii = 1:Nsig ts = data(:,ii);ts =重塑(ts,窗口,Nsegment);Ts = (Ts -mean(Ts))./max(abs(Ts));为Kk = 1:大小(ts,2) CFS = fb.wt(ts(:, Kk));X(:,:,1,kk+start) = gather(abs(cfs));结束start = start+Nsegment;如果Mod (ii,50) == 0“加工”+ ii +文件输出+ Nsig)结束结束disp (“…”);数据=收集(数据);结束
函数[x,info] = helperReadSPData(x,info)此函数仅用于使用小波工具箱的示例。它可能会改变%将在未来的版本中删除。N =数字(x);如果N > 8192 x = x(1:8192);elseifN < 8192 pad = 8192-N;Prepad =地板(pad/2);Postpad = cell (pad/2);X = [0 (prepad,1);x;0 (postpad 1)];结束X = X /max(abs(X));结束
函数[dataout,info] = helperdigitscalalogram (audioin,info,fb) audioin = single(audioin);audioin = gpuArray(audioin);audioin = helperReadSPData(audioin);CFS = gather(abs(fb.wt(audioin)));Audioin = gather(Audioin);dataout = {cfs,info.Label};结束