主要内容

使用自动多 GPU 支持训练网络

R2026b

此示例说明如何使用自动并行支持在本地计算机上使用多个 GPU 进行深度学习训练。

训练深度学习网络通常需要几个小时或几天的时间。借助并行计算,您可以使用多个 GPU 加快训练速度。要了解有关并行训练选项的详细信息,请参阅Scale Up Deep Learning in Parallel, on GPUs, and in the Cloud。

下载数据集

Flowers 数据集包含 3670 个 224×224 大小的花卉图像,这些图像属于五类(雏菊、蒲公英、玫瑰、向日葵和郁金香)。下载并提取数据集。

url = "http://download.tensorflow.org/example_images/flower_photos.tgz";
downloadFolder = tempdir;
filename = fullfile(downloadFolder,"flower_dataset.tgz");

dataFolder = fullfile(downloadFolder,"flower_photos");

if ~exist(dataFolder,"dir")
    fprintf("Downloading Flowers data set (218 MB)... ")
    websave(filename,url);
    untar(filename,downloadFolder)
    fprintf("Done.\n")
end
Downloading Flowers data set (218 MB)... 
Done.

加载和拆分数据集

使用 imageDatastore 对象加载数据集,并调整所有图像的大小,使其具有一致的大小。预先调整图像的大小(而不是每次训练加载图像时调整图像的大小)可以减少不必要的处理。

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

imageSize = [224 224];

resizedImages = dir(fullfile(dataFolder,"flower_photos","**","*.png"));
if isempty(resizedImages)
    tds = transform(imds,@(x) imresize(x,imageSize));

    writeall(tds,dataFolder, ...
        OutputFormat="png", ...
        FolderLayout="duplicate");
end

imdsUniform = imageDatastore(dataFolder, ...
    IncludeSubfolders=true, ...
    LabelSource="foldernames");

将数据分成训练集 (90%) 和测试集 (10%)。

[imdsTrain,imdsTest] = splitEachLabel(imdsUniform,0.9,"randomized");

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

要使用增强的图像数据训练网络,请创建 augmentedImageDatastore 对象。使用随机平移和水平翻转。数据增强有助于防止网络过拟合和记忆训练图像的具体细节。

pixelRange = [-30 30];
imageAugmenter = imageDataAugmenter( ...
    RandXReflection=true, ...
    RandXTranslation=pixelRange, ...
    RandYTranslation=pixelRange);
augmentedImdsTrain = augmentedImageDatastore(imageSize,imdsTrain, ...
    DataAugmentation=imageAugmenter);

定义网络架构和训练选项

定义 ResNet-50 网络,并调整输出类的数量,使其与数据集相匹配。

net = imagePretrainedNetwork("resnet50",NumClasses=numClasses,Weights="none");

指定训练选项。

  • 通过将执行环境设置为 "multi-gpu",使用多个 GPU 训练网络。当您使用多个 GPU 时,就增加了可用的计算资源。根据 GPU 的数量扩大小批量大小,以保持每个 GPU 上的工作负载不变。根据小批量大小缩放学习率。在 GPU 上进行训练需要 Parallel Computing Toolbox™ 许可证和受支持的 GPU 设备。有关受支持设备的信息,请参阅GPU 计算要求 (Parallel Computing Toolbox)。

  • 使用学习率调度,以随着训练的进行降低学习率。

  • 打开训练进度图可在训练过程中获得可视化的反馈数据。

numGPUs = gpuDeviceCount("available")
numGPUs = 
4
miniBatchSize = 128*numGPUs;
initialLearnRate = 1e-2*miniBatchSize/64;

options = trainingOptions("adam", ...
    ExecutionEnvironment="multi-gpu", ...
    InitialLearnRate=initialLearnRate, ...
    MiniBatchSize=miniBatchSize, ...
    Verbose=false, ...
    Plots="training-progress", ...
    Metrics="accuracy", ...
    MaxEpochs=80, ...
    Shuffle="every-epoch", ...
    ValidationData=augmentedImageDatastore(imageSize,imdsTest), ...
    ValidationFrequency=floor(4*numel(imdsTrain.Files)/miniBatchSize), ...
    LearnRateSchedule="piecewise", ...
    LearnRateDropFactor=0.1, ...
    LearnRateDropPeriod=50);

训练网络

使用 trainnet 函数训练神经网络。对于分类,使用交叉熵损失。

net = trainnet(augmentedImdsTrain,net,"crossentropy",options);
Starting parallel pool (parpool) using the 'Processes' profile ...
Connected to parallel pool with 4 workers.

自动多 GPU 支持可以利用多个 GPU 来加快网络训练速度。下图显示在具有四个 NVIDIA® A5000 的 Linux 计算机上,GPU 的数量对整个训练时间的加速情况。您观察到的加速将取决于您的硬件和代码。通常,计算密集程度更高的训练(例如涉及大图像的训练)使用多个 GPU 时受益更多。

要验证训练是否有效地使用了所有可用的 GPU,您可以使用 GPU Monitor (Parallel Computing Toolbox)。GPU 监控程序会实时显示您计算机中每个 GPU 的 GPU 利用率、内存使用量和进程。

测试网络

对测试图像进行分类。要使用多个 GPU 进行预测,请划分数据,使用并行方式进行预测。

确定测试数据集中的观测值总数。

numObservations = numel(imdsTest.Files);

在此示例中,可以使用在训练期间打开的并行池。如果您尚未打开并行池,请打开一个工作单元数量与 GPU 数量一样多的并行池。

parpool("Processes",numGPUs);

使用 parfor (Parallel Computing Toolbox) 对图像进行并行分类。parfor 循环与 for 循环类似,但循环迭代是在并行池中的工作单元上并行执行的。在 parfor 循环内:

  • 使用 subset 函数选择测试数据的子集。

  • 使用 minibatchpredict 函数基于该子集进行预测。minibatchpredict 函数自动使用 GPU(如果有)。否则,该函数使用 CPU。

  • 使用 scores2label 函数将预测分数转换为标签。

parfor idx = 1:numGPUs
	startIdx = ceil((idx-1)*numObservations/numGPUs) + 1;
    endIdx = ceil(idx*numObservations/numGPUs);
    subdsTest = subset(imdsTest,startIdx:endIdx);
    augSubdsTest = augmentedImageDatastore(imageSize,subdsTest);

    scoresTest = minibatchpredict(net,augSubdsTest,MiniBatchSize=miniBatchSize);
    YTest{idx} = scores2label(scoresTest,classNames);
end

将预测结果收集到单个数组中。

YTest = cat(1,YTest{:});

确定网络的准确度并绘制混淆图。

accuracy = sum(YTest==imdsTest.Labels)/numel(imdsTest.Labels)
accuracy = 
0.8000
confusionchart(imdsTest.Labels,YTest)

另请参阅

| | |

主题