百度PaddlePaddle入门-14(多个CPU加速训练)

接下来介绍在paddlepaddle中如何使用多CPU来加速训练。

接着前面几节讲的手写数字识别部分,在启动训练前,加载数据和网络结构的代码部分均不变。

  1 # 加载相关库
  2 import os
  3 import random
  4 import paddle
  5 import paddle.fluid as fluid
  6 from paddle.fluid.dygraph.nn import Conv2D, Pool2D, FC
  7 import numpy as np
  8 from PIL import Image
  9
 10 import gzip
 11 import json
 12
 13 # 定义数据集读取器
 14 def load_data(mode=‘train‘):
 15
 16     # 读取数据文件
 17     datafile = ‘./work/mnist.json.gz‘
 18     print(‘loading mnist dataset from {} ......‘.format(datafile))
 19     data = json.load(gzip.open(datafile))
 20     # 读取数据集中的训练集,验证集和测试集
 21     train_set, val_set, eval_set = data
 22
 23     # 数据集相关参数,图片高度IMG_ROWS, 图片宽度IMG_COLS
 24     IMG_ROWS = 28
 25     IMG_COLS = 28
 26     # 根据输入mode参数决定使用训练集,验证集还是测试
 27     if mode == ‘train‘:
 28         imgs = train_set[0]
 29         labels = train_set[1]
 30     elif mode == ‘valid‘:
 31         imgs = val_set[0]
 32         labels = val_set[1]
 33     elif mode == ‘eval‘:
 34         imgs = eval_set[0]
 35         labels = eval_set[1]
 36     # 获得所有图像的数量
 37     imgs_length = len(imgs)
 38     # 验证图像数量和标签数量是否一致
 39     assert len(imgs) == len(labels),  40           "length of train_imgs({}) should be the same as train_labels({})".format(
 41                   len(imgs), len(labels))
 42
 43     index_list = list(range(imgs_length))
 44
 45     # 读入数据时用到的batchsize
 46     BATCHSIZE = 100
 47
 48     # 定义数据生成器
 49     def data_generator():
 50         # 训练模式下,打乱训练数据
 51         if mode == ‘train‘:
 52             random.shuffle(index_list)
 53         imgs_list = []
 54         labels_list = []
 55         # 按照索引读取数据
 56         for i in index_list:
 57             # 读取图像和标签,转换其尺寸和类型
 58             img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype(‘float32‘)
 59             label = np.reshape(labels[i], [1]).astype(‘int64‘)
 60             imgs_list.append(img)
 61             labels_list.append(label)
 62             # 如果当前数据缓存达到了batch size,就返回一个批次数据
 63             if len(imgs_list) == BATCHSIZE:
 64                 yield np.array(imgs_list), np.array(labels_list)
 65                 # 清空数据缓存列表
 66                 imgs_list = []
 67                 labels_list = []
 68
 69         # 如果剩余数据的数目小于BATCHSIZE,
 70         # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch
 71         if len(imgs_list) > 0:
 72             yield np.array(imgs_list), np.array(labels_list)
 73
 74     return data_generator
 75
 76
 77 # 定义模型结构
 78 class MNIST(fluid.dygraph.Layer):
 79      def __init__(self, name_scope):
 80          super(MNIST, self).__init__(name_scope)
 81          name_scope = self.full_name()
 82          # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
 83          self.conv1 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act=‘relu‘)
 84          # 定义池化层,池化核为2,采用最大池化方式
 85          self.pool1 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type=‘max‘)
 86          # 定义卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
 87          self.conv2 = Conv2D(name_scope, num_filters=20, filter_size=5, stride=1, padding=2, act=‘relu‘)
 88          # 定义池化层,池化核为2,采用最大池化方式
 89          self.pool2 = Pool2D(name_scope, pool_size=2, pool_stride=2, pool_type=‘max‘)
 90          # 定义全连接层,输出节点数为10,激活函数使用softmax
 91          self.fc = FC(name_scope, size=10, act=‘softmax‘)
 92
 93     # 定义网络的前向计算过程
 94      def forward(self, inputs):
 95          x = self.conv1(inputs)
 96          x = self.pool1(x)
 97          x = self.conv2(x)
 98          x = self.pool2(x)
 99          x = self.fc(x)
100          return x


单GPU训练

现实生活中,我们可能会遇到更复杂的机器学习、深度学习任务,需要运算速度更高的硬件(GPU、TPU),甚至同时使用多个机器共同训练一个任务(多卡训练和多机训练)。

飞桨动态图通过fluid.dygraph.guard(place=None)里的place参数,设置在GPU上训练还是CPU上训练,比如:

1 with fluid.dygraph.guard(place=fluid.CPUPlace()) #设置使用CPU资源训神经网络。
2 with fluid.dygraph.guard(place=fluid.CUDAPlace(0)) #设置使用GPU资源训神经网络,默认使用机器的第一个GPU。

下面是采用GPU训练实例(就是前三行):

 1 #仅前3行代码有所变化,在使用GPU时,可以将use_gpu变量设置成True
 2 use_gpu = True
 3 place = fluid.CUDAPlace(0) if use_gpu else fluid.CPUPlace()
 4
 5 with fluid.dygraph.guard(place):
 6     model = MNIST("mnist")
 7     model.train()
 8     #调用加载数据的函数
 9     train_loader = load_data(‘train‘)
10
11     #四种优化算法的设置方案,可以逐一尝试效果
12     optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01)
13     #optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=0.01)
14     #optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=0.01)
15     #optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.01)
16
17     EPOCH_NUM = 2
18     for epoch_id in range(EPOCH_NUM):
19         for batch_id, data in enumerate(train_loader()):
20             #准备数据,变得更加简洁
21             image_data, label_data = data
22             image = fluid.dygraph.to_variable(image_data)
23             label = fluid.dygraph.to_variable(label_data)
24
25             #前向计算的过程
26             predict = model(image)
27
28             #计算损失,取一个批次样本损失的平均值
29             loss = fluid.layers.cross_entropy(predict, label)
30             avg_loss = fluid.layers.mean(loss)
31
32             #每训练了100批次的数据,打印下当前Loss的情况
33             if batch_id % 200 == 0:
34                 print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
35
36             #后向传播,更新参数的过程
37             avg_loss.backward()
38             optimizer.minimize(avg_loss)
39             model.clear_gradients()
40
41     #保存模型参数
42     fluid.save_dygraph(model.state_dict(), ‘mnist‘)
loading mnist dataset from ./work/mnist.json.gz ......
epoch: 0, batch: 0, loss is: [3.2412765]
epoch: 0, batch: 200, loss is: [0.3588875]
epoch: 0, batch: 400, loss is: [0.21310554]
epoch: 1, batch: 0, loss is: [0.34854925]
epoch: 1, batch: 200, loss is: [0.22530955]
epoch: 1, batch: 400, loss is: [0.20724224]

多CPU分布式训练

在工业实践中,许多较复杂的任务需要使用更强大的模型。强大模型加上海量的训练数据,经常导致模型训练耗时严重。比如在计算机视觉分类任务中,训练一个在ImageNet数据集上精度表现良好的模型,大概需要一周的时间,因为我们需要不断尝试各种优化的思路和方案。如果每次训练均要耗时1周,这会大大降低模型迭代的速度。在机器资源充沛的情况下,我们可以采用分布式训练,大部分模型的训练时间可压缩到小时级别。

分布式训练有两种实现模式:模型并行和数据并行。

1. 模型并行

模型并行是将一个网络模型拆分为多份,拆分后的模型分到多个设备上(GPU)训练,每个设备的训练数据是相同的。 模型并行的方式一般适用于:

  1. 模型架构过大,完整的模型无法放入单个GPU。2012年ImageNet大赛的冠军模型AlexNet是模型并行的典型案例。由于当时GPU内存较小,单个GPU不足以承担AlexNet。研究者将AlexNet拆分为两部分放到两个GPU上并行训练。
  2. 网络模型的设计结构可以并行化时,采用模型并行的方式。例如在计算机视觉目标检测任务中,一些模型(YOLO9000)的边界框回归和类别预测是独立的,可以将独立的部分分在不同的设备节点上完成分布式训练。

说明:当前GPU硬件技术快速发展,深度学习使用的主流GPU的内存已经足以满足大多数的网络模型需求,所以大多数情况下使用数据并行的方式。

2. 数据并行

数据并行与模型并行不同,数据并行每次读取多份数据,读取到的数据输入给多个设备(GPU)上的模型,每个设备上的模型是完全相同的。数据并行的方式与众人拾柴火焰高的道理类似,如果把训练数据比喻为砖头,把一个设备(GPU)比喻为一个人,那单GPU训练就是一个人在搬砖,多GPU训练就是多个人同时搬砖,每次搬砖的数量倍数增加,效率呈倍数提升。但是注意到,每个设备的模型是完全相同的,但是输入数据不同,每个设备的模型计算出的梯度是不同的,如果每个设备的梯度更新当前设备的模型就会导致下次训练时,每个模型的参数都不同了,所以我们还需要一个梯度同步机制,保证每个设备的梯度是完全相同的。

数据并行中有一个参数管理服务器(parameter server)收集来自每个设备的梯度更新信息,并计算出一个全局的梯度更新。当参数管理服务器收到来自训练设备的梯度更新请求时,统一更新模型的梯度。

飞桨有便利的数据并行训练方式,仅改动几行代码即可实现多GPU训练,如果想了解飞桨数据并行的基本思想,可以参考官网文档-https://www.paddlepaddle.org.cn/documentation/docs/zh/user_guides/howto/training/cluster_howto.html

用户只需要对程序进行简单修改,即可实现在多GPU上并行训练。飞桨采用数据并行的实现方式,在训练前,需要配置如下参数:

1.从环境变量获取设备的ID,并指定给CUDAPlace

1 device_id = fluid.dygraph.parallel.Env().dev_id
2 place = fluid.CUDAPlace(device_id)

2.对定义的网络做预处理,设置为并行模式

1 strategy = fluid.dygraph.parallel.prepare_context() ## 新增
2 model = MNIST("mnist")
3 model = fluid.dygraph.parallel.DataParallel(model, strategy)  ## 新增

3.定义多GPU训练的reader,将每批次的数据平分到每个GPU上

1 valid_loader = paddle.batch(paddle.dataset.mnist.test(), batch_size=16, drop_last=true)
2 valid_loader = fluid.contrib.reader.distributed_batch_reader(valid_loader)

4.收集每批次训练数据的loss,并聚合参数的梯度

1 avg_loss = mnist.scale_loss(avg_loss)  ## 新增
2 avg_loss.backward()
3 mnist.apply_collective_grads()         ## 新增

完整程序如下所示。

 1 def train_multi_gpu():
 2
 3     ##修改1-从环境变量获取使用GPU的序号
 4     place = fluid.CUDAPlace(fluid.dygraph.parallel.Env().dev_id)
 5
 6     with fluid.dygraph.guard(place):
 7
 8         ##修改2-对原模型做并行化预处理
 9         strategy = fluid.dygraph.parallel.prepare_context()
10         model = MNIST("mnist")
11         model = fluid.dygraph.parallel.DataParallel(model, strategy)
12
13         model.train()
14
15         #调用加载数据的函数
16         train_loader = load_data(‘train‘)
17         ##修改3-多GPU数据读取,必须确保每个进程读取的数据是不同的
18         train_loader = fluid.contrib.reader.distributed_batch_reader(train_loader)
19
20         optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01)
21         EPOCH_NUM = 5
22         for epoch_id in range(EPOCH_NUM):
23             for batch_id, data in enumerate(train_loader()):
24                 #准备数据
25                 image_data, label_data = data
26                 image = fluid.dygraph.to_variable(image_data)
27                 label = fluid.dygraph.to_variable(label_data)
28
29                 predict = model(image)
30
31                 loss = fluid.layers.square_error_cost(predict, label)
32                 avg_loss = fluid.layers.mean(loss)
33
34                 # 修改4-多GPU训练需要对Loss做出调整,并聚合不同设备上的参数梯度
35                 avg_loss = mnist.scale_loss(avg_loss)
36                 avg_loss.backward()
37                 model.apply_collective_grads()
38                 # 最小化损失函数,清除本次训练的梯度
39                 optimizer.minimize(avg_loss)
40                 model.clear_gradients()
41
42                 if batch_id % 200 == 0:
43                     print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
44
45     #保存模型参数
46     fluid.save_dygraph(model.state_dict(), ‘mnist‘)

启动多GPU的训练,需要在命令行设置一些参数变量。打开终端,运行如下命令:

1 $ python -m paddle.distributed.launch --selected_gpus=0,1,2,3 --log_dir ./mylog train_multi_gpu.py
  • paddle.distributed.launch表示启动分布式运行。
  • 通过selected_gpus设置使用的GPU的序号。当前机器需要是多GPU卡的机器,通过命令watch nvidia-smi可以查看GPU的序号。
  • log_dir用于存放训练的log,如果不设置,每个GPU上的训练信息都会打印到屏幕。
  • 多GPU运行的脚本是:train_multi_gpu.py,包含上述修改过的train_multi_gpu()函数。

训练完成后,程序会在指定的./mylog文件夹下产生四个worklog文件。每个文件存放对应设备的训练过程日志,其中worklog.0的内容如下:

grep: warning: GREP_OPTIONS is deprecated; please use an alias or script
dev_id 0
I1104 06:25:04.377323 31961 nccl_context.cc:88] worker: 127.0.0.1:6171 is not ready, will retry after 3 seconds...
I1104 06:25:07.377645 31961 nccl_context.cc:127] init nccl context nranks: 3 local rank: 0 gpu id: 1?
W1104 06:25:09.097079 31961 device_context.cc:235] Please NOTE: device: 1, CUDA Capability: 61, Driver API Version: 10.1, Runtime API Version: 9.0
W1104 06:25:09.104460 31961 device_context.cc:243] device: 1, cuDNN Version: 7.5.
start data reader (trainers_num: 3, trainer_id: 0)
epoch: 0, batch_id: 10, loss is: [0.47507238]
epoch: 0, batch_id: 20, loss is: [0.25089613]
epoch: 0, batch_id: 30, loss is: [0.13120805]
epoch: 0, batch_id: 40, loss is: [0.12122715]
epoch: 0, batch_id: 50, loss is: [0.07328521]
epoch: 0, batch_id: 60, loss is: [0.11860339]
epoch: 0, batch_id: 70, loss is: [0.08205047]
epoch: 0, batch_id: 80, loss is: [0.08192863]
epoch: 0, batch_id: 90, loss is: [0.0736289]
epoch: 0, batch_id: 100, loss is: [0.08607423]
start data reader (trainers_num: 3, trainer_id: 0)
epoch: 1, batch_id: 10, loss is: [0.07032011]
epoch: 1, batch_id: 20, loss is: [0.09687119]
epoch: 1, batch_id: 30, loss is: [0.0307216]
epoch: 1, batch_id: 40, loss is: [0.03884467]
epoch: 1, batch_id: 50, loss is: [0.02801813]
epoch: 1, batch_id: 60, loss is: [0.05751991]
epoch: 1, batch_id: 70, loss is: [0.03721186]
.....

原文地址:https://www.cnblogs.com/yuzaihuan/p/12348467.html

时间: 2024-10-01 07:48:43

百度PaddlePaddle入门-14(多个CPU加速训练)的相关文章

百度PaddlePaddle入门-4

当习惯使用飞桨框架完成建模时,会发现程序呈现出“八股文”的形态.即不同的程序员使用不同模型解决不同任务的时候,他们编写的建模程序是极其相似的.虽然这在某些“极客”的眼里缺乏精彩,但从实用性的角度,这样的设计使建模者更关注需要解决的任务,而不是将精力投入在学习框架上.只要通过一个示例程序掌握使用飞桨的方法,编写实现不同任务的多种模型均变得十分容易. 这点与Python的设计思想一致:对于某个特定功能,并不是实现方式越灵活.越多样越好,最好只有一种最符合“道”的最佳实现.“道”指的是如何人类的思维习

百度PaddlePaddle入门-9

本节介绍使用飞桨快速实现“手写数字识别”的建模方法. 与“房价预测”的案例类似,我们以同样的标准结构实现“手写数字识别”的建模.在后续的课程中,该标准结构会反复出现,逐渐加深我们对深度学习模型的理解.深度学习模型的标准结构分如下五个步骤: 数据处理:读取数据和预处理操作. 模型设计:搭建神经网络结构. 训练配置:配置优化器.学习率.训练参数. 训练过程:循环调用训练过程,循环执行“前向计算 + 损失函数 + 反向传播”. 保存模型并测试:将训练好的模型保存并评估测试. 下面我们使用飞桨框架,按照

百度PaddlePaddle再获新技能 智能推荐、对话系统、控制领域都能搞定!

编辑文章 引言:人工智能技术越来越广泛的应用于各行各业,而这一切都离不开底层深度学习框架的支持.近日,百度深度学习PaddlePaddle正式发布了强化学习框架PARL,同时开源了基于该框架,在NeurIPS 2018强化学习赛事中夺冠的模型完整训练代码,再次向业界展示了百度在深度学习领域的技术能力. PARL的效果如何? PARL是基于百度 PaddlePaddle 打造的深度强化学习框架,覆盖了DQN.DDQN.Dueling DQN.DDPG.PPO等主流强化学习算法.在PARL 1.0的

百度PaddlePaddle常规赛NLP赛道火热开启

作为人工智能时代的基础,深度学习一直是人工智能最热门.企业投入最多的研究领域之一,百度PaddlePaddle深度学习框架应运而生,这是国内唯一一家拥有自主知识产权的开源深度学习框架.在此框架中,汇聚了更多的AI科学家.架构师.AI爱好者,设置常规赛,提供丰富的真实数据,多样的算法赛题,显示百度对深度学习框架战略地位的重视,让AI爱好者能够得到更多真实场景的练习机会和更多PaddlePaddle的实际训练经验,这势必推动PaddlePaddle更广泛.更深入地用于人工智能研发及落地应用. 目前已

TensorFlow指定GPU/CPU进行训练和输出devices信息

TensorFlow指定GPU/CPU进行训练和输出devices信息 1.在tensorflow代码中指定GPU/CPU进行训练 with tf.device('/gpu:0'): .... with tf.device('/gpu:1'): ... with tf.device('/cpu:0'): ... 2.输出devices的信息 在指定devices的时候往往不知道具体的设备信息,这时可用下面的代码查看对应的信息 进入Python环境 from tensorflow.python.c

[深度学习] Pytorch(三)—— 多/单GPU、CPU,训练保存、加载模型参数问题

[深度学习] Pytorch(三)-- 多/单GPU.CPU,训练保存.加载预测模型问题 上一篇实践学习中,遇到了在多/单个GPU.GPU与CPU的不同环境下训练保存.加载使用使用模型的问题,如果保存.加载的上述三类环境不同,加载时会出错.就去研究了一下,做了实验,得出以下结论: 多/单GPU训练保存模型参数.CPU加载使用模型 #保存 PATH = 'cifar_net.pth' torch.save(net.module.state_dict(), PATH) #加载 net = Net()

【深度学习系列】一起来参加百度 PaddlePaddle AI 大赛吧!

写这个系列写了两个月了,对paddlepaddle的使用越来越熟悉,不过一直没找到合适的应用场景.最近百度搞了个AI大赛,据说有四个赛题,现在是第一个----综艺节目精彩片段预测 ,大家可以去检测一下最近的学习成果啊!还有丰厚的奖金10W元软妹币哦! 这是啥比赛? 看比赛的要求,是希望参赛选手使用PaddlePaddle深度学习框架.利用BROAD数据集.利用K-Lab,着手解决行业中的真实问题,从而让AI真正应用于行业.真正服务于行业.本次大赛,我们将目光放在电视综艺行业,希望选手们利用BRO

PaddlePaddle入门-3

深度学习在很多机器学习领域均有非常出色的表现,在图像识别.语音识别.自然语言处理.机器人.网络广告投放.医学自动诊断和金融等各大领域有着广泛的应用.面对繁多的应用场景,深度学习框架可以节省大量而繁琐的外围工作,使建模者关注业务场景和模型设计本身. 使用深度学习框架完成建模任务有两个显著优势. 节省大量编写底层代码的精力:屏蔽底层实现,用户只需关注模型的逻辑结构,降低了深度学习入门门槛. 省去了部署和适配环境的烦恼:飞桨框架具备灵活的移植性,可将代码部署到CPU/GPU/移动端上,选择具有分布式性

数字图像处理之cpu加速(1)

在处理图像时,会经常对像素进行操作,实时性要求较高的场所往往会使用并行处理,好在(C/C++ API)支持多种并行方式:mpi,openmp,intel ipp 等,今天记录一种利用 openmp简单的并行处理图像方法:灰度图像取反. 需要用到的头文件:#include “omp.h”,作者是基于opencv3.0处理的图片,cpu为赛扬E3200,双核. 话不多说上代码: #include "opencv2/opencv.hpp" #include "omp.h"