深度学习技巧应用33-零门槛实现模型在多个GPU的分布式流水线训练的应用技巧

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用33零门槛实现模型在多个GPU的分布式流水线训练的应用技巧,本文将帮助大家零门槛的实现模型在多个GPU的并行训练,如果你手头上没有GPU资源,根据本文的介绍也可实现模型的并行,让大家了解模型的并行是怎么实现的,揭开模型分布式训练的神秘面纱,提升自己的模型训练水平。在大规模语言模型训练领域迈进自己的脚步。
在这里插入图片描述

一、 神经网络模型并行的介绍

神经网络模型并行广泛应用于分布式训练技术中,本文展示了如何通过使用模型并行来解决多个GPU训练的问题,与DataParallel不同,模型并行将单个模型分割到不同的GPU上,而不是将整个模型复制到每个GPU上(假设一个模型M包含10层:使用DataParallel时,每个GPU将拥有这10层的副本,而在使用模型并行在两个GPU上时,每个GPU可能托管5层)。

模型并行的思想是将模型的不同子网络放置到不同的设备上,并相应地实现前向方法以跨设备移动中间输出。由于只有模型的某部分在单个设备上运行,因此一组设备可以共同服务于更大的模型。本文的的重点是将模型并行的思路展示给大家。

分布式流水线模型训练

分布式模型训练通常指的是在多个计算节点上并行地训练机器学习模型。这种训练方式可以提高模型训练的速度,尤其是在处理大规模数据集和复杂模型时。分布式训练可以通过不同的并行策略来实现,例如数据并行、模型并行、流水线并行等。以下是这些并行策略的一些基本数学原理:
1.数据并行(Data Parallelism):
数据并行是最常见的并行策略。在这种策略中,训练数据被分成多个部分,每个计算节点(或设备)独立地在自己的数据部分上训练完整的模型,并定期同步参数更新。
假设我们有一个损失函数 L ( θ ) L(\theta) L(θ),其中 θ \theta θ 是模型参数。在数据并行中,每个节点计算损失和梯度:
分布式流水线模型训练 ∇ θ L k ( θ ) = ∂ L k ( θ ) ∂ θ \nabla_{\theta} L_k(\theta) = \frac{\partial L_k(\theta)}{\partial \theta} θLk(θ)=θLk(θ)
其中 L k L_k Lk 是第 k k k 个节点上的损失函数。参数更新可以通过平均所有节点的梯度来实现:
θ ← θ − α 1 N ∑ k = 1 N ∇ θ L k ( θ ) \theta \leftarrow \theta - \alpha \frac{1}{N} \sum_{k=1}^{N} \nabla_{\theta} L_k(\theta) θθαN1k=1NθLk(θ)
其中 α \alpha α 是学习率, N N N 是节点数。
2.模型并行(Model Parallelism):
当模型太大以至于无法放入单个设备的内存时,可以使用模型并行。在这种策略中,模型的不同部分被放置在不同的计算节点上。每个节点只负责模型的一部分,所有节点协同工作以完成整个前向和后向传播。
3.流水线并行(Pipeline Parallelism):
流水线并行将模型分成几个部分,并且每个部分由不同的计算节点处理。这些节点按流水线的方式工作,即一个节点处理一部分输入并将结果传递给下一个节点,以此类推。这种方式可以减少延迟并提高设备利用率。

二、构建两个GPU的环境

很多人可能设备环境都没有GPU,下面我介绍在kaggle平台上实现模型并行,环境选择加速器选择GPU T4*2。

现在从一个包含两个线性层的模型开始,为了在两个GPU设备上运行这个模型,我们只需将每个线性层放置在不同的GPU上,并根据层的设备相应地移动输入和中间输出。

import torch
import torch.nn as nn
import torch.optim as optim# 检查是否有可用的GPU
if torch.cuda.is_available():# 输出GPU数量print(f"Number of GPUs available: {torch.cuda.device_count()}")# 输出当前GPU的名称for i in range(torch.cuda.device_count()):print(f"GPU {i}: {torch.cuda.get_device_name(i)}")
else:print("No GPU available.")class MainModel(nn.Module):def __init__(self):super(MainModel, self).__init__()self.net1 = torch.nn.Linear(10, 10).to('cuda:0')self.relu = torch.nn.ReLU()self.net2 = torch.nn.Linear(10, 5).to('cuda:1')def forward(self, x):x = self.relu(self.net1(x.to('cuda:0')))return self.net2(x.to('cuda:1'))model = MainModel()
loss_fn = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.001)optimizer.zero_grad()
outputs = model(torch.randn(20, 10))
labels = torch.randn(20, 5).to('cuda:1')
loss_fn(outputs, labels).backward()
optimizer.step()

运行后,我们看到两台GPU信息

Number of GPUs available: 2
GPU 0: Tesla T4
GPU 1: Tesla T4

三、将模型并行应用于现有模块

这里我们需要将torchvision.models.resnet50()分解到两个GPU上。从现有的ResNet模块继承,并在构造过程中将层分割到两个GPU上。然后,重写前向方法,通过相应地移动中间输出,将两个子网络拼接起来。

from torchvision.models.resnet import ResNet, Bottleneck
import torch.nn as nn
num_classes = 1000class ModelParallelResNet50(ResNet):def __init__(self, *args, **kwargs):super(ModelParallelResNet50, self).__init__(Bottleneck, [3, 4, 6, 3], num_classes=num_classes, *args, **kwargs)self.seq1 = nn.Sequential(self.conv1,self.bn1,self.relu,self.maxpool,self.layer1,self.layer2).to('cuda:0')self.seq2 = nn.Sequential(self.layer3,self.layer4,self.avgpool,).to('cuda:1')self.fc.to('cuda:1')def forward(self, x):x = self.seq2(self.seq1(x).to('cuda:1'))return self.fc(x.view(x.size(0), -1))

单个模型训练与并行模型时间比较

import torchvision.models as models
import matplotlib.pyplot as plt
plt.switch_backend('Agg')
import numpy as np
import timeit
import torch.nn as nnnum_batches = 3
batch_size = 120
image_w = 128
image_h = 128def train(model):model.train(True)loss_fn = nn.MSELoss()optimizer = optim.SGD(model.parameters(), lr=0.001)one_hot_indices = torch.LongTensor(batch_size) \.random_(0, num_classes) \.view(batch_size, 1)for _ in range(num_batches):# generate random inputs and labelsinputs = torch.randn(batch_size, 3, image_w, image_h)labels = torch.zeros(batch_size, num_classes) \.scatter_(1, one_hot_indices, 1)# run forward passoptimizer.zero_grad()outputs = model(inputs.to('cuda:0'))# run backward passlabels = labels.to(outputs.device)loss = loss_fn(outputs, labels)loss.backward()optimizer.step()num_repeat = 10stmt = "train(model)"setup = "model = ModelParallelResNet50()"
mp_run_times = timeit.repeat(stmt, setup, number=1, repeat=num_repeat, globals=globals())
mp_mean, mp_std = np.mean(mp_run_times), np.std(mp_run_times)setup = "import torchvision.models as models;" + \"model = models.resnet50(num_classes=num_classes).to('cuda:0')"
rn_run_times = timeit.repeat(stmt, setup, number=1, repeat=num_repeat, globals=globals())
rn_mean, rn_std = np.mean(rn_run_times), np.std(rn_run_times)def plot(means, stds, labels, fig_name):fig, ax = plt.subplots()ax.bar(np.arange(len(means)), means, yerr=stds,align='center', alpha=0.5, ecolor='red', capsize=10, width=0.6)ax.set_ylabel('ResNet50 Execution Time (Second)')ax.set_xticks(np.arange(len(means)))ax.set_xticklabels(labels)ax.yaxis.grid(True)plt.tight_layout()plt.savefig(fig_name)plt.close(fig)plot([mp_mean, rn_mean],[mp_std, rn_std],['Model Parallel', 'Single GPU'],'mp_and_rn.png')

运行结果如图:
在这里插入图片描述

通过流水线输入加速的比较

class PipelineParallelResNet50(ModelParallelResNet50):def __init__(self, split_size=20, *args, **kwargs):super(PipelineParallelResNet50, self).__init__(*args, **kwargs)self.split_size = split_sizedef forward(self, x):splits = iter(x.split(self.split_size, dim=0))s_next = next(splits)s_prev = self.seq1(s_next).to('cuda:1')ret = []for s_next in splits:# A. ``s_prev`` runs on ``cuda:1``s_prev = self.seq2(s_prev)ret.append(self.fc(s_prev.view(s_prev.size(0), -1)))# B. ``s_next`` runs on ``cuda:0``, which can run concurrently with As_prev = self.seq1(s_next).to('cuda:1')s_prev = self.seq2(s_prev)ret.append(self.fc(s_prev.view(s_prev.size(0), -1)))return torch.cat(ret)setup = "model = PipelineParallelResNet50()"
pp_run_times = timeit.repeat(stmt, setup, number=1, repeat=num_repeat, globals=globals())
pp_mean, pp_std = np.mean(pp_run_times), np.std(pp_run_times)plot([mp_mean, rn_mean, pp_mean],[mp_std, rn_std, pp_std],['Model Parallel', 'Single GPU', 'Pipelining Model Parallel'],'mp_and_rn_and_pp.png')

运行结果如图:
在这里插入图片描述

我们需要注意的是:设备到设备的张量复制操作会在源设备和目标设备上的当前流上同步。如果您创建了多个流,您必须确保复制操作得到适当的同步。在复制操作完成之前写入源张量或读取/写入目标张量可能会导致未定义的行为。上述实现的只在源设备和目标设备上都使用默认流,因此不需要强制额外的同步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/643086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dhcp服务器的ip池的待分配ip地址是否冲突的检测机制

看到有的资料说,dhcp服务器在分配ip地址时,要检测是否待分配的ip地址是否存在冲突,会向广播域发出,对应ip发出icmp的ping消息来验证是否冲突。特地用自己的公司的交换机验证一下,在交换机上镜像抓包观察一下。 wiresha…

机器学习实验4——CNN卷积神经网络分类Minst数据集

文章目录 🧡🧡实验内容🧡🧡🧡🧡 原理🧡🧡🧡🧡CNN实现分类Minst🧡🧡代码数据预处理:设置基本参数: &#x1f9e…

接口文档swagger2的使用

Spring-接口文档swagger2 1、swagger/knife4j 接口文档配置 ​ knife4j是swagger的增强版本&#xff0c;更加的小巧、轻量&#xff0c;功能也是更加的完善&#xff0c;UI也更加的清晰&#xff1b;可以从swagger到knife4j无缝切换。 1.1 引入相关依赖 <!--接口文档的开发:…

神经网络:表述(Neural Networks: Representation)

1.非线性假设 无论是线性回归还是逻辑回归&#xff0c;当特征太多时&#xff0c;计算的负荷会非常大。 案例&#xff1a; 假设我们有非常多的特征&#xff0c;例如大于 100 个变量&#xff0c;我们希望用这 100 个特征来构建一个非线性的多项式模型&#xff0c;结果将是数量非…

Win10 如何用powershell写个WOL开机脚本

环境&#xff1a; Win10 专业版 问题描述&#xff1a; Win10 如何用powershell写个WOL开机脚本 解决方案&#xff1a; 1.脚本内容 $mac b1-10-18-52-11-12 $macBytes $mac -split - | ForEach-Object { [byte](0x $_) } $broadcastAddress [byte[]](1..6 | ForEach-O…

springboot导出数据到excel模板,使用hutool导出数据到指定excel,java写入数据到excel模板

最近遇到一个需求&#xff0c;需要从数据库查询数据&#xff0c;写入到对应的excel导入模板中。再把导出的数据进行修改&#xff0c;上传。 我们项目用的是easyExcel&#xff0c;一顿百度搜索&#xff0c;不得其法。 主要是要把数据填充到指定单元格中&#xff0c;跟平时用到的…

【Android】细数Linux和Android系统中的伪文件系统

文章目录 前言Linux伪文件系统cgroupfsLinux的cgroupsAndroid的cgroups debugfsfunctionfs(/dev/usb-ffs/adb)functionfs 的引入sysfs是什么 procfs(/proc)pstore(/sys/fs/pstore)selinuxfs(/sys/fs/selinux)sysfs(/sys)参考 前言 做了好些年Android开发&#xff0c;你了解过L…

Java Web(二)--HTML

基本介绍 官网文档地址: HTML 教程 HTML&#xff08;HyperText Mark-up Language&#xff09;即超文本标签语言&#xff1b;HTML 文本是由 HTML 标签组成的文本&#xff0c;可以包括文字、图形、动画、声音、表格、链接等&#xff1b;HTML 的结构包括头部&#xff08;Head&…

学校“数据结构”课程Project—扩展功能(自主设计)

目录 一、设想功能描述 想法缘起 目标功能 二、问题抽象 三、算法设计和优化 1. 易想的朴素搜索 / dp 搜索想法 动态规划&#xff08;dp&#xff09;想法 2. 思考与优化 四、算法实现 五、结果示例 附&#xff1a;使用的地图API 一、设想功能描述 想法缘起 OSM 导出…

汽车网络架构与常用总线汇总

汽车CAN总线简述 CAN 是控制器局域网Controller Area Network 的缩写&#xff0c;1986年&#xff0c;由德国Bosch公司为汽车开发的网络技术&#xff0c;主要用于汽车的监测与控制&#xff0c;目的为适应汽车“减少线束的数量”“通过多个网络进行大量数据的高速传输”的需求。…

TA百人计划学习笔记 3.1.1模板测试

资料 源视频 【技术美术百人计划】图形 3.1 深度与模板测试 传送门效果示例_哔哩哔哩_bilibili ppt 3100-模板测试与深度测试(1) 参考 Unity Shader: 理解Stencil buffer并将它用于一些实战案例&#xff08;描边&#xff0c;多边形填充&#xff0c;反射区域限定&#xff0c;阴影…

c++学习笔记-STL案例-机房预约系统6-老师模块

前言 衔接上一篇“c学习笔记-STL案例-机房预约系统5-学生模块”&#xff0c;本文主要设计老师模块&#xff0c;从&#xff0c;老师登录和注销、查看所有预约、审核预约三个方面进行分析和实现。 目录 9 教师模块 9.1 教师登录和注销 9.1.1 构造函数 9.1.2 教师子菜单 ​编…

Linux7 安装 Oracle 19C RAC 详细图文教程

实战篇&#xff1a;Linux7 安装 Oracle 19C RAC 详细图文教程 本文是按照&#xff1a;https://www.modb.pro/db/154424的思路进行编写 一、安装前规划 安装RAC前&#xff0c;当然要先做好规划。具体包含以下几方面&#xff1a; 节点主机版本主机名实例名Grid/Oracle版本Publi…

鸿蒙原生开发-仿ChatGPT应用实战

运行环境 DAYU200:4.0.10.16 SDK&#xff1a;4.0.10.15 IDE&#xff1a;4.0.600 前言 在配置好环境之后&#xff0c;可以尝试这编写一个较为简单的应用程序练练手&#xff0c;这里选择使用一个免费的API接口网站 ALAPI来尝试编写一个可进行对话的GPT应用程序。 创建项目 …

SQL注入示例

例一、基础SQL注入&#xff1a;load_file读文件 CISP-PTE 认证考试 首先是有单引号和括号的&#xff0c;首要是要闭合&#xff0c;然后回显点是在-1的位置&#xff0c;读取文件上面的key的话使用的是load_file(/tmp/360/key) id-1)%09ununionion%09select%091,2,3,load_file…

【算法与数据结构】322、LeetCode零钱兑换

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题可以抽象成一个完全背包问题。 第一步&#xff0c; d p [ j ] dp[j] dp[j]的含义。 d p [ j ] dp…

Unity之Cinemachine教程

前言 Cinemachine是Unity引擎的一个高级相机系统&#xff0c;旨在简化和改善游戏中的相机管理。Cinemachine提供了一组强大而灵活的工具&#xff0c;可用于创建令人印象深刻的视觉效果&#xff0c;使开发人员能够更轻松地掌控游戏中的摄像机行为。 主要功能和特性包括&#x…

Springboot+vue的医院后台管理系统(有报告),Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的医院后台管理系统&#xff08;有报告&#xff09;&#xff0c;Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的医院后台管理系统&#xff0c;采用M&#xff08…

LeetCode、875. 爱吃香蕉的珂珂【中等,最小速度二分】

文章目录 前言LeetCode、875. 爱吃香蕉的珂珂【中等&#xff0c;最小速度二分】题目及分类思路分析及代码实现代码优化 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Ja…

如何修改flutter的minSdkVersion版本?

在使用第三方插件的时候&#xff0c;插件对最低的 minSdkVersion版本是有要求的&#xff0c;你比如flutter 插件 webview_flutter 就会报一下错&#xff1a; minSdkVersion 16 cannot be smaller than version 19 declared in library 解决方法①&#xff1a; 这个时候我们需…