主要内容

forward

R2026b

计算深度学习网络输出以进行训练

描述

一些深度学习层在训练期间的行为和其在推断(预测)期间的行为是不同的。例如,在训练期间,丢弃层会随机将输入元素设置为零以帮助防止过拟合,但在推断期间,丢弃层不会更改输入。类似地,批量归一化层在训练期间使用小批量统计量进行归一化,但在推断期间使用训练得到的均值和方差。

要计算网络输出以进行训练,请使用 forward 函数。要计算网络输出以进行推断,请使用 predict 函数。

[Y1,...,YN] = forward(net,X1,...,XM) 在给定输入数据 X1, …, XM 和神经网络 net 的情况下,返回用于训练的网络输出 Y1, …, YN。

示例

[Y1,...,YN,state] = forward(net,X1,...,XM) 还返回更新后的网络状态。

[Y1,...,YN,state,pruningActivations] = forward(net,X1,...,XM) 还返回由剪枝层的激活值组成的元胞数组。此语法仅在 net 为 TaylorPrunableNetwork 对象时才适用。

要对深度神经网络进行剪枝,您需要 Deep Learning Toolbox™ Model Compression Library 支持包。该支持包是一项免费附加功能,您可以使用附加功能资源管理器进行下载。或者,请参阅 Deep Learning Toolbox Model Compression Library。

___ = forward(___,Name=Value) 使用一个或多个名称-值参量指定其他选项。

示例

全部折叠

此示例说明如何使用自定义学习率调度来训练对手写数字进行分类的网络。

您可以使用 trainnet 和 trainingOptions 函数训练大多数类型的神经网络。如果 trainingOptions 函数没有提供您需要的选项(例如,自定义求解器),则您可以定义自己的自定义训练循环,使用 dlarray 和 dlnetwork 对象进行自动微分。有关说明如何使用 trainnet 函数重新训练已经过预训练的深度学习网络的示例,请参阅重新训练神经网络以对新图像进行分类。

训练深度神经网络是一项优化任务。通过将神经网络视为 f(X;θ) 函数(其中 X 是网络输入,而 θ 是可学习参数集),您可以优化 θ,以便根据训练数据最小化某些损失值。例如,优化可学习参数 θ,以便对于给定的输入 X 和对应的目标值 T,它们可以最小化预测值 Y=f(X;θ) 和 T 之间的误差。

使用的损失函数取决于任务的类型。例如:

  • 对于分类任务,您可以最小化预测值和目标值之间的交叉熵误差。

  • 对于回归任务,您可以最小化预测值和目标值之间的均方误差。

您可以使用梯度下降算法来优化目标,即:使用损失函数相对于可学习参数的梯度来逐步接近最小值,以通过迭代更新可学习参数 θ 来最小化损失 L。梯度下降算法通常使用 θt+1=θt-ρ∇L 形式的更新步长变体来更新可学习参数,其中 t 是迭代序号,ρ 是学习率,∇L 表示梯度(损失函数相对于可学习参数的导数)。

此示例使用随机梯度下降算法(不带动量)训练网络对手写数字进行分类。

加载训练数据

使用 imageDatastore 函数将位数数据加载为图像数据存储,并指定包含图像数据的文件夹。

unzip("DigitsData.zip")

imds = imageDatastore("DigitsData", ...
    IncludeSubfolders=true, ...
    LabelSource="foldernames");

将数据划分为训练集和测试集。留出 10% 的数据用于使用 splitEachLabel 函数进行测试。

[imdsTrain,imdsTest] = splitEachLabel(imds,0.9,"randomize");

此示例中使用的网络需要大小为 28×28×1 的输入图像。要自动调整训练图像的大小,请使用增强的图像数据存储。指定要对训练图像额外执行的增强操作:在水平和垂直坐标区上随机平移图像最多 5 个像素。数据增强有助于防止网络过拟合和记忆训练图像的具体细节。

inputSize = [28 28 1];
pixelRange = [-5 5];

imageAugmenter = imageDataAugmenter( ...
    RandXTranslation=pixelRange, ...
    RandYTranslation=pixelRange);

augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain,DataAugmentation=imageAugmenter);

要在不执行进一步数据增强的情况下自动调整测试图像的大小,请使用增强的图像数据存储,而不指定任何其他预处理操作。

augimdsTest = augmentedImageDatastore(inputSize(1:2),imdsTest);

确定训练数据中类的数量。

classes = categories(imdsTrain.Labels);
numClasses = numel(classes);

定义网络

定义用于图像分类的网络。

  • 对于图像输入,请指定输入大小与训练数据匹配的图像输入层。

  • 不对图像输入进行归一化,将输入层的 Normalization 选项设置为 "none"。

  • 指定三个 convolution-batchnorm-ReLU 模块。

  • 通过将 Padding 选项设置为 "same",填充卷积层的输入,使输出具有相同的大小。

  • 对于第一个卷积层,指定 20 个大小为 5 的滤波器。对于其余卷积层,指定 20 个大小为 3 的滤波器。

  • 对于分类,指定一个大小与类数目匹配的全连接层

  • 要将输出映射到概率,请包括一个 softmax 层。

使用自定义训练循环训练网络时,不要包含输出层。

layers = [
    imageInputLayer(inputSize,Normalization="none")
    convolution2dLayer(5,20,Padding="same")
    batchNormalizationLayer
    reluLayer
    convolution2dLayer(3,20,Padding="same")
    batchNormalizationLayer
    reluLayer
    convolution2dLayer(3,20,Padding="same")
    batchNormalizationLayer
    reluLayer
    fullyConnectedLayer(numClasses)
    softmaxLayer];

基于层数组创建一个 dlnetwork 对象。

net = dlnetwork(layers)
net = 
  dlnetwork with properties:

         Layers: [12×1 nnet.cnn.layer.Layer]
    Connections: [11×2 table]
     Learnables: [14×3 table]
          State: [6×3 table]
     InputNames: {'imageinput'}
    OutputNames: {'softmax'}
    Initialized: 1

  View summary with summary.

定义模型损失函数

训练深度神经网络是一项优化任务。通过将神经网络视为 f(X;θ) 函数(其中 X 是网络输入,而 θ 是可学习参数集),您可以优化 θ,以便根据训练数据最小化某些损失值。例如,优化可学习参数 θ,以便对于给定的输入 X 和对应的目标值 T,它们可以最小化预测值 Y=f(X;θ) 和 T 之间的误差。

定义 modelLoss 函数。modelLoss 函数接受 dlnetwork 对象 net、小批量输入数据 X和相应目标 T,并返回损失、损失相对于 net 中可学习参数的梯度以及网络状态。要自动计算梯度,请使用 dlgradient 函数。

function [loss,gradients,state] = modelLoss(net,X,T)

% Forward data through network.
[Y,state] = forward(net,X);

% Calculate cross-entropy loss.
loss = crossentropy(Y,T);

% Calculate gradients of loss with respect to learnable parameters.
gradients = dlgradient(loss,net.Learnables);

end

定义 SGD 函数

创建 sgdStep 函数,该函数采用参数和损失相对于参数的梯度,并使用随机梯度下降算法返回更新后的参数,表示为 θt+1=θt-ρ∇L,其中 t 是迭代序号,ρ 是学习率,∇L 表示梯度(损失相对于可学习参数的导数)。

function parameters = sgdStep(parameters,gradients,learnRate)

parameters = parameters - learnRate .* gradients;

end

定义自定义更新函数不是自定义训练循环的必要步骤。或者,您也可以使用内置更新函数,如 sgdmupdate、adamupdate 和 rmspropupdate。

指定训练选项

使用 128 的小批量大小和 0.01 的学习率进行十五轮训练。

numEpochs = 15;
miniBatchSize = 128;
learnRate = 0.01;

训练模型

创建一个 minibatchqueue 对象,用于在训练期间处理和管理小批量图像。对于每个小批量:

  • 使用自定义小批量预处理函数 preprocessMiniBatch(在此示例末尾定义)将目标值转换为 one-hot 编码向量。

  • 用维度标签 "SSCB"(空间、空间、通道、批量)格式化图像数据。默认情况下,minibatchqueue 对象将数据转换为基础类型为 single 的 dlarray 对象。不要格式化目标值。

  • 放弃部分小批量。

  • 在 GPU 上(如果有)进行训练。默认情况下,如果 GPU 可用,则 minibatchqueue 对象会将每个输出都转换为一个 gpuArray。使用 GPU 需要 Parallel Computing Toolbox™ 和支持的 GPU 设备。有关受支持设备的信息,请参阅GPU 计算要求 (Parallel Computing Toolbox)。

mbq = minibatchqueue(augimdsTrain,...
    MiniBatchSize=miniBatchSize,...
    MiniBatchFcn=@preprocessMiniBatch,...
    MiniBatchFormat=["SSCB" ""], ...
    PartialMiniBatch="discard");

计算训练进度监视器的总迭代次数。

numObservationsTrain = numel(imdsTrain.Files);
numIterationsPerEpoch = floor(numObservationsTrain / miniBatchSize);
numIterations = numEpochs * numIterationsPerEpoch;

初始化 TrainingProgressMonitor 对象。由于计时器在您创建监视器对象时启动,请确保您创建的对象靠近训练循环。

monitor = trainingProgressMonitor( ...
    Metrics="Loss", ...
    Info="Epoch", ...
    XLabel="Iteration");

使用自定义训练循环来训练网络。对于每轮训练,对数据进行乱序处理,并遍历小批量数据。对于每个小批量:

  • 使用 dlfeval 和 modelLoss 函数计算模型损失、梯度和状态,并更新网络状态。

  • 使用 dlupdate 函数和自定义更新函数更新网络参数。

  • 更新训练进度监视器中的损失值和轮数值。

  • 如果 monitor 的 Stop 属性为 true,则停止。当您点击“停止”按钮时,TrainingProgressMonitor 对象的 Stop 属性值会更改为 true。

epoch = 0;
iteration = 0;

% Loop over epochs.
while epoch < numEpochs && ~monitor.Stop
    
    epoch = epoch + 1;

    % Shuffle data.
    shuffle(mbq);
    
    % Loop over mini-batches.
    while hasdata(mbq) && ~monitor.Stop

        iteration = iteration + 1;
        
        % Read mini-batch of data.
        [X,T] = next(mbq);
        
        % Evaluate the model gradients, state, and loss using dlfeval and the
        % modelLoss function and update the network state.
        [loss,gradients,state] = dlfeval(@modelLoss,net,X,T);
        net.State = state;
        
        % Update the network parameters using SGD.
        updateFcn = @(parameters,gradients) sgdStep(parameters,gradients,learnRate);
        net = dlupdate(updateFcn,net,gradients);
        
        % Update the training progress monitor.
        recordMetrics(monitor,iteration,Loss=loss);
        updateInfo(monitor,Epoch=epoch);
        monitor.Progress = 100 * iteration/numIterations;
    end
end

测试模型

使用 testnet 函数测试神经网络。对于单标签分类,需评估准确度。准确度是指正确预测的百分比。默认情况下,testnet 函数使用 GPU(如果有)。要手动选择执行环境,请使用 testnet 函数的 ExecutionEnvironment 参量。

accuracy = testnet(net,augimdsTest,"accuracy")
accuracy = 
96.3000

在混淆图中可视化预测。使用 minibatchpredict 函数进行预测,并使用 scores2label 函数将分类分数转换为标签。默认情况下,minibatchpredict 函数使用 GPU(如果有)。要手动选择执行环境,请使用 minibatchpredict 函数的 ExecutionEnvironment 参量。

scores = minibatchpredict(net,augimdsTest);
YTest = scores2label(scores,classes);

在混淆图中可视化预测。

TTest = imdsTest.Labels;
figure
confusionchart(TTest,YTest)

对角线上的较大值表示相应类的预测准确。非对角线上的较大值表示相应类之间的严重混淆。

支持函数

小批量预处理函数

preprocessMiniBatch 函数使用以下步骤预处理小批量预测变量和标签:

  1. 使用 preprocessMiniBatchPredictors 函数预处理图像。

  2. 从传入的元胞数组中提取标签数据,并沿第二个维度串联成一个分类数组。

  3. 将分类标签 one-hot 编码为数值数组。编码到第一个维度会生成与网络输出形状匹配的编码数组。

function [X,T] = preprocessMiniBatch(dataX,dataT)

% Preprocess predictors.
X = preprocessMiniBatchPredictors(dataX);

% Extract label data from cell and concatenate.
T = cat(2,dataT{:});

% One-hot encode labels.
T = onehotencode(T,1);

end

小批量预测变量预处理函数

preprocessMiniBatchPredictors 函数从输入元胞数组中提取图像数据并串联成一个数值数组,以此预处理小批量预测变量。对于灰度输入,在第四个维度上进行串联会向每个图像添加第三个维度,以用作单一通道维度。

function X = preprocessMiniBatchPredictors(dataX)

% Concatenate.
X = cat(4,dataX{:});

end

输入参数

全部折叠

神经网络,指定为下列值之一:

要对深度神经网络进行剪枝,您需要 Deep Learning Toolbox Model Compression Library 支持包。该支持包是一项免费附加功能,您可以使用附加功能资源管理器进行下载。或者,请参阅 Deep Learning Toolbox Model Compression Library。

输入数据,每个输入数据指定为下列值之一:

  • 格式化的 dlarray 对象

  • 未格式化的 dlarray 对象 (自 R2025a 起)

  • 数值数组 (自 R2025a 起)

输入 Xi 对应于网络输入 net.InputNames(i)。

要使用自动微分通过自定义训练循环来训练神经网络,输入数据必须为格式化或未格式化的 dlarray 对象。

提示

神经网络需要输入数据具有特定的布局。例如,向量序列分类网络通常需要向量序列表示形式为 t×c 数组,其中 t 和 c 分别是序列的时间步数和通道数。神经网络通常具有一个输入层,用于指定数据的预期布局。

大多数数据存储和函数会以网络需要的布局输出数据。如果您的数据布局与网络预期的布局不同,则可通过使用 InputDataFormats 选项或将输入数据指定为格式化的 dlarray 对象来表明您的数据具有不同的布局。通常,调整 InputDataFormats 训练选项比预处理输入数据更为便捷。

有关详细信息,请参阅Deep Learning Data Formats。

要创建接收未格式化数据的神经网络,请使用 inputLayer 对象并且不指定格式。要将未格式化的数据直接输入网络,请不要指定 InputDataFormats 参量 (自 R2025a 起)。

在 R2025a 之前的版本中: 对于没有输入层的神经网络,您必须使用 InputDataFormats 参量指定一种格式。

名称-值参数

全部折叠

将可选参量对组指定为 Name1=Value1,...,NameN=ValueN,其中 Name 是参量名称,Value 是对应的值。名称-值参量必须出现在其他参量之后,但对各个参量对组的顺序没有要求。

示例: forward(net,X,Outputs=["relu1" "relu2"]) 指定从名称为 "relu1" 和 "relu2" 的层提取输出。

神经网络输出,指定为层名称或层输出路径的字符串数组或字符向量元胞数组。使用以下形式之一指定输出:

  • "layerName",其中 layerName 是具有单个输出的层的名称。

  • "layerName/outputName",其中 layerName 是层的名称,outputName 是层输出的名称。对于具有多个输出的层,请使用此选项。

要使用 networkLayer 对象内部的层的输出,请先使用 expandLayers 函数展开嵌套网络。有关详细信息,请参阅网络层提示。

如果您未指定要从中提取输出的层,则默认情况下,软件会使用 net.Outputs 指定的输出。

性能优化,指定为下列值之一:

  • "auto" - 自动应用适用于输入网络和硬件资源的多项优化。

  • "none" - 禁用所有优化。

使用 "auto" 加速选项可以提供性能优势,但会增加初始运行时间。使用兼容参数的后续调用会更快。当您计划使用大小和形状相同的不同输入数据多次调用函数时,请使用性能优化。

自 R2025a 起

输入数据维度的描述,指定为字符串数组、字符向量或字符向量元胞数组。

如果 InputDataFormats 为 "auto",则软件会使用网络输入所需要的格式。否则,软件会为对应的网络输入使用指定的格式。

深度学习数据格式是字符串,其中每个字符描述对应数据维度的类型。这些字符是:

  • "S" - 空间

  • "C" - 通道

  • "B" - 批量

  • "T" - 时间

  • "U" - 未指定

例如,假设您有一个表示一批序列的数组,其中第一个、第二个和第三个维度分别对应于通道、观测值和时间步。您可以将该数据描述为具有格式 "CBT"(通道、批量、时间)。

您可以指定多个标注为 "S" 或 "U" 的维度。每个 "C"、"B" 和 "T" 标签最多只能使用一次。该软件忽略第二个维度后的单一尾部 "U" 维度。

对于具有多个输入的神经网络 net,请指定一个输入数据格式数组,其中 InputDataFormats(i) 对应于输入 net.InputNames(i)。

有关详细信息,请参阅Deep Learning Data Formats。

要创建接收未格式化数据的神经网络,请使用 inputLayer 对象并且不指定格式。要将未格式化的数据直接输入网络,请不要指定 InputDataFormats 参量 (自 R2025a 起)。

在 R2025a 之前的版本中: 对于没有输入层的神经网络,您必须使用 InputDataFormats 参量指定一种格式。

数据类型: char | string | cell

自 R2025a 起

输出数据维度的描述,指定为下列值之一:

  • "auto" - 自动确定数据布局。

    • 如果网络输出格式化数据,则函数直接返回格式化的 dlarray。

    • 如果网络输出维度数与输入数据相同的未格式化数据,则函数使用 InputDataFormats 排序。

    • 如果网络输出维度数与输入数据不同的未格式化数据,则函数会对输出维度进行排列,使批量维度和时间维度排在通道维度之前。例如,对于包含通道和批量输出维度的网络,输出数组的大小为 numObservations×numChannels。此排序与默认 dlarray 维度排序不同,在默认维度排序中,"C"(通道)维度排在 "B"(批量)和 "T"(时间)维度之前。

  • 字符串、字符向量或字符向量元胞数组 - forward 函数使用指定的数据格式。

深度学习数据格式是字符串,其中每个字符描述对应数据维度的类型。这些字符是:

  • "S" - 空间

  • "C" - 通道

  • "B" - 批量

  • "T" - 时间

  • "U" - 未指定

例如,假设您有一个表示一批序列的数组,其中第一个、第二个和第三个维度分别对应于通道、观测值和时间步。您可以将该数据描述为具有格式 "CBT"(通道、批量、时间)。

您可以指定多个标注为 "S" 或 "U" 的维度。每个 "C"、"B" 和 "T" 标签最多只能使用一次。该软件忽略第二个维度后的单一尾部 "U" 维度。

有关详细信息,请参阅Deep Learning Data Formats。

数据类型: char | string | cell

输出参量

全部折叠

具有多个输出的网络的输出数据,以下列值之一的形式返回:

  • 格式化的 dlarray 对象

  • 未格式化的 dlarray 对象 (自 R2025a 起)

  • 数值数组 (自 R2025a 起)

数据类型与输入数据的数据类型匹配。

输出 Y1, …, YN 的顺序与 Outputs 参量指定的输出顺序匹配。

对于分类神经网络,输出的元素对应于每个类的分数。分数的顺序与训练数据中类别的顺序匹配。例如,如果您使用分类标签 TTrain 训练神经网络,则分数的顺序与 categories(TTrain) 给出的类别顺序匹配。

更新后的网络状态,以表形式返回。

网络状态是一个具有三列的表:

  • Layer - 层名称,指定为字符串标量。

  • Parameter - 状态参数名称,指定为字符串标量。

  • Value - 状态参数的值,指定为 dlarray 对象。

层状态保留在层运算期间计算的信息,以便在层的后续前向传导中使用。例如,LSTM 层包含单元状态和隐藏状态,批量归一化层计算运行统计量。

对于 HasStateInputs 属性设置为 1 (true) 的循环层(例如 LSTM 层),状态表不包含该层的状态条目。

使用 State 属性更新 dlnetwork 的状态。

如果输入网络为 TaylorPrunableNetwork 对象,则返回由剪枝层的激活值组成的元胞数组。

扩展功能

全部展开

版本历史记录

在 R2019b 中推出

全部展开