first
含义是计算机内包含一组处理单元(PE),每一个处理单元存储一个(或多个)数据元素。当机器执行顺序程序时,可对应于全部或部分的内部处理单元所存的数据同时操作。
将并行处理技术引入信息检索领域
把数据划分成若干块分别映像到不同的处理机上,每一台处理机运行同样的处理程序对所分派的数据进行处理。
数据级并行依赖于并行处理机,它属于SIMD系统内的并行。
特点是重复设置许多个同样的处理单元
在这种并行模式中,被划分的是数据,所以这种并行方式叫数据并行。
数据并行的实例运用(PyTorch)
有两种主要方法
使用mscorlib.dll 下的System.Threading.Parallel 类
使用 System.Core.dll下的 System.Linq.ParallelEnumerable 类
.NET 4.0
from 数据并行(Data Parallelism)
深度学习中
任务切分
数据并行的模型训练中,训练任务被切分到多个进程(设备)上,每个进程维护相同的模型参数和相同的计算任务,但是处理不同的数据(batch data)。
数据并行可通过增加并行训练设备来提高训练吞吐量
输入数据切分整个训练数据集:
- 根据并行进程数划分,每个进程只读取自身切分的数据
- 读取仅由具体某个进程负责, 根据并行进程数划分,再将不同数据块发送到对应进程上
即
- 划分 -> 读取
- 读取(rank0) -> 划分 -> 发送
1相对2不需要进行数据通信,训练效率更高
飞桨框架中默认为1
参数同步
之后让模型参数同步
梯度更新过程
每个进程处理不同的数据会得到不同的Loss
由Loss计算反向梯度并更新模型参数后,要保证进程间模型参数正确同步
初始相同的实现方法:
- 相同的随机种子+相同的顺序 初始化所有参数
- 具体进程初始化全部模型参数 + 广播
前/反向计算
每个进程根据自身得到的输入数据独立前向计算
每个进程根据自身的前向计算独立进行反向计算
反向中会计算出不同的梯度,
所以更新前对所有进程上的梯度进行同步
使用相同的全局梯度
(可通过Allreduce sum同步通信操作实现的
Allreduce sum操作后每个进程上得到的梯度是相同的,这时候的梯度值等于所有进程上梯度对应位置相加的和,然后每个进程用Allreduce后的梯度和除以数据并行中的进程数,这样得到的梯度是同步之前所有进程上梯度的平均值。
参数更新
得到相同全局梯度,后独立地完成参数更新
注意问题
使用Allreduce同步通信操作来实现所有进程间梯度同步,要求数据在各进程间的切分要做到尽量均匀
- 要求所有进程每个训练step 输入的local batch size 大小相同。
- 要保证所有进程上分配到相同的batch 数量。
优化
优化技巧
通信融合
通过减少通信频率来实现减少总的通信消耗
通信融合是,通过将N个梯度的Allreduce 通信合并成一次Allreduce 通信,可以减少N-1 次通信延迟时间。
通信前将多个梯度tensors 拼接成一个内存地址连续的大tensor,梯度同步时仅对拼接后的大tensor 做一次Allreduce 操作。
参数更新时将大tensor切分还原回之前的多个小tensors, 完成每个梯度对应参数的更新。
通信计算重叠
通信和计算可以并行,让两者的耗时相互重叠掩盖,减少反向的耗时。调度到不同的流(stream)上实现的.
ps. more LARS 和 LAMB 等 layer-wise-lr-adaptive 优化算法。
pytorch数据并行
PyTorch数据并行
单gpu
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
多gpu,DataParallel使用
#device_ids = [0,1,2,3]
os.environ['CUDA_VISIBLE_DEVICES'] == '0,5'
或者
CUDA_VISIBLE_DEVICES=1,2,3 python
more
.cuda()函数
返回一个存储在CUDA内存中的复制,其中device可以指定cuda设备。
ps.
os.environ[“CUDA_VISIBLE_DEVICES”]的使用
程序开头多加一条语句 os.environ[“CUDA_VISIBLE_DEVICES”] = “1,2”,作用是只允许gpu1和gpu2可用
Model = nn.DataParallel(Model, device_ids=[0,1]),作用是从可用的两个gpu中搜索第0和第1个位置的gpu
资料:
数据并行:提升训练吞吐的高效方法|深度学习分布式训练专题
pytorch(分布式)数据并行个人实践总结——DataParallel/DistributedDataParallel