mshadow-ps 两级参数服务器接口实战:从多 GPU 梯度聚合到分布式异步训练

发布时间:2026/9/20 12:55:40

mshadow-ps 两级参数服务器接口实战:从多 GPU 梯度聚合到分布式异步训练 人工智能深度学习机器学习【免费下载链接】mxnetLightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more项目地址https://gitcode.com/gh_mirrors/mxne/mxnet点击查看免费下载mshadow-ps 是 mshadow 张量库内置的参数服务器Parameter Server插件为 GPU/CPU Tensor 提供异步的跨设备、跨机器参数同步接口。本文以 mshadow-ps 指南文档 为核心结合 mshadow_ps.h 等源码与 guide/mshadow-ps 目录下的完整可编译示例讲解两级参数服务器架构、ISharedModel核心接口的异步语义、服务器端权重更新机制并给出从单机多 GPU 到分布式训练的完整实战代码。读完本文你将能够用 mshadow-ps 写出计算与同步相互重叠的多卡/多机深度学习程序。两级参数服务器架构为不同层级选择不同一致性模型mshadow-ps 的设计目标是让多 GPU与分布式深度学习以一种简单且统一的方式实现。它实现的是一个两级参数服务器其架构如下图片来自 guide/mshadow-ps/2-levels.png架构要点Worker 节点通常一张 GPU 卡或一个 CPU 核运行一个 worker 节点图中每个 process 内的 dev 0~3。Level-1 Server同一台机器内的 worker 节点先与本地 Level-1 Server 通信完成机内参数同步与聚合。Level-2 Server跨机器的通信经由 Level-2 Server 完成。设计动机是同一台机器内 worker 之间的带宽和延迟通常比跨机器的好一个数量级约 10x。通过两级结构可以在不同层级使用不同的一致性模型从而更好地权衡算法收敛效率与系统性能。例如Level-1 使用顺序一致性模型即 BSPBulk Synchronous Parallel来保证算法收敛Level-2 使用最终一致性模型来隐藏网络延迟。该设计细节可参见 mshadow-ps 作者在 OSDI14 发表的论文论文标题与作者信息可查 mshadow 仓库历史与 README 提及内容此处不展开外部链接。从源码角度看两级模型对应 ps_local-inl.h机内多线程实现与 ps_dist-inl.h分布式实现两个实现文件此外还有基于 rabit allreduce 的 ps_rabit-inl.h。工厂函数 CreateSharedModel 根据传入的local或dist字符串选择具体实现local单机模式返回LocalModel若MSHADOW_RABIT_PS开启且当前运行在 rabit 分布式环境中则返回RabitModel单机内 allreduce 不产生额外开销。dist分布式模式返回DistModelMSHADOW_DIST_PS宏默认开启定义见 mshadow_ps.h#L37-L45。核心接口ISharedModel 的四个关键操作在使用前先熟悉ISharedModel接口。它定义在 mshadow_ps.h#L55-L278模板参数为设备类型xpumshadow::cpu/mshadow::gpu和元素类型DType默认float。接口中有四个关键函数函数源码位置语义InitKey(shape, key, devid)mshadow_ps.h#L99-L103为特定 Tensor 形状分配一个 key向参数服务器注册该 key 的形状使用某个 key 之前必须调用Push(data, key, devid, priority0)mshadow_ps.h#L137-L143把本地数据推送到同步接口不同设备推入的同一 key 数据会被聚合Push 是异步调用立即返回PullReq(data, key, devid, priority0, callback, callback_arg)mshadow_ps.h#L159-L168请求把同步结果拷贝回data在默认本地场景下同步结果是被推入数据之和也支持服务器端权重更新此时 PullReq 取回的是更新后的权重而非梯度之和同样异步PullWait(key, devid)mshadow_ps.h#L111阻塞等待对应 key 的 pull 请求完成若没有未完成的 pull 请求则直接返回priority参数表示操作优先级数值越大优先级越高。另外ISharedModel还提供SetParam(name, val)配置接口mshadow_ps.h#L74、CheckWeight调试接口mshadow_ps.h#L120-L125以及 C11 下的 lambda 回调重载mshadow_ps.h#L183-L193。这套接口最关键的性质是Push与PullReq都是异步的。只要梯度一就绪就可以调用它们mshadow-ps 会在后台完成数据同步当真正需要同步结果时再调用PullWait阻塞等待任务完成。这种设计允许我们在Push/PullReq与PullWait之间插入额外的计算让计算与同步相互重叠。实战一单机多 GPU 梯度求和local_sum编译配置local_sum-inl.h 是完整的入门示例。local_sum.cpp与local_sum.cu分别是 CPU 与 GPU 的入口Runmshadow::cpu/Runmshadow::gpu。编译方式先按本机环境修改 config.mk然后在 guide/mshadow-ps 目录下执行make。config.mk 中的关键开关# whether use CUDA during compile USE_CUDA 0 # add the path to CUDA libary to link and compile flag USE_CUDA_PATH NONE # choose the version of blas you want to use: mkl, blas, atlas, openblas, apple USE_BLAS blas # whether compile with parameter server (分布式模式需改为 1) USE_DIST_PS 0 PS_PATH ../../../parameter_server/ # whether compile with rabit allreduce USE_RABIT_PS 1 RABIT_PATH ../../rabitMakefile 会根据这些开关生成目标单机模式产出local_sum.cpuGPU 目标为local_sum.gpu当USE_DIST_PS1时产物切换为dist_async_sum.cpu并追加-lunwind链接选项。程序解析示例中每个线程在本地做少量计算后通过 mshadow-ps 接口获取data的求和结果// this function is runed by specific thread templatetypename xpu inline void RunWorkerThread(int devid, mshadow::ps::ISharedModelxpu, float *ps) { // initialize tensor engine mshadow::InitTensorEnginexpu(devid); mshadow::Streamxpu *stream mshadow::NewStreamxpu(); // allocate tensor on xpu mshadow::TensorContainerxpu, 2 data(mshadow::Shape2(2, 3)); // set the computation stream to the new allocated stream // this will make subsequent computation whose target is data // to use the stream, stream is needed for async execution in GPU data.set_stream(stream); // assume these operations sets the content of dataient data[0] 1.0f; data[1] devid data[0]; printf(dev%d: before sync, data:\n, devid); // use print to show result, do not call // print normally since Copy will block Print(data); printf(\n); // intiaialize the key, register the shape on parameter server ps-InitKey(data[0].shape_, 0, devid); ps-InitKey(data[1].shape_, 1, devid); // push data[0] out, for update, or aggregation // 0 is the key of the data, devid is the current device id ps-Push(data[0], 0, devid); // pull request is used to request the data to be copied back // once computation is done ps-PullReq(data[0], 0, devid); // computation can be done here.. // the pull request handler will be overlapped with // similar as previous call ps-Push(data[1], 1, devid); ps-PullReq(data[1], 1, devid); // more computation can be done here... // the computation will be overlapped // PullWait will block until these request finishes ps-PullWait(0, devid); ps-PullWait(1, devid); printf(dev%d: after sync, data:\n, devid); // use print to show result, do not call // print normally since Copy will block Print(data); printf(\n); mshadow::DeleteStream(stream); mshadow::ShutdownTensorEnginexpu(); }Run函数负责初始化与线程调度templatetypename xpu inline int Run(int argc, char *argv[]) { if (argc 2) { printf(Usage: device list\n\ \tfor CPU the device list can be arbitrary\n\ \tfor GPU the device list need to be actual device index\n); return 0; } // list of device ids std::vectorint devs; // initialization for (int i 1; i argc; i) { // record the device id devs.push_back(atoi(argv[i])); } mshadow::ps::ISharedModelxpu, float *ps mshadow::ps::CreateSharedModelxpu, float(local); // intiaialize the ps ps-Init(devs); // use openmp to launch #devs threads #pragma omp parallel num_threads(devs.size()) { int tid omp_get_thread_num(); RunWorkerThreadxpu(devs[tid], ps); } delete ps; return 0; }程序运行时传入设备列表作为参数如./local_sum.cpu 0 1 2CPU 下设备号可任意GPU 下必须是真实设备索引OpenMP会启动与设备数等量的线程每个线程在一个设备上运行RunWorkerThread。示例中每个设备推入的数据为data[0]1.0、data[1]devid1同步后各设备拿到的是所有设备推入数据之和。需要注意两点示例没有在服务器端做权重更新因此同步结果就是各设备推入数据的简单求和。输出打印不能直接调用常规Print因为Copy会阻塞异步流示例中的Print包装函数会先把数据拷贝到 CPU 侧临时容器再打印见 local_sum-inl.h#L28-L42。实战二多 GPU 两层神经网络nnet_ps.cu要更具体地理解接口的用法可以参考多 GPU 两层神经网络示例 guide/neuralnet/nnet_ps.cu修改自同目录下的nnet.cu。其核心思路一旦得到某一层的梯度就调用Push和PullReq在下一次对该层做前向之前调用PullWait这就在反向传播backprop与下一轮该层前向之间制造了一个时间滞后time lagmshadow-ps 会在该时间滞后内与计算并发地完成同步越靠后的层滞后越大而通常越靠后的层也越需要更多时间做同步参数更多两者自然匹配。nnet_ps.cu 中对 mshadow-ps 的使用还有几个值得注意的细节PullReq中的回调函数Callback可以给PullReq传一个回调在请求完成时被调用回调执行前线程上下文已切换到 pull 请求所在的设备回调签名void(Streamxpu *stream, void *arg)见 mshadow_ps.h#L66。示例把权重更新放在回调里在拿到梯度之和时立即执行更新C11 下还可直接传 lambdamshadow_ps.h#L183-L193。计算流Computing Stream受 GPU 编程模型约束必须使用非默认流进行计算。做法是对 mshadow tensor 调用set_stream把计算流设置为新建的流若想在忘记设置流时得到报错可用-DMSHADOW_FORCE_STREAM编译。数据集影响示例跑在 MNIST 上数据量很小多卡可能观察不到加速在更大规模任务上才能看到显著加速。进阶把权重更新移动到服务器端到目前为止的示例都是先用 mshadow-ps 拿到梯度聚合之和再在每张 GPU 上本地更新权重。mshadow-ps 更高级的用法是把权重更新搬到服务器上通信模式变为每个线程仍然调用Push推入梯度服务器端应用更新规则来更新权重每个线程调用PullReq从服务器拉回更新后的权重。这种更新模式更适合分布式场景。要做到这一点用户需要实现 IModelUpdater 接口——其核心虚方法是InitModel初始化 key 对应的模型与Update用收到的梯度更新模型——并在程序中定义如下CreateModelUpdater特化函数namespace mshadow { namespace ps { template IModelUpdaterfloat *CreateModelUpdater() { return new MyModelUpdater(); } } }在调用ISharedModel::Init之前用户还需要通过ps-SetParam(update_on_server, 1)开启服务器端更新模式。如果使用分布式共享模型则必须定义ModelUpdater否则服务器端无从更新。单机求和示例中不涉及服务器端更新也必须显式定义该函数并返回NULL见 local_sum-inl.h#L93-L103。从实现上看IModelUpdater的模板特化与服务器端更新规则在分布式实现中由 ps_dist-inl.h#L41-L59 的UpdaterWrapper桥接到底层 KV 层parameter/kv_layer.h把用户的InitModel/Update适配为分布式 KV 层的初始化与更新回调。实战三分布式异步求和Level-2 Server构建参数服务器并配置首先构建参数服务器将ps_dir替换为任意方便目录。参数服务器是 DMLC 体系下的独立开源仓库即 dmlc/parameter_server对应 README 中的-b dev分支克隆后安装第三方依赖并编译git clone parameter_server 仓库地址 -b dev ps_dir cd ps_dir ./script/install_third.sh make -j8然后修改 config.mkUSE_DIST_PS 1 PS_PATH ps_dir再执行make。启动分布式集群并运行以1 个服务器节点、3 个 worker 节点、每个 worker 节点 2 个设备为例./local.sh 1 3 ./dist_async_sum.cpu 1 2local.sh 是一个本地模拟集群的启动脚本用法为$0 num_servers num_workers bin [args..]。它会在本机依次拉起 1 个 schedulerrole:SCHEDULER, port:8001、num_servers个 server 节点端口从 9600 递增和num_workers个 worker 节点端口从 9500 递增并统一传入-num_servers/-num_workers等参数见 local.sh#L22-L57。真实分布式环境下这些节点会分布在不同机器上并通过 scheduler 发现彼此。dist_async_sum 与 local_sum 的差异dist_async_sum-inl.h 与local_sum-inl.h大体相似主要区别有两点1创建分布式模型并开启服务器端更新auto* ps mshadow::ps::CreateSharedModelxpu, float(dist); ps-SetParam(update_on_server, 1);注意此处Run中与local版本不同没有rabit::Init调用因为走的是参数服务器路径而非 rabit allreduce。2显式创建服务器节点与 worker 节点dist_async_sum.cpp 定义了CreateServerNode实例化MShadowServerNodefloat即分布式服务器节点入口和WorkerNodeMain调用Runmshadow::cpu运行 worker 逻辑。同一个二进制文件依据-my_node指定的角色SCHEDULER/SERVER/WORKER执行不同入口。同时分布式示例必须实现真正的IModelUpdaterUpdater类在InitModel_中把 key 对应的模型初始化为 0 并登记到std::mapint, Tensorcpu, 1, float在Update_中把推入的梯度累加到模型上dist_async_sum-inl.h#L38-L56。worker 端则先PullReq拉回服务器上的模型再推入本地增量并再次拉取从而验证分布式异步聚合链路。源码级实现原理LocalModel 与 DistModel理解接口语义后可以进一步看底层实现LocalModel单机实现在 ps_local-inl.h。它维护每个设备独立的 push/pull 队列与工作线程perdev_push_thread、perdev_pull_thread等可配置参数见 ps_local-inl.h#L105-L120 的SetParam解析push 侧按 key 聚合各设备数据默认求和也支持push_op[key]gatherpull 侧异步把结果拷回并触发回调PullWait通过条件变量等待对应 key 的请求完成。构造时还暴露了nthread_reduction归约线程数、use_pin_memory是否使用锁页内存等调优参数。DistModel分布式实现在 ps_dist-inl.h继承LocalModel并叠加::psparameter_server的 KV 层。机内仍走 Level-1 聚合跨机通过shared_model_的Push/Pull与远程服务器交互见 ps_dist-inl.h#L83-L100 的ServerInitKey与HandlePushFinish。这正对应两级架构机内 Level-1 保证局部强一致BSP机间 Level-2 采用异步最终一致性。小结mshadow-ps 用一组极简的异步接口InitKey/Push/PullReq/PullWait统一了单机多 GPU 与分布式两类同步场景本地模式通过每设备队列线程实现计算与同步重叠分布式模式借助两级参数服务器在不同层级采用不同一致性模型来兼顾收敛与吞吐。建议的进阶路径是先跑通 local_sum-inl.h 理解异步语义再研究 guide/neuralnet/nnet_ps.cu 的回调与 stream 用法最后通过 dist_async_sum-inl.h 与 local.sh 打通分布式训练链路。这一整套机制后来也被广泛借鉴到深度学习框架的参数服务器设计中理解它有助于深入阅读 mshadow 及基于其构建的深度学习系统的同步内核。赞分享人工智能深度学习机器学习【免费下载链接】mxnetLightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more项目地址https://gitcode.com/gh_mirrors/mxne/mxnet点击查看免费下载相关推荐ToolJet REST API 数据源配置指南凭据、认证方式与 SSL 设置ToolJet REST API 数据源配置指南凭据、认证方式与 SSL 设置 ToolJet 可以连接任意公开的 REST API 端点在查询面板中创建查深度学习机器学习人工智能冒险岛游戏编辑器Harepacker-resurrected打造专属游戏世界的终极工具冒险岛游戏编辑器Harepacker resurrected打造专属游戏世界的终极工具 你是否曾梦想过亲手设计自己的冒险岛地图是否想要修改游戏角色外观或创建深度学习人工智能机器学习分布式训练DeiT训练实战从ImageNet数据准备到多GPU分布式训练DeiT训练实战从ImageNet数据准备到多GPU分布式训练 想要快速上手DeiTData efficient Image Transformers计算机视觉深度学习上一篇如何在5分钟内开始使用Lathe完整安装与快速启动指南下一篇为什么选择PyxleyFlaskReact开发者不可错过的仪表盘工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/20 12:55:40

如何使用PHP实现数据的分页功能?

数据的分页功能在网络应用中非常常见,它可以帮助我们更好地展示和组织大量的数据。底层原理查询数据库:首先,我们需要从数据库中查询出所有的数据。但是,当数据量很大时,一次性加载所有数据会导致页面加载缓慢&#xf…

2026/9/20 12:50:39

RapidOCR 快速上手:两行代码完成离线图片文字识别

RapidOCR 快速上手:两行代码完成离线图片文字识别 【免费下载链接】RapidOCR 📄 Awesome OCR multiple programing languages toolkits based on ONNX Runtime, OpenVINO, MNN, PaddlePaddle, TensorRT and PyTorch. 项目地址: https://gitcode.com/Gi…

2026/9/20 13:35:45

当心陷阱!不是所有 AI 写作工具都靠谱,2026 导师认可工具全览

每年毕业季,无数同学深陷论文难题:开题毫无思路、搭建框架耗费数日、初稿逻辑松散、查重标红泛滥、AI检测超标、格式反复被导师驳回。现如今市面上通用型AI工具遍地开花,但绝大多数通用大模型存在编造虚假参考文献、学术语句口语化、AI生成痕…

2026/9/20 13:35:45

合肥桑夏太阳能维修预约电话|附近师傅上门检修|欧米到家报修热线

太阳能热水器使用时间长了,容易出现不上水、水箱水位不准、水温升不上去、热水出得少、上水不停、仪表不显示、控制器报警、管道漏水、冬季冻堵、电加热不能使用等情况。尤其是合肥气候湿润、四季分明,多雨潮湿且冬季低温湿冷,部分家庭太阳能…

2026/9/20 13:35:45

2026 AI编程Coding Plan横评:GLM、Kimi、MiMo怎么选?

2026年年中的时候,AI编程基本已经从“要不要用”变成了“用哪家、怎么订”的阶段。我身边的团队里,现在讨论最多的已经不是某个模型刷分多高,而是GLM、Kimi、MiMo这几家的Coding Plan到底该订哪个、订完怎么接入自己的编辑器、高峰期到底卡不…

2026/9/20 13:30:45

抖音无水印批量下载:3 种任务的完整操作指南

抖音无水印批量下载:3 种任务的完整操作指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖音批…

2026/9/20 0:04:49

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/20 0:04:49

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/20 0:04:49

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/20 0:04:49

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/20 4:54:47

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/20 5:01:23

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/20 5:09:33

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码