分布式并行模块总结
分布式并行模块
1、分布式并行训练的优势
在深度学习发展的过程中为了更好的网络学习能力和泛化能力,数据集和模型规模都呈指数式提高。在NLP领域随着Transformer层的堆叠,模型的精度确实有所提高,但与此同时,模型参数所需的内存很快达到了性能上线。在人脸识别领域,因为全连接层的参数规模收到分类数量的影响,因此大规模人脸识别的参数也受到了内存的限制。而在推荐领域,由于人类网络活动的增加,使得基础数据的特征过多,在较为经典的wide&deep等模型中会使得模型头部的Embedding层规模巨大。
分布式并行训练,可以降低对内存、计算性能等硬件的需求,是进行训练的重要优化手段
2、并行类型
1、数据并行:对数据进行切分的并行模式,一般按照batch维度切分,将数据分配到各个计算单元中,进行模型计算。
2、模型并行:对模型进行切分的并行模式。MindSpore中支持层内模型并行模式,对参数切分后分配到各个计算单元中进行训练。
3、混合并行:涵盖数据并行和模型并行的并行模式。
3、MindSpore支持的多种模式
当前MindSpore也提供分布式并行训练的功能。它支持了多种模式包括:
DATA_PARALLEL
:数据并行模式。AUTO_PARALLEL
:自动并行模式,融合了数据并行、模型并行及混合并行的1种分布式并行模式,可以自动建立代价模型,为用户选择1种并行模式。其中,代价模型指围绕Ascend 910芯片基于内存的计算开销和通信开销对训练时间建模,并设计高效的算法找到训练时间较短的并行策略。
4、需配置环境
在裸机环境(对比云上环境,即本地有Ascend 910 AI 处理器)进行分布式训练时,需要配置当前多卡环境的组网信息文件。MindSpore分布式并行训练的通信使用了华为集合通信库Huawei Collective Communication Library
(以下简称HCCL),可以在Ascend AI处理器配套的软件包中找到。同时mindspore.communication.management
中封装了HCCL提供的集合通信接口,方便用户配置分布式信息。
5、优秀代码解析
Status L2NormalizeInfo::InferMirrorOps() {
mirror_ops_.clear(); // 清除mirror
Shape input_tensor_map = inputs_tensor_map_.at(0);
std::vector<Group> input_group;
// 创建组失败
if (CreateGroupByTensorMap(input_tensor_map, &input_group) != SUCCESS) {
MS_LOG(ERROR) << name_ << " : Create group failed.";
return FAILED;
}
OperatorVector op_for_weight;
// 镜像操作为空
if (input_group.empty()) {
MS_LOG(INFO) << name_ << " : The mirror ops is empty.";
return SUCCESS;
} else {
op_for_weight = CreateMirrorOps(input_group[0].name(), input_group[0].GetDevNum());
mirror_ops_.push_back(op_for_weight);
// 创建镜像操作成功,组为input_group[0]
MS_LOG(INFO) << name_ << " : Create the mirror ops success, the group is " << input_group[0].name();
}
return SUCCESS;
}
Status L2NormalizeInfo::GenerateStrategies(int64_t stage_id) {
// 获取属性失败
if (GetAttrs() != SUCCESS) {
MS_LOG(ERROR) << name_ << " : GetAttrs failed.";
return FAILED;
}
Shape input0_split(inputs_shape_[0].size() - 1, 1);
int64_t axis_index = axis_;
if (axis_ < 0) {
size_t input_dim = inputs_shape_.at(0).size();
axis_index = static_cast<int64_t>(input_dim) + axis_;
}
(void)input0_split.insert(input0_split.begin() + axis_index, 0);
Shapes splittable_inputs = {input0_split};
std::vector<StrategyPtr> sp_vector;
// 生成策略失败
if (GenerateStrategiesForIndependentInputs(stage_id, inputs_shape_, splittable_inputs, &sp_vector) != SUCCESS) {
MS_LOG(ERROR) << name_ << " : Generate strategies failed.";
return FAILED;
}
size_t success = 0;
for (auto &sp : sp_vector) { // 遍历sp_vector
if (SetCostUnderStrategy(sp) == SUCCESS)