主要内容

训练生成对抗网络(GAN)的声音合成

这个例子展示了如何训练和使用生成对抗网络(GAN)来生成声音。

简介

在生成对抗网络中,生成器和鉴别器相互竞争以提高生成质量。

GANs在音频和语音处理领域引起了极大的兴趣。应用包括文本到语音合成、语音转换和语音增强。

这个例子训练GAN进行音频波形的无监督合成。本例中的GAN产生打击音。同样的方法可以用于生成其他类型的声音,包括语音。

用预先训练的GAN合成音频

在从头开始训练GAN之前,请使用预先训练好的GAN生成器来合成打击声音。

下载预训练的生成器。

matFileName =“drumGeneratorWeights.mat”;loc = matlab.internal.examples.download万博1manbetxSupportFile(“音频”“GanAudioSynthesis /”+ matFileName);拷贝文件(loc pwd)

这个函数synthesizePercussiveSound调用一个预先训练好的网络来合成一个采样频率为16千赫的打击声。的synthesizePercussiveSound函数包含在本例的末尾。

合成一种打击乐,然后听它。

synthsound =合成打击乐;Fs = 16e3;声音(synthsound fs)

绘制合成的敲击声。

T = (0:length(synthsound)-1)/fs;情节(t, synthsound)网格包含(“时间(s)”)标题(“合成打击音”

您可以使用打击声音合成器与其他音频效果,以创建更复杂的应用程序。例如,您可以将混响应用于合成的打击音。

创建一个反射器对象并打开其参数调谐器UI。这个UI使您能够调优反射器模拟运行时的参数。

混响=混响器(SampleRate=fs);parameterTuner(混响);

创建一个timescope对象来可视化打击声音。

ts = timescope(SampleRate=fs,...TimeSpanSource =“财产”...TimeSpanOverrunAction =“滚动”...时间间隔= 10,...BufferLength = 10 * 256 * 64,...ShowGrid = true,...YLimits = [1]);

在循环中,合成打击声并应用混响。使用参数调谐器UI来调整混响。的值。如果要长时间运行模拟,请增大loopCount参数。

loopCount = 20;ii = 1:loopCount synthsound = synthesizePercussiveSound;Synthsound =混响(合成声);ts (synthsound (: 1));soundsc (synthsound fs)暂停(0.5)结束

培训GAN

现在您已经看到了预先训练的打击音生成器的运行情况,您可以详细地研究训练过程。

GAN是一种深度学习网络,它生成的数据具有与训练数据相似的特征。

GAN由两个一起训练的网络组成发电机和一个鉴频器

  • 生成器——给定一个向量或随机值作为输入,该网络生成与训练数据具有相同结构的数据。生成器的工作就是欺骗鉴别器。

  • 判别器——给定包含来自训练数据和生成数据的观察结果的数据批次,该网络试图将观察结果分类为真实的或生成的。

为了使生成器的性能最大化,在给定生成的数据时,使鉴别器的损失最大化。也就是说,生成器的目标是生成鉴别器分类为实数的数据。为了最大限度地提高鉴别器的性能,在给定真实数据和生成数据批次时,尽量减少鉴别器的损失。理想情况下,这些策略会产生一个生成令人信服的真实数据的生成器和一个学习了训练数据特征的强特征表示的鉴别器。

在本例中,您训练生成器创建敲击声音的伪时频短时傅里叶变换(STFT)表示。训练鉴别器来识别STFT是由生成器合成的还是从真实音频信号计算出来的。您可以通过计算真实敲击声音的短录音的STFT来创建真正的STFT。

负荷训练数据

使用Freesound One-Shot Percussive Sounds数据集训练GAN[2].下载并提取数据集。删除任何带有禁止商业使用许可的文件。

url1 =“https://zenodo.org/record/4687854/files/one_shot_percussive_sounds.zip”;url2 =“https://zenodo.org/record/4687854/files/licenses.txt”;downloadFolder = tempdir;percussivesoundsFolder = fullfile(下载文件夹,“one_shot_percussive_sounds”);licensefilename = fullfile(percussivesoundsFolder,“licenses.txt”);如果~ datasetExists percussivesoundsFolder disp ("下载免费的一次敲击声音数据集(112.6 MB)…") unzip(url1,downloadFolder) websave(licensefilename,url2);removeRestrictiveLicence (percussivesoundsFolder licensefilename)结束

创建一个audioDatastore对象,它指向数据集。

ads = audioDatastore(percussivesoundsFolder, inclesubfolders =true);

定义发电机网络

定义一个从随机值的1 × 1 × 100数组生成stft的网络。创建一个网络,将1 × 1 × 100阵列升级为128 × 128 × 1阵列,使用一个完全连接层,然后是一个重塑层和一系列带有ReLU层的转置卷积层。

这个图显示了信号通过发生器时的尺寸。的表4定义了生成器体系结构[1]

发电机网络定义在modelGenerator,它包含在本示例的末尾。

定义鉴别器网络

定义一个网络,对真实的和生成的128 × 128 stft进行分类。

创建一个使用128 × 128图像的网络,并使用一系列带有泄漏的ReLU层的卷积层输出标量预测评分,然后是完全连接的层。

该图显示了信号通过鉴别器时的尺寸。的表5定义了鉴别器体系结构[1]

中定义了鉴别器网络modelDiscriminator,它包含在本示例的末尾。

生成真正的打击音训练数据

从数据存储中的敲击声信号生成STFT数据。

定义STFT参数。

fftLength = 256;win = hann(fftLength,“周期”);overlapLength = 128;

为了加快处理速度,将特征提取分布到多个使用parfor

首先,确定数据集的分区数量。如果没有并行计算工具箱™,请使用单个分区。

如果canUseParallelPool = gcp;numPar = numpartitions(ads,pool);其他的numPar = 1;结束
使用“本地”配置文件启动并行池(parpool)…与6名工人连接到平行水池。

对于每个分区,从数据存储中读取并计算STFT。

parforii = 1:numPar subds =分区(ads,numPar,ii);STrain = 0 (fftLength/2+1,128,1, nummel (subds.Files));idx = 1:数字(subds.Files)%阅读音频[x,xinfo] = read(subds);%进行预处理x = preprocessAudio(single(x), xininfo . samplerate);% STFTS0 = stft(x,Window=win,OverlapLength= OverlapLength,FrequencyRange=“单向的”);%级S = abs(S0);STrain(:,:,:,idx) = S;结束STrainC{ii} = STrain;结束
分析文件并将文件传输给工作人员…完成。

将输出转换为带有stft的四维数组。

(4,STrainC{:});

将数据转换为对数刻度,以便更好地与人类的感知保持一致。

STrain = log(STrain + 1e-6);

将训练数据归一化,使其均值为零,单位标准差为零。

计算每个频率仓的STFT均值和标准差。

SMean = mean(STrain,[2 3 4]);SStd = std(STrain,1,[2 3 4]);

归一化每个频率仓。

STrain = (STrain- smean)./SStd;

计算的stft具有无界值。遵循中的方法[1],将光谱裁剪为3个标准差,并重新缩放到[-1 1],使数据有界。

应变=应变/3;Y =重塑(应变,数字(应变),1);Y(Y<-1) = -1;Y(Y>1) = 1;应变=重塑(Y,大小(应变));

丢弃最后一个频率仓以强制STFT仓的数量为2的幂(这对卷积层很有效)。

应变=应变(1:end-1,:,:,:);

排列尺寸,为输入鉴别器做准备。

STrain = permute(STrain,[2 1 3 4]);

指定培训项目

在1000个epoch中使用64个小批量进行训练。

maxEpochs = 1000;miniBatchSize = 64;

计算消费数据所需的迭代次数。

numIterationsPerEpoch = floor(size(STrain,4)/miniBatchSize);

指定Adam优化的选项。设置生成器和鉴别器的学习速率为0.0002.对于这两个网络,使用梯度衰减因子为0.5和梯度衰减因子的平方为0.999。

learnRateGenerator = 0.0002;learnRateDiscriminator = 0.0002;gradientDecayFactor = 0.5;squaredGradientDecayFactor = 0.999;

如果有GPU,可以在GPU上进行训练。使用GPU需要并行计算工具箱™。

executionEnvironment =“汽车”

初始化生成器和鉴别器权重。的initializeGeneratorWeights而且initializeDiscriminatorWeights函数返回使用gloriot统一初始化获得的随机权重。本例的最后包含了函数。

generatorParameters = initializeGeneratorWeights;discriminatorParameters = initializeDiscriminatorWeights;

火车模型

使用自定义训练循环训练模型。遍历训练数据并在每次迭代中更新网络参数。

对于每个纪元,洗牌训练数据并在小批量数据上循环。

对于每个小批量:

  • 生成一个dlarray对象,该对象包含生成器网络的随机值数组。

  • 对于GPU训练,将数据转换为agpuArray(并行计算工具箱)对象。

  • 评估模型梯度使用dlfeval(深度学习工具箱)辅助函数,modelDiscriminatorGradients而且modelGeneratorGradients

  • 方法更新网络参数adamupdate(深度学习工具箱)函数。

初始化Adam的参数。

trailingAvgGenerator = [];trailingAvgSqGenerator = [];trailingAvgDiscriminator = [];trailingAvgSqDiscriminator = [];

根据您的机器,训练这个网络可能需要数小时。要跳过训练,请设置doTraining

doTraining =真正的

你可以设置saveCheckpoints真正的以每十次将更新的权重和状态保存到MAT文件中。然后,如果训练中断,您可以使用这个MAT文件恢复训练。

saveCheckpoints =真正的

指定生成器输入的长度。

numLatentInputs = 100;

训练GAN。这可能需要几个小时来运行。

迭代= 0;epoch = 1: maxepoch% Shuffle数据。idx = randperm(size(STrain,4));应变=应变(:,:,:,idx);在小批上循环。index = 1:numIterationsPerEpoch迭代=迭代+ 1;读取小批数据。dlX = STrain(:,:,:,(index-1)*miniBatchSize+1:index*miniBatchSize);dlX = dlarray(dlX,“SSCB”);为发电机网络生成潜在输入。Z = 2 * (rand(1,1,numLatentInputs,miniBatchSize,“单身”) - 0.5);dlZ = dlarray(Z);如果在GPU上训练,则将数据转换为gpuArray。如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray(dlZ);dlX = gpuArray(dlX);结束使用dlfeval和帮助函数。gradientsDiscriminator =...dlfeval (@modelDiscriminatorGradients discriminatorParameters、generatorParameters dlX, dlZ);更新鉴别器网络参数。[discriminatorParameters, trailingAvgDiscriminator trailingAvgSqDiscriminator] =...adamupdate (discriminatorParameters gradientsDiscriminator,...trailingAvgDiscriminator trailingAvgSqDiscriminator,迭代,...learnRateDiscriminator、gradientDecayFactor squaredGradientDecayFactor);为发电机网络生成潜在输入。Z = 2 * (rand(1,1,numLatentInputs,miniBatchSize,“单身”) - 0.5);dlZ = dlarray(Z);如果在GPU上训练,则将数据转换为gpuArray。如果(executionEnvironment = =“汽车”&& canUseGPU) || executionEnvironment ==“图形”dlZ = gpuArray(dlZ);结束使用dlfeval和% |modelGeneratorGradients| helper函数。gradientsGenerator =...dlfeval (@modelGeneratorGradients discriminatorParameters generatorParameters, dlZ);更新发电机网络参数。[generatorParameters, trailingAvgGenerator trailingAvgSqGenerator] =...adamupdate (generatorParameters gradientsGenerator,...trailingAvgGenerator trailingAvgSqGenerator,迭代,...learnRateGenerator、gradientDecayFactor squaredGradientDecayFactor);结束每10个周期,保存一个训练快照到MAT文件。如果国防部(时代,10)= = 0 disp (“时代”+ epoch +“Out of”+ maxEpochs +“完成”。);如果saveCheckpoints%保存检查点,以防训练中断。保存(“audiogancheckpoint.mat”...“generatorParameters”“discriminatorParameters”...“trailingAvgDiscriminator”“trailingAvgSqDiscriminator”...“trailingAvgGenerator”“trailingAvgSqGenerator”“迭代”);结束结束结束
千分之十的纪元完成。千分之二十纪元完成。Epoch 30 / 1000完成。纪元40 / 1000完成。1000次中的50次完成。Epoch 60 / 1000完成。Epoch 70 / 1000完成。纪元80 / 1000完成。纪元90 / 1000完成。纪元100 / 1000完成。 Epoch 110 out of 1000 complete. Epoch 120 out of 1000 complete. Epoch 130 out of 1000 complete. Epoch 140 out of 1000 complete. Epoch 150 out of 1000 complete. Epoch 160 out of 1000 complete. Epoch 170 out of 1000 complete. Epoch 180 out of 1000 complete. Epoch 190 out of 1000 complete. Epoch 200 out of 1000 complete. Epoch 210 out of 1000 complete. Epoch 220 out of 1000 complete. Epoch 230 out of 1000 complete. Epoch 240 out of 1000 complete. Epoch 250 out of 1000 complete. Epoch 260 out of 1000 complete. Epoch 270 out of 1000 complete. Epoch 280 out of 1000 complete. Epoch 290 out of 1000 complete. Epoch 300 out of 1000 complete. Epoch 310 out of 1000 complete. Epoch 320 out of 1000 complete. Epoch 330 out of 1000 complete. Epoch 340 out of 1000 complete. Epoch 350 out of 1000 complete. Epoch 360 out of 1000 complete. Epoch 370 out of 1000 complete. Epoch 380 out of 1000 complete. Epoch 390 out of 1000 complete. Epoch 400 out of 1000 complete. Epoch 410 out of 1000 complete. Epoch 420 out of 1000 complete. Epoch 430 out of 1000 complete. Epoch 440 out of 1000 complete. Epoch 450 out of 1000 complete. Epoch 460 out of 1000 complete. Epoch 470 out of 1000 complete. Epoch 480 out of 1000 complete. Epoch 490 out of 1000 complete. Epoch 500 out of 1000 complete. Epoch 510 out of 1000 complete. Epoch 520 out of 1000 complete. Epoch 530 out of 1000 complete. Epoch 540 out of 1000 complete. Epoch 550 out of 1000 complete. Epoch 560 out of 1000 complete. Epoch 570 out of 1000 complete. Epoch 580 out of 1000 complete. Epoch 590 out of 1000 complete. Epoch 600 out of 1000 complete. Epoch 610 out of 1000 complete. Epoch 620 out of 1000 complete. Epoch 630 out of 1000 complete. Epoch 640 out of 1000 complete. Epoch 650 out of 1000 complete. Epoch 660 out of 1000 complete. Epoch 670 out of 1000 complete. Epoch 680 out of 1000 complete. Epoch 690 out of 1000 complete. Epoch 700 out of 1000 complete. Epoch 710 out of 1000 complete. Epoch 720 out of 1000 complete. Epoch 730 out of 1000 complete. Epoch 740 out of 1000 complete. Epoch 750 out of 1000 complete. Epoch 760 out of 1000 complete. Epoch 770 out of 1000 complete. Epoch 780 out of 1000 complete. Epoch 790 out of 1000 complete. Epoch 800 out of 1000 complete. Epoch 810 out of 1000 complete. Epoch 820 out of 1000 complete. Epoch 830 out of 1000 complete. Epoch 840 out of 1000 complete. Epoch 850 out of 1000 complete. Epoch 860 out of 1000 complete. Epoch 870 out of 1000 complete. Epoch 880 out of 1000 complete. Epoch 890 out of 1000 complete. Epoch 900 out of 1000 complete. Epoch 910 out of 1000 complete. Epoch 920 out of 1000 complete. Epoch 930 out of 1000 complete. Epoch 940 out of 1000 complete. Epoch 950 out of 1000 complete. Epoch 960 out of 1000 complete. Epoch 970 out of 1000 complete. Epoch 980 out of 1000 complete. Epoch 990 out of 1000 complete. Epoch 1000 out of 1000 complete.

合成的声音

现在你已经训练了网络,你可以更详细地研究合成过程。

训练有素的打击声发生器从随机值的输入数组合成短时傅里叶变换(STFT)矩阵。逆STFT (ISTFT)操作将时频STFT转换为合成的时域音频信号。

如果你跳过训练,加载一个预先训练的发电机的重量。

如果~ doTraining负载(matFileName“generatorParameters”“SMean”“SStd”);结束

生成器以1 × 1 × 100的随机值向量作为输入。生成一个示例输入向量。

dlZ = dlarray(2*(rand(1,1,numLatentInputs,1,“单身”) - 0.5));

将随机向量传递给生成器以创建STFT图像。generatorParameters是一个包含预训练生成器权值的结构。

dlXGenerated = modelGenerator(dlZ,generatorParameters);

转换STFTdlarray到一个单精度矩阵。

S = dlXGenerated.extractdata;

对STFT进行转置,使其尺寸与istft函数。

S = S.';

STFT是一个128 × 128矩阵,其中第一个维度表示从0到8 kHz线性间隔的128个频率箱。生成器被训练从256的FFT长度中生成单侧STFT,省略最后一个bin。通过在STFT中插入一行零来重新引入该bin。

S = [S; 0 (1,128)];

恢复生成用于训练的stft时使用的规范化和缩放步骤。

S = S * 3;S = (S *SStd) + SMean;

将STFT从对数域转换为线性域。

S = exp(S);

将STFT从单面转换为双面。

S = [S;S(end-1:-1:2,:)];

用零填充以删除窗口边缘效果。

S =[零(256,100),S,零(256,100)];

STFT矩阵不包含任何相位信息。使用快速版本的Griffin-Lim算法进行20次迭代来估计信号相位并产生音频样本。

myAudio = stftmag2sig(S,256,...FrequencyRange =“双侧”...窗口=损害(256“周期”),...OverlapLength = 128,...MaxIterations = 20,...方法=“fgla”);myAudio = myAudio./max(abs(myAudio),[],“所有”);myAudio = myAudio(128*100:end-128*100);

听一下合成的打击音。

声音(收集(myAudio), fs)

绘制合成的敲击声。

t = (0:length(myAudio)-1)/fs;情节(t, myAudio)网格包含(“时间(s)”)标题(“合成GAN声音”

绘制合成的敲击声的STFT。

图stft (fs, myAudio窗口=损害(256年“周期”), OverlapLength = 128);

模型生成器函数

modelGenerator函数将1 × 1 × 100数组(dlX)升级为128 × 128 × 1数组(dlY)。参数是保存生成器层权重的结构。的表4定义了生成器体系结构[1]

函数dlY = modelGenerator(dlX,parameters) dlY = fulllyconnect (dlX,parameters. fc . weights,parameters. fc . bias,Dataformat=“SSCB”);dlY =重塑(dlY,[1024 4 4 size(dlY,2)]);ly = permute(ly,[3 2 1 4]);dlY = relu(dlY);dlY = dltranspconv(dlY,parameters.Conv1.Weights,parameters.Conv1.Bias,Stride=2,裁剪=“相同”DataFormat =“SSCB”);dlY = relu(dlY);dlY = dltranspconv(dlY,parameters.Conv2.Weights,parameters.Conv2.Bias,Stride=2,裁剪=“相同”DataFormat =“SSCB”);dlY = relu(dlY);dlY = dltranspconv(dlY,parameters.Conv3.Weights,parameters.Conv3.Bias,Stride=2,裁剪=“相同”DataFormat =“SSCB”);dlY = relu(dlY);dlY = dltranspconv(dlY,parameters.Conv4.Weights,parameters.Conv4.Bias,Stride=2,裁剪=“相同”DataFormat =“SSCB”);dlY = relu(dlY);dlY = dltranspconv(dlY,parameters.Conv5.Weights,parameters.Conv5.Bias,Stride=2,裁剪=“相同”DataFormat =“SSCB”);dlY = tanh(dlY);结束

模型鉴别器函数

modelDiscriminator函数获取128 * 128的图像并输出标量预测分数。鉴别器体系结构定义在[1]的表5中。

函数dlY = dlconv(dlX,parameters. conv1 . weights,parameters. conv1 . bias,Stride=2,Padding=“相同”);ly = leakyrelu(ly,0.2);dlY = dlconv(dlY,parameters.Conv2.Weights,parameters.Conv2.Bias,Stride=2,Padding=“相同”);ly = leakyrelu(ly,0.2);dlY = dlconv(dlY,parameters.Conv3.Weights,parameters.Conv3.Bias,Stride=2,Padding=“相同”);ly = leakyrelu(ly,0.2);dlY = dlconv(dlY,parameters.Conv4.Weights,parameters.Conv4.Bias,Stride=2,Padding=“相同”);ly = leakyrelu(ly,0.2);dlY = dlconv(dlY,parameters.Conv5.Weights,parameters.Conv5.Bias,Stride=2,Padding=“相同”);ly = leakyrelu(ly,0.2);dlY = stripdim (dlY);ly = permute(ly,[3 2 1 4]);海底=重塑(海底,4 * 4 * 64 * 16,元素个数(海底)/ (4 * 4 * 64 * 16));weights = parameters.FC.Weights;偏差=参数。fc .偏差;dlY =全连接(dlY,权重,偏差,数据格式=“CB”);结束

模型鉴别器梯度函数

modelDiscriminatorGradients函数将生成器和鉴别器参数作为输入generatorParameters而且discriminatorParameters,一小批输入数据X,和一个随机值的数组Z,并返回判别器损失相对于网络中可学习参数的梯度。

函数gradientsDiscriminator = modelDiscriminatorGradients(discriminatorParameters,generatorParameters,X,Z)用鉴别器网络计算真实数据的预测。。Y = modelDiscriminator(X,discriminatorParameters);用鉴别器网络计算生成数据的预测。Xgen = modelGenerator(Z,generatorParameters);Ygen = modelDiscriminator(dlarray(Xgen,“SSCB”), discriminatorParameters);计算GAN损耗。lossDiscriminator = ganDiscriminatorLoss(Y,Ygen);对于每个网络,计算与损失相关的梯度。gradientsDiscriminator = dlgradient(lossDiscriminator,discriminatorParameters);结束

模型生成器梯度函数

modelGeneratorGradients函数将可学习参数和随机值数组作为判别器和生成器的输入Z,并返回发电机损耗相对于网络中可学习参数的梯度。

函数gradientsGenerator = modelGeneratorGradients(discriminatorParameters,generatorParameters,Z)用鉴别器网络计算生成数据的预测。Xgen = modelGenerator(Z,generatorParameters);Ygen = modelDiscriminator(dlarray(Xgen,“SSCB”), discriminatorParameters);计算GAN损耗lossGenerator = ganGeneratorLoss(Ygen);对于每个网络,计算与损失相关的梯度。gradientsGenerator = dlgradient(lossGenerator,generatorParameters);结束

鉴别器损失函数

鉴别器的目标是不被生成器愚弄。为了最大化鉴别器成功鉴别真实图像和生成图像的概率,最小化鉴别器损失函数。发生器的损失函数遵循中突出显示的DCGAN方法[1]

函数lossDiscriminator = ganDiscriminatorLoss(dlYPred,dlYPredGenerated) fake = dlarray(0 (1,size(dlYPred,2)));real = dlarray(ones(1,size(dlYPred,2)));D_loss = mean(sigmoid_cross_entropy_with_logits(dlYPredGenerated,fake));D_loss = D_loss + mean(sigmoid_cross_entropy_with_logits(dlYPred,real));lossDiscriminator = D_loss / 2;结束

发电机损耗函数

生成器的目标是生成鉴别器分类为“真实”的数据。为了最大化来自生成器的图像被鉴别器分类为真实的概率,最小化生成器损失函数。生成器的损失函数遵循中强调的深度卷积生成对抗网络(DCGAN)方法[1]

函数lossGenerator = ganGeneratorLoss(dlYPredGenerated) real = dlarray(ones(1,size(dlYPredGenerated,2)));lossGenerator = mean(sigmoid_cross_entropy_with_logits(dlYPredGenerated,real));结束

Discriminator Weights初始化器

initializeDiscriminatorWeights使用格洛洛特算法初始化鉴别器权重。

函数discriminatorParameters = initializeDiscriminatorWeights filterSize = [5 5];Dim = 64;% Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 1 dim]);偏差= 0(1,1,暗淡,“单身”);discriminatorParameters.Conv1。Weights = dlarray(Weights);discriminatorParameters.Conv1。偏差= dlarray(偏差);% Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) dim 2*dim]);偏差=零(1,1,2*dim,“单身”);discriminatorParameters.Conv2。Weights = dlarray(Weights);discriminatorParameters.Conv2。偏差= dlarray(偏差);% Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 2*dim 4*dim]);偏差=零(1,1,4*dim,“单身”);discriminatorParameters.Conv3。Weights = dlarray(Weights);discriminatorParameters.Conv3。偏差= dlarray(偏差);% Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 4*dim 8*dim]);偏差=零(1,1,8*dim,“单身”);discriminatorParameters.Conv4。Weights = dlarray(Weights);discriminatorParameters.Conv4。偏差= dlarray(偏差);% Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 8*dim 16*dim]);偏差=零(1,1,16*dim,“单身”);discriminatorParameters.Conv5。Weights = dlarray(Weights);discriminatorParameters.Conv5。偏差= dlarray(偏差);%全连接weights = iGlorotInitialize([1,4 * 4 * dim * 16]);偏差= 0 (1,1,“单身”);discriminatorParameters.FC.Weights = dlarray(weights);discriminatorParameters.FC.Bias = dlarray(偏差);结束

生成器权重初始化器

initializeGeneratorWeights使用格洛洛特算法初始化生成器权重。

函数generatorParameters = initializeGeneratorWeights dim = 64;%密度1weights = iGlorotInitialize([dim*256,100]);偏差= 0 (dim*256,1,“单身”);generatorParameters.FC.Weights = dlarray(weights);generatorParameters.FC.Bias = dlarray(偏差);filterSize = [5 5];% Trans Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 8*dim 16*dim]);偏差= 0 (1,1,dim*8,“单身”);generatorParameters.Conv1。Weights = dlarray(Weights);generatorParameters.Conv1。偏差= dlarray(偏差);% Trans Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 4*dim 8*dim]);偏差= 0 (1,1,dim*4,“单身”);generatorParameters.Conv2。Weights = dlarray(Weights);generatorParameters.Conv2。偏差= dlarray(偏差);% Trans Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 2*dim 4*dim]);偏差= 0 (1,1,dim*2,“单身”);generatorParameters.Conv3。Weights = dlarray(Weights);generatorParameters.Conv3。偏差= dlarray(偏差);% Trans Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) dim 2*dim]);偏差= 0(1,1,暗淡,“单身”);generatorParameters.Conv4。Weights = dlarray(Weights);generatorParameters.Conv4。偏差= dlarray(偏差);% Trans Conv2Dweights = iGlorotInitialize([filterSize(1) filterSize(2) 1 dim]);偏差= 0 (1,1,1,“单身”);generatorParameters.Conv5。Weights = dlarray(Weights);generatorParameters.Conv5。偏差= dlarray(偏差);结束

合成打击声

synthesizePercussiveSound使用预先训练的网络合成打击声音。

函数y = synthesizepercussisounound持续的pGeneratorParameters pMean ppd如果isempty (pGeneratorParameters)如果MAT文件不存在,请下载文件名=“drumGeneratorWeights.mat”;负载(文件名,“SMean”“SStd”“generatorParameters”);pMean = SMean;pSTD = SStd;pGeneratorParameters = generatorParameters;结束生成随机向量dlZ = dlarray(2 * (rand(1,1,100,1),“单身”) - 0.5));生成频谱图dlXGenerated = modelGenerator(dlZ,pGeneratorParameters);从单数组转换为单数组S = dlXGenerated.extractdata;S = S.';%零填充删除边缘效果S = [S;0 (1128)];与训练相反的步骤S = S * 3;S = (S *pSTD) + pMean;S = exp(S);做成两面的S = [S;S (end-1: 1:2,)];%末尾和开始处为零的PadS =[零(256,100)S零(256,100)];使用快速Griffin-Lim算法重建信号。myAudio = stftmag2sig(S,256,...FrequencyRange =“双侧”...窗口=损害(256“周期”),...OverlapLength = 128,...MaxIterations = 20,...方法=“fgla”);myAudio = myAudio./max(abs(myAudio),[],“所有”);y = myAudio(128*100:end-128*100);结束

效用函数

函数Out = sigmoid_cross_entropy_with_logits(x,z) Out = max(x, 0) - x .* z + log(1 + exp(-abs(x)));结束函数w = iGlorotInitialize(sz)如果numInputs = sz(2);numOutputs = sz(1);其他的numInputs = prod(sz(1:3));numOutputs = prod(sz([1 2 4]));结束乘数=根号(2 / (numInputs + numOutputs));W =乘数*根号(3)* (2 * rand(sz,“单身”) - 1);结束函数out = preprocessAudio(in,fs)%确保单一In = mean(In,2);重新采样到16kHzX = resample(in,16e3,fs);切割或填充大约有1秒的长度加上填充以确保% 128分析窗口的STFT与256点窗口和128点%重叠。y = trimOrPad(x,16513);%正常化Out = y /max(abs(y));结束函数y = trimOrPad(x,n)修剪或垫音频% y = trimOrPad(x,n)对输入的x到n个样本沿第一个进行修整或填充%的维度。如果x被修剪了,它的正面和背面修剪得一样。如果x是填充的,它在前面和后面都是用零填充的。对于奇数长度的裁边或填充物,额外的样品被裁边或填充物%从后面开始。A = size(x,1);如果a < n frontPad = floor((n-a)/2);backPad = n - a - frontPad;y = [0 (frontPad、大小(x, 2),如= x); x; 0(挤压垫、大小(x, 2),如= x));elseifa > n frontTrim =地板((a-n)/2) + 1;backTrim = a - n - frontTrim;y = x(frontTrim:end-backTrim,:);其他的Y = x;结束结束函数removeRestrictiveLicence (percussivesoundsFolder licensefilename)removeRestrictiveLicense移除限制性license解析将id映射到license的license文件。创建一个表来保存信息。F = fileread(licensefilename);K = jsondecode(f);fns =字段(K);T = table(Size=[numel(fns),4],...VariableTypes = [“字符串”“字符串”“字符串”“字符串”),...VariableNames = [“ID”“文件名”“用户名”“许可证”]);ii = 1:数字(fns) fn =字符串(K.(fns{ii}).name);li = string(K.(fns{ii}).license);id = extractAfter(string(fns{ii}),“x”);un = string(K.(fns{ii}).username);T(ii,:) = {id,fn,un,li};结束删除任何禁止商业使用的文件。。文件中的文件%合适的文件夹,然后删除它。un万博1manbetxsupportedLicense =“http://creativecommons.org/licenses/by-nc/3.0/”;fileToRemove = T.ID(strcmp(T.License,un万博1manbetxsupportedLicense));ii = 1:numel(fileToRemove) fileInfo = dir(fullfile(percussivesoundsFolder,“* *”fileToRemove (ii) +“wav”));删除(fullfile (fileInfo.folder fileInfo.name))结束结束

参考

[1]多纳休,C.麦考利,M.帕克特,2019。“对抗性音频合成。”ICLR。

拉米雷斯,安东尼奥,普里蒂什·钱德纳,泽维尔·法沃里,艾米莉亚·戈麦斯和泽维尔·塞拉。“由高级音色特征参数化的神经冲击合成”2020年IEEE声学、语音和信号处理国际会议(ICASSP), 2020年。https://doi.org/10.1109/icassp40776.2020.9053128。