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

发布时间:2026/11/12 3:36:37

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/11/12 3:36:33

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

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

2026/11/9 0:37:36

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

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

2026/11/12 3:34:17

同时高压电工证 低压实操考试考什么

工地太忙根本没时间复习考试?高压电工证低压也能一起考 你是不是也这样,工地天天赶工期,晚上加班,白天干活,根本没空去复习考试?现在很多人在考高压电工证的时候,也想顺带把低压电工证一起考了,因为两个证的考试内容有重叠, 官方报名入口…

2026/11/12 3:34:17

鲁山电工证多少钱?学历不高怕报不上名?考前押题帮你稳过

鲁山电工证多少钱?学历不高怕报不上名?考前押题帮你稳过 学历不高怕报不上名?别急,鲁山电工证多少钱你先搞清楚,别被乱收费耽误了时间。现在市面上各种培训机构鱼龙混杂,很多人担心自己文化程度不够,考不过电工证,其实只要你掌握好 考前押题…

2026/11/12 3:34:17

电工证可以异地补证,值不值得考?洛阳涧西区转岗人真实经历分享

电工证可以异地补证,值不值得考?洛阳涧西区转岗人真实经历分享 你现在急需特种作业证才能上岗找工作,偏偏电工证丢了,又不懂补办流程,心里急得像热锅上的蚂蚁。别担心,其实 电工证可以异地补证 ,而且这个证书值不值得考,答案早就摆在眼前。…

2026/11/12 3:34:17

电工证可以异地补证 在哪考的证能顺利转过来

电工证可以异地补证 在哪考的证能顺利转过来 之前考的证在外省能不能转过来?这是很多在外地打工的电工、电焊工、高处作业人员经常问的问题。特别是像周口市这类以市政工程为主的地区,很多施工人员都跨省工作,证书的转移和补办就成了刚需。今天我们就来聊…

2026/11/11 12:42:59

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/12 0:04:01

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘

工地太忙根本没时间复习考试?学习电工证到哪里学通过率揭秘 工地太忙根本没时间复习考试?你不是一个人。作为一名在南阳卧龙区干了七八年市政公用工程的电工,我深知这个问题的现实性。电工证不仅是工作的“入场券”,更是职业发展的“通行证”,但备考过程…

2026/11/12 0:04:01

双流电工证考别怕挂科!郑州报考避坑指南全攻略

双流电工证考别怕挂科!郑州报考避坑指南全攻略 实操考试心里没底怕挂科?双流电工证考在郑州报名,很多人因为不了解流程、准备不充分,白白浪费时间和金钱。作为三门峡应届工程类毕业生,我也曾经历过这样的焦虑。今天就从零开始,手把手教你如何避开郑州报…

2026/11/12 0:04:01

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少

之前考的证在外省能不能转过来 怎么报名考电工证培训价格多少 之前考的证在外省能不能转过来?这个问题确实让不少准备换城市工作的朋友犯了难,尤其像电工证这种实操性很强的证书,很多人担心跨省后证书能不能继续用。其实,只要符合相关流程,是可以顺利转…

2026/11/11 20:27:01

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/10 10:29:37

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

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

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

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