MATLAB实战 利用1D-DCGAN生成光谱或信号数据

0.前言

在光谱学或信号处理领域,获取大量高质量的数据可能是一项挑战。利用DCGAN迁移对抗生成光谱或信号数据,可以有效地增加数据集的多样性,提高模型的泛化能力。

该实战项目提供了所有源代码与测试数据,旨在帮助学者快速地掌握了解利用DCGAN对1维数据的生成。

建议开始本项目前提前了解和掌握以下内容:MATLAB代码解析:利用DCGAN实现图像数据的生成 全网最细&DCGAN设计-训练入门

项目参考文献:

光谱技术结合水分校正与样本增广的棉田土壤盐分精准反演 - 中国知网

1.训练效果、脚本与文件

1.1训练效果

训练8个周期

训练36个周期

训练115个周期

充分训练后

1.2脚本代码

1.2.1主程序

Matlab 复制代码
数据获取
clear all
clc
load("TestData.mat");
%返回相同的数据类型,以行为分配样本
%'IterationDimension'=1以第一个维度划分样本(行),2为第二个维度,以此类推;
ADataStore = arrayDatastore(DataMat,'IterationDimension',1,'OutputType', 'cell');
%%构建生成器
numLatentInputs=200;%输入随机数大小
netG=Creat_1D_Gener(numLatentInputs);
%%判别器
netD=Creat_1D_Discri();
%%指定训练选项
dropoutProb = 0.25;%泄露率
scale = 0.2;
numEpochs = 2000;%训练周期
miniBatchSize = 256;%最小批次
learnRate = 0.00002;
learnRateD=0.00002;
gradientDecayFactor = 0.45;
squaredGradientDecayFactor = 0.999;
flipProb = 0.15;%翻转概率
validationFrequency = 100;%验证频率
%%训练模型
mbq = minibatchqueue(ADataStore, ...
    MiniBatchSize=miniBatchSize, ...
    MiniBatchFcn=@preprocessMiniBatch12_2D, ...%预处理方法,与采集的数据类型对应
    PartialMiniBatch="discard", ...
    MiniBatchFormat="SCB");

trailingAvgG = [];
trailingAvgSqG = [];
trailingAvg = [];
trailingAvgSqD = [];
numValidationImages = 4;
ZValidation = randn(numLatentInputs,numValidationImages,"single");
ZValidation = dlarray(ZValidation,"CB");
if canUseGPU
    ZValidation = gpuArray(ZValidation);
end

f = figure;
f.Position(3) = 2*f.Position(3);

imageAxes = subplot(1,2,1);
scoreAxes = subplot(1,2,2);

C = colororder;
lineScoreG = animatedline(scoreAxes,Color=C(1,:));
lineScoreD = animatedline(scoreAxes,Color=C(2,:));
legend("Generator","Discriminator");
ylim([0 1])
xlabel("Iteration")
ylabel("Score")
grid on

iteration = 0;
start = tic;

% Loop over epochs.
for epoch = 1:numEpochs

    % Reset and shuffle datastore.
    shuffle(mbq);

    % Loop over mini-batches.
    while hasdata(mbq)
        iteration = iteration + 1;
        
        % Read mini-batch of data.
        X = next(mbq);

        % Generate latent inputs for the generator network. Convert to
        % dlarray and specify the format "CB" (channel, batch). If a GPU is
        % available, then convert latent inputs to gpuArray.
        Z = randn(numLatentInputs,miniBatchSize,"single");
        Z = dlarray(Z,"CB");

        if canUseGPU
            Z = gpuArray(Z);
        end

        % Evaluate the gradients of the loss with respect to the learnable
        % parameters, the generator state, and the network scores using
        % dlfeval and the modelLoss function.
        [~,~,gradientsG,gradientsD,stateG,scoreG,scoreD] = ...
            dlfeval(@modelLoss,netG,netD,X,Z,flipProb);
        netG.State = stateG;  

        %%show data
        %"epoch"
        %epoch
        %"scoreG-D"
        %[scoreG,scoreD]
        
        
        % Update the discriminator network parameters.
        [netD,trailingAvg,trailingAvgSqD] = adamupdate(netD, gradientsD, ...
            trailingAvg, trailingAvgSqD, iteration, ...
            learnRateD, gradientDecayFactor, squaredGradientDecayFactor);
        

        % Update the generator network parameters.
        [netG,trailingAvgG,trailingAvgSqG] = adamupdate(netG, gradientsG, ...
            trailingAvgG, trailingAvgSqG, iteration, ...
            learnRate, gradientDecayFactor, squaredGradientDecayFactor);
        % Every validationFrequency iterations, display batch of generated
        % images using the held-out generator input.
        if mod(iteration,validationFrequency) == 0 || iteration == 1
            % Generate images using the held-out generator input.
            XGeneratedValidation = predict(netG,ZValidation);

            % Tile and rescale the images in the range [0 1].
            I = imtile(extractdata(XGeneratedValidation));
            I = rescale(I);
            % Display the images.
            subplot(1,2,1);
            plot(I,'DisplayName','I')
            % xticklabels([0 900]);
            % yticklabels([-1 1]);
            title("Generated Curve");
            % Update the scores plot.
            subplot(1,2,2)
            scoreGV = double(extractdata(scoreG));
            addpoints(lineScoreG,iteration,scoreGV);

            scoreDV = double(extractdata(scoreD));
            addpoints(lineScoreD,iteration,scoreDV);

            % Update the title with training progress information.
            D = duration(0,0,toc(start),Format="hh:mm:ss");
            title(...
                "Epoch: " + epoch + ", " + ...
                "Iteration: " + iteration + ", " + ...
                "Elapsed: " + string(D))

            drawnow
            %周期性保存数据
            if mod(iteration,validationFrequency*100)==0
                %save GANmodel_test.mat netG netD trailingAvg trailingAvgSqD iteration
            end
        end

    end
end
%%生成新图像  
numLatentInputs = 50;
numObservations = 1;
ZNew = randn(numLatentInputs,numObservations,"single");
ZNew = dlarray(ZNew,"CB");
if canUseGPU
    ZNew = gpuArray(ZNew);
end

XGeneratedNew = predict(netG,ZNew);

I = imtile(extractdata(XGeneratedNew));
I=rescale(I)
figure
plot(I,'DisplayName','I')
axis off
title("Generated Images")

该代码内容与之前图像生成的思路*[1]*基本一致,主要变动在于生成器、判别器、数据库构建和数据预处的区别。

[1] https://blog.csdn.net/m0_47787372/article/details/141791275?spm=1001.2014.3001.5501

首先是数据格式的变动,由于1D数据较小,这里直接用内存载入训练。

该程序提供的示例数据为2维的doule类型(每行为1个样本),数据量3658、单样本长度128。这里利用,arrayDatastore函数直接从内存读取该数据作为深度学习的训练样本,'IterationDimension'为样本分割的维数,这里按行分割样本,固设置为1.OutputType设置成same或cell都可以。

Matlab 复制代码
ADataStore = arrayDatastore(DataMat,'IterationDimension',1,'OutputType', 'cell');

如果这里不使用arrayDatastore类函数,将无法使用minibatchqueue函数将数据拆分成多个训练批次。后者仅支持datastore数据类型,当然你使用imaginedatastore等其他函数也是可以的(把1维数据变成图像再训练),但这本质上属于还是未对matlab数据类型的实现精准掌握。

1.2.2 生成器

Matlab 复制代码
function net=Creat_2D_Gener(numLatentInputs)
net = dlnetwork;

Add branches to the dlnetwork. Each branch is a linear array of layers.
tempNet = [
    featureInputLayer(numLatentInputs,"Name","input")
    projectAndReshapeLayer([8 2048])
    transposedConv1dLayer(3,1024,"Name","transposed-conv1d","Cropping","same","Stride",2)
    instanceNormalizationLayer("Name","instancenorm")
    reluLayer("Name","relu")
    transposedConv1dLayer(3,512,"Name","transposed-conv1d_1","Cropping","same","Stride",2)
    instanceNormalizationLayer("Name","instancenorm_1")
    reluLayer("Name","relu_1")
    transposedConv1dLayer(3,256,"Name","transposed-conv1d_2","Cropping","same")
    instanceNormalizationLayer("Name","instancenorm_2")
    reluLayer("Name","relu_3")
    transposedConv1dLayer(3,128,"Name","transposed-conv1d_3","Cropping","same","Stride",2)
    instanceNormalizationLayer("Name","instancenorm_3")
    reluLayer("Name","relu_2")
    transposedConv1dLayer(3,64,"Name","transposed-conv1d_4","Cropping","same","Stride",2)
    instanceNormalizationLayer("Name","instancenorm_3_1")
    reluLayer("Name","relu_2_1")
    transposedConv1dLayer(1,1,"Name","transposed-conv1d_5","Cropping","same")
    tanhLayer("Name","tanh")];
net = addLayers(net,tempNet);

clear tempNet;

net = initialize(net);

plot(net);

end

生成器用的是1维转置卷积层,输入200个随机数,通过自定义的全连接reshape层将数据转化为8*2048的大小。利用Matlab的DL designer工具包进行分析,通过观察Activation属性,我们可以很快的了解数据在生成器中的变化。其中S为空间维度,C为通道维度,B为批次量(根据训练设置变化)。这里的设计的思路就是利用噪声生成一个通道数高的带加工样本,之后每次一维转置卷积中通道维度每减半、空间维度翻倍。最后加工为128*1(C)的1维数据。

其中,rehape自定义层代码如下,和图像生成的项目基本一致,但是输出格式进行了调整(SCB),该层就是将200个输入噪声通过全连接层变为8*2048长度的数据,再reshape成8*2048*1的SCB格式数据。

Matlab 复制代码
classdef projectAndReshapeLayer < nnet.layer.Layer ...
        & nnet.layer.Formattable ...
        & nnet.layer.Acceleratable

    properties
        % Layer properties.
        OutputSize
    end

    properties (Learnable)
        % Layer learnable parameters.

        Weights
        Bias
    end

    methods
        function layer = projectAndReshapeLayer(outputSize,NameValueArgs)
            % layer = projectAndReshapeLayer(outputSize)
            % creates a projectAndReshapeLayer object that projects and
            % reshapes the input to the specified output size.
            %
            % layer = projectAndReshapeLayer(outputSize,Name=name)
            % also specifies the layer name.

            % Parse input arguments.
            arguments
                outputSize
                NameValueArgs.Name = "";
            end

            % Set layer name.
            name = NameValueArgs.Name;
            layer.Name = name;

            % Set layer description.
            layer.Description = "Project and reshape to size " + ...
                join(string(outputSize));

            % Set layer type.
            layer.Type = "Project and Reshape";

            % Set output size.
            layer.OutputSize = outputSize;
        end

        function layer = initialize(layer,layout)
            % layer = initialize(layer,layout) initializes the layer
            % learnable parameters.
            %
            % Inputs:
            %         layer  - Layer to initialize
            %         layout - Data layout, specified as a 
            %                  networkDataLayout object
            %
            % Outputs:
            %         layer - Initialized layer

            % Layer output size.
            outputSize = layer.OutputSize;

            % Initialize fully connect weights.
            if isempty(layer.Weights)

                % Find number of channels.
                idx = finddim(layout,"C");
                numChannels = layout.Size(idx);

                % Initialize using Glorot.
                sz = [prod(outputSize) numChannels];
                numOut = prod(outputSize);
                numIn = numChannels;
                layer.Weights = initializeGlorot(sz,numOut,numIn);
            end

            % Initialize fully connect bias.
            if isempty(layer.Bias)

                % Initialize with zeros.
                layer.Bias = initializeZeros([prod(outputSize) 1]);
            end
        end

        function Z = predict(layer, X)
            % Forward input data through the layer at prediction time and
            % output the result.
            %
            % Inputs:
            %         layer - Layer to forward propagate through
            %         X     - Input data, specified as a formatted dlarray
            %                 with a "C" and optionally a "B" dimension.
            % Outputs:
            %         Z     - Output of layer forward function returned as
            %                 a formatted dlarray with format "SSCB".

            % Fully connect.
            weights = layer.Weights;
            bias = layer.Bias;
            X = fullyconnect(X,weights,bias);

            % Reshape.
            outputSize = layer.OutputSize;
            Z = reshape(X,outputSize(1),outputSize(2),[]);
            Z = dlarray(Z,"SCB");
        end
    end
end

1.2.3 判别器

判别器基本与生成器对称,用1维卷积核, 代码如下:

Matlab 复制代码
function net=Creat_1D_Discri(droprate,scale)
net = dlnetwork;

tempNet = [
    inputLayer([128 1 NaN],"SCB","Name","input")
    dropoutLayer(droprate,"Name","dropout")
    convolution1dLayer(3,32,"Name","conv1d","Padding","same","Stride",2)
    leakyReluLayer(scale,"Name","leakyrelu_1")
    convolution1dLayer(3,64,"Name","conv1d_1","Padding","same","Stride",2)
    batchNormalizationLayer("Name","batchnorm")
    leakyReluLayer(scale,"Name","leakyrelu_2")
    convolution1dLayer(3,128,"Name","conv1d_2","Padding","same","Stride",2)
    batchNormalizationLayer("Name","batchnorm_1")
    leakyReluLayer(scale,"Name","leakyrelu_3")
    convolution1dLayer(3,256,"Name","conv1d_3","Padding","same","Stride",2)
    batchNormalizationLayer("Name","batchnorm_1_1")
    leakyReluLayer(scale,"Name","leakyrelu_3_1")
    convolution1dLayer(3,512,"Name","conv1d_4","Padding","same","Stride",2)
    batchNormalizationLayer("Name","batchnorm_1_2")
    leakyReluLayer(scale,"Name","leakyrelu_3_2")
    convolution1dLayer(5,1,"Name","conv1d_5","Padding","same","Stride",4)
    sigmoidLayer("Name","layer")];
net = addLayers(net,tempNet);

% clean up helper variable
clear tempNet;

net = initialize(net);

plot(net);

具体参数如下

1.2.3数据预处理函数

预处理函数有比较明显的改动,1个是本次示例数据是int12的格式,所以我们这里归一化范围修改了。其次是样本凭借的维度(批次维度)为3,需要注意。同时我们需要调整数据的维度顺序,因为arraydatastore按第一个维度分割样本后的数据格式为1*128*1(CSB),为了对应深度学习模型的输入维度(SCB),在预处理前利用permute函数进行维度调整。

Matlab 复制代码
function X = preprocessMiniBatch12_2D(data)

% Concatenate mini-batch
X = cat(3,data{:});

%调整矩阵的维度,让数值回到空间通道中,通道在第二位置;
X=permute(X, [2, 1, 3]); 
% Rescale the images in the range [-1 1].
X = rescale(X,-1,1,InputMin=0,InputMax=2^12);

end

1.2.4 损失函数

无大变化:

反向传播与梯度计算

Matlab 复制代码
function [lossG,lossD,gradientsG,gradientsD,stateG,scoreG,scoreD] = ...
    modelLoss(netG,netD,X,Z,flipProb)

% Calculate the predictions for real data with the discriminator network.
YReal = forward(netD,X);
% Calculate the predictions for generated data with the discriminator
% network.
[XGenerated,stateG] = forward(netG,Z);
YGenerated = forward(netD,XGenerated);

% Calculate the score of the discriminator.
scoreD = (mean(YReal) + mean(1-YGenerated)) / 2;

% Calculate the score of the generator.
scoreG = mean(YGenerated);

% Randomly flip the labels of the real images.
numObservations = size(YReal,4);
idx = rand(1,numObservations) < flipProb;
YReal(:,:,:,idx) = 1 - YReal(:,:,:,idx);

% Calculate the GAN loss.
[lossG, lossD] = ganLoss(YReal,YGenerated);

% For each network, calculate the gradients with respect to the loss.
gradientsG = dlgradient(lossG,netG.Learnables,RetainData=true);
gradientsD = dlgradient(lossD,netD.Learnables);

end

损失函数:

Matlab 复制代码
function [lossG,lossD] = ganLoss(YReal,YGenerated)

% Calculate the loss for the discriminator network.
lossD = -mean(log(YReal)) - mean(log(1-YGenerated));

% Calculate the loss for the generator network.
lossG = -mean(log(YGenerated));

end

1.3 资源下载

脚本、函数文件与示例数据如下:

通过网盘分享的文件:24-1D_DCGAN_EXAMPLE.zip

链接: https://pan.baidu.com/s/1kxQ4Q3RCzLeeAgdQBWl9KQ?pwd=3wgy 提取码: 3wgy

2.总结

从信息论的角度进行分析,DCGAN 在基于先验知识(真实样本)的条件下尽可能地生成接 近真实的样本,这一过程并不会创造新信息,无法通过对抗过程来增加训练集基本特征的多样性。但对于样本 多样性而言,DCGAN具有基于现有特征进行缩放及组 合以形成更多具有特异性高级特征的能力,因此它具有强化预测模型的泛化能力的潜力,提高模型对特征挖掘和学习能力,但这也导致DCGAN在过少的训练集(基本特征不足)或足够丰富的训练集(高级特征充足)的场景下, 很难带来显著的预测性能效果提升[2].

[2] 光谱技术结合水分校正与样本增广的棉田土壤盐分精准反演 - 中国知网

该项目详细展示和分析了在MATLAB中利用DCGAN生成1D数据的方法和注意事项,欢迎大家进行交流。

相关推荐
JianminZheng2 小时前
灰狼优化算法
算法
初晴~2 小时前
【动态规划】打家劫舍类问题
java·数据结构·c++·python·算法·leetcode·动态规划
自信人间三百年3 小时前
数据结构与算法-前缀和数组
java·数据结构·算法·leetcode
说私域3 小时前
私域流量圈层在新消费时代的机遇与挑战:兼论开源 AI 智能名片、2 + 1 链动模式、S2B2C 商城小程序的应用
人工智能·小程序
小森( ﹡ˆoˆ﹡ )3 小时前
词嵌入方法(Word Embedding)
人工智能·机器学习·自然语言处理·nlp·word·embedding
阿牛牛阿6 小时前
多模态大模型(1)--CLIP
算法·机器学习·ai·aigc
想成为高手4996 小时前
成功男人背后的女人--解析AIGC幕后的算法原理
算法·aigc
凡人的AI工具箱6 小时前
15分钟学 Go 第 49 天 :复杂项目开发
开发语言·人工智能·后端·算法·golang
FFDUST6 小时前
C++ 优先算法 —— 四数之和(双指针)
c语言·开发语言·c++·算法·leetcode·1024程序员节
python1566 小时前
基于驾驶员面部特征的疲劳检测系统
python·深度学习·目标检测