【深度学习】单机多卡 | DataParallel将计算任务在多个 GPU 上并行执行,可以在多个 GPU 上分摊工作负载,从而加快训练速度

【深度学习】单机多卡 | DataParallel将计算任务在多个 GPU 上并行执行,可以在多个 GPU 上分摊工作负载,从而加快训练速度

  • 写在最前面
  • DataParallel (DP) 简介
    • 使用 DataParallel 的场景
    • 使用 DataParallel 的基本步骤
  • 代码部分
    • train.py
    • 简单的代码示例
      • 代码解析
    • DataParallel 的局限性
  • 小结


请添加图片描述

🌈你好呀!我是 是Yu欸
🌌 2024每日百字篆刻时光,感谢你的陪伴与支持 ~
🚀 欢迎一起踏上探险之旅,挖掘无限可能,共同成长!

写在最前面

希望在单机多卡的模式下运行我的模型代码,加快训练速度。

请教吕博:如何更改代码?
其中,提到模型先用DP方式运行

DP是什么?又被学到了一个知识点。

在深度学习和分布式计算领域,DP 通常指的是 DataParallelDataParallel 是一种将计算任务在多个 GPU 上并行执行的方法。它在单机多卡环境中非常有用,可以在多个 GPU 上分摊工作负载,从而加快训练速度。

DataParallel (DP) 简介

torch.nn.DataParallel 是 PyTorch 中的一个工具,可以让模型在多个 GPU 上并行运行。它通过将输入批次拆分成多个子批次,每个子批次发送到不同的 GPU 上,并行执行前向传播和反向传播,然后将每个 GPU 上的梯度聚合到主 GPU 上进行参数更新。

使用 DataParallel 的场景

  • 单机多卡训练: 当你有一台机器配备了多块 GPU,并希望利用所有的 GPU 资源来加速模型训练时,DataParallel 是一个简单而有效的解决方案。
  • 简化代码: 相比于更复杂的分布式训练方案,DataParallel 提供了一种较为简化的方式来实现多 GPU 并行训练,通常只需要对模型进行简单包装。

使用 DataParallel 的基本步骤

  1. 定义模型: 创建你的神经网络模型。
  2. 包装模型: 使用 torch.nn.DataParallel 包装你的模型。
  3. 将模型和数据迁移到 GPU: 使用 .to(device) 将模型和输入数据迁移到合适的设备上。
  4. 训练模型: 按照常规方式训练模型。

代码部分

train.py

仅展示相关部分

import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,2,3"
# import部分省略def evaluate(model, device, dataloader):model.eval()total_loss, total_step = 0.0, 0.0# 使用with torch.no_grad()来禁用梯度计算with torch.no_grad():# 对dataloader中的每个batch进行遍历for step, batch in enumerate(dataloader):# 将batch中的数据移动到指定设备上batch = tuple(t.to(device) for t in batch)input_ids, attention_mask, decoder_input_ids, decoder_attention_mask, labels = batch# 通过模型进行前向传播,并获取输出结果outputs = model(input_ids, attention_mask=attention_mask, decoder_input_ids=decoder_input_ids,decoder_attention_mask=decoder_attention_mask, labels=labels)# 获取模型输出结果中的loss值loss = outputs['loss']# 累加总损失和总步数total_loss += loss.item()total_step += 1# 返回总损失和Nonereturn total_loss / total_step, None# 设置随机数种子、日志路径
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 初始化tokenizer、添加特殊的tokens
# define dataloader 定义数据加载器
# 每批的个数4/梯度累计个数4
batch_size = int(args.batch_size / args.gradient_accumulation_steps)
# from processing.dataset import BartDataset
# return input_ids, attention_mask, decoder_input_ids, decoder_attention_mask, labels
trian_dataset = BartDataset(tokenizer, args, mode='train')
train_dataloader = DataLoader(dataset=trian_dataset,batch_size=batch_size,shuffle=True,collate_fn=trian_dataset.collate_fn,num_workers=20 # 优化数据加载
)eval_dataset = BartDataset(tokenizer, args, mode='test')
eval_dataloader = DataLoader(dataset=eval_dataset,batch_size=batch_size,shuffle=False,collate_fn=eval_dataset.collate_fn,num_workers=20 # 优化数据加载
)# define model 实例化模型# 检查GPU数量并设置DataParallel
if torch.cuda.device_count() > 1:print(f"Using {torch.cuda.device_count()} GPUs")net = nn.DataParallel(model)
else:print("Using single GPU or CPU")net = model# define criterion 定义损失函数# define optimizer优化器
# 参考:https://blog.csdn.net/hottie_xiaomiao/article/details/124392847
# 打印每一次迭代元素的名字和param
param_optimizer = list(model.named_parameters())
no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']
# 参数组:每组参数可以指定自己的优化器参数,即可使用不同的优化策略
optimizer_grouped_parameters = [{'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},{'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
]
optimizer = torch.optim.AdamW(optimizer_grouped_parameters, lr=args.bart_lr)
# 计算总步数
total_steps = int(len(trian_dataset) * args.epochs / args.gradient_accumulation_steps)
# 初始化学习率调整器
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=int(args.warmup_steps * total_steps),num_training_steps=total_steps)# Begin training
# logger部分省略# 定义一个初始的最好评估损失,即正无穷大
best_eval_loss = float('inf')
# 定义当前的步骤和当前损失
current_step, current_loss = 0, 0
# 定义全局步骤数
global_step = 0# 对于每个 epoch 进行循环
for epoch in range(args.epochs):# 将模型设置为训练模式model.train()# 对训练数据集进行循环for step, batch in enumerate(train_dataloader):# 将batch中的每一个tensor都移动到指定的设备上(如GPU)batch = tuple(t.to(device) for t in batch)# 从batch中获取输入,注意这里的命名方式要和模型中forward函数中的输入命名相同input_ids, attention_mask, decoder_input_ids, decoder_attention_mask, labels = batch# 将输入传递给模型进行前向计算outputs = model(input_ids, attention_mask=attention_mask, decoder_input_ids=decoder_input_ids,decoder_attention_mask=decoder_attention_mask, labels=labels)# TODO:1# print(outputs)# 获取模型的损失loss = outputs['loss']# 记录当前损失和步骤数,用于计算平均损失current_loss += loss.item()current_step += 1# 如果使用了梯度累积,则将损失除以累积步骤数if args.gradient_accumulation_steps > 1:loss = loss / args.gradient_accumulation_steps# 反向传播计算梯度loss.backward()# 将梯度进行裁剪,以防止梯度爆炸clip_grad_norm_(model.parameters(), args.max_clip_norm)# 如果达到了梯度累积的步骤数,则进行一次优化更新if (step + 1) % args.gradient_accumulation_steps == 0:optimizer.step()scheduler.step()optimizer.zero_grad()global_step += 1# 如果当前步骤是一个log间隔的倍数,则打印日志信息,清空当前步骤和当前损失# 在训练完一个 epoch 后,对模型在验证集上进行评估eval_loss, _ = evaluate(model, device, eval_dataloader)logger.info("Eval loss: {:.6f}, the best loss: {:.6f}".format(eval_loss, best_eval_loss))# 如果当前的评估损失比之前的最好评估损失更小,则更新最好评估损失if eval_loss < best_eval_loss:best_eval_loss = eval_loss# 创建一个输出目录,用于存储模型的输出# 在日志中输出检查点保存路径,将模型、tokenizer、args的设置保存到检查点路径中

简单的代码示例

以下是使用 DataParallel 在多 GPU 上运行模型的一个简单示例:

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset# 设置环境变量,指定使用的GPU
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,6,7"# 定义设备
globalDevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 定义一个简单的CNN模型
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()self.conv = nn.Conv2d(3, 16, 3, 1)self.fc = nn.Linear(16 * 26 * 26, 10)def forward(self, x):x = self.conv(x)x = torch.relu(x)x = x.view(x.size(0), -1)x = self.fc(x)return x# 实例化模型
cnn = CNN().to(globalDevice)# 检查GPU数量并设置DataParallel
if torch.cuda.device_count() > 1:print(f"Using {torch.cuda.device_count()} GPUs")net = nn.DataParallel(cnn)
else:print("Using single GPU or CPU")net = cnn# 定义数据集和数据加载器
class SimpleDataset(Dataset):def __init__(self, size):self.size = sizedef __len__(self):return self.sizedef __getitem__(self, idx):return torch.randn(3, 28, 28), torch.tensor(1)dataset = SimpleDataset(1000)
dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=20)# 定义优化器和损失函数
optimizer = optim.SGD(net.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()# 简单的训练过程
for epoch in range(args.epochs):for inputs, labels in dataloader:inputs, labels = inputs.to(globalDevice), labels.to(globalDevice)optimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()print(f"Epoch {epoch+1}, Loss: {loss.item()}")

代码解析

  1. 环境变量设置:

    os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,6,7"
    

    指定要使用的 GPU。

  2. 定义设备:

    globalDevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    

    根据是否有可用的 GPU 设置设备。

  3. 定义模型:

    class CNN(nn.Module):...
    
  4. 包装模型:

    if torch.cuda.device_count() > 1:net = nn.DataParallel(cnn)
    else:net = cnn
    

    如果检测到多个 GPU,使用 DataParallel 包装模型。

  5. 数据加载器:

    dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=20)
    

    使用 num_workers 参数优化数据加载。

  6. 训练过程:

    for epoch in range(2):...
    

DataParallel 的局限性

  • 数据并行粒度: DataParallel 进行的是数据并行操作,每个 GPU 处理一部分数据批次。这可能导致 GPU 利用率不均衡,尤其是在有计算负载差异的情况下。
  • 单节点限制: DataParallel 主要用于单节点多 GPU。如果需要跨节点并行(分布式训练),应该考虑使用 torch.nn.parallel.DistributedDataParallel

小结

DataParallel 是 PyTorch 提供的一种简单易用的多 GPU 并行方法,适合单节点多卡训练。通过这种方法,可以在多个 GPU 上分摊计算任务,提高训练速度和效率。对于更复杂的分布式计算任务,可以考虑使用 DistributedDataParallel


欢迎大家添加好友交流。

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

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

相关文章

可用的微信小程序抓包方式(Charles + bp)

扫码领资料 获网安教程 前言 接到对公司小程序进行渗透的任务&#xff0c;尝试了网上几种对小程序抓包的方式&#xff08;BurpProxifier、Burp安卓模拟器等&#xff09;都无法完成抓包&#xff0c;可能已经失效&#xff0c;结合不同的文章尝试了bpCharles&#xff0c;成功抓包…

diffusion model(十八):diffusion model中negative prompt的工作机制

info个人博客主页http://myhz0606.com/article/ncsn 前置阅读&#xff1a; DDPM&#xff1a; http://myhz0606.com/article/ddpm classifier-guided&#xff1a;http://myhz0606.com/article/guided classifier-free guided&#xff1a;http://myhz0606.com/article/classi…

SANGFOR深信服配置短信验证全流程

登录管理平台&#xff1a; 打开浏览器&#xff0c;输入管理平台地址&#xff08;例如&#xff1a;http://192.168.0.1&#xff09;。输入管理员账号和密码&#xff0c;点击“登录”。 配置认证策略&#xff1a; 导航到“认证” -> “认证策略”。点击“新建策略”。选择“验…

如何评估CRM客户系统的功能是否满足助贷机构的需求?

评估 CRM 客户系统的功能是否满足助贷机构的需求&#xff0c;可以从以下几个方面入手&#xff1a; 1. 客户信息管理 - 检查系统能否全面、准确地记录客户的基本信息&#xff0c;如个人身份、财务状况、贷款需求等。 - 确认是否支持多维度的客户分类和标签功能&#xff0c;以…

《妃梦千年》第十四章-第十五章:重重困局,风云再起

第十四章&#xff1a;重重困局 林清婉和皇上的关系日益亲密&#xff0c;但宫中的局势却依然复杂多变。一天夜里&#xff0c;林清婉正在寝宫中思考未来的对策&#xff0c;忽然接到一个紧急消息。小翠匆匆跑来&#xff0c;神色紧张&#xff1a;“娘娘&#xff0c;边疆的将军送来…

LeetCode:经典题之876、143 题解及延伸

系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 …

pdfmake不能设置表格边框颜色?

找到pdfmake>build>pdfmake.js中&#xff1a; 找到定义的“TableProcessor.prototype.drawVerticalLine”和“TableProcessor.prototype.drawHorizontalLine”两个方法&#xff1a; 重新定义borderColor: var borderColor this.tableNode.table.borderColor||"#…

Python:探索高效、智能的指纹识别技术(简单易懂)

目录 概括 导入库 函数一 参数&#xff1a; 函数二 函数三 主函数 运行结果 src&#xff1a; model_base 7.bmp ​编辑 总结 概括 指纹识别是一种基于人体生物特征的身份验证技术。它通过捕捉和分析手指上的独特纹路和细节特征&#xff0c;实现高准确度的身份识别。…

【工具测评】ONLYOFFICE8.1版本桌面编辑器测评:好用!

随着远程工作的普及和数字化办公的发展&#xff0c;越来越多的人开始寻找功能强大、易于使用的办公软件。在这个背景下&#xff0c;ONLYOFFICE 8.1应运而生&#xff0c;成为许多用户的新选择。ONLYOFFICE 8.1是一款办公套件软件&#xff0c;提供文档处理、电子表格和幻灯片制作…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-41目标检测数据集

41目标检测数据集 import os import pandas as pd import torch import torchvision import matplotlib.pylab as plt from d2l import torch as d2l# 数据集下载链接 # http://d2l-data.s3-accelerate.amazonaws.com/banana-detection.zip# 读取数据集 #save def read_data_b…

6.28U-Net深度学习基准模型特点与应用

U-Net深度学习基准模型特点与应用 U-Net是一种在深度学习领域广泛应用于图像分割任务的卷积神经网络&#xff08;CNN&#xff09;模型&#xff0c;最初由Olaf Ronneberger、Philipp Fischer和Thomas Brox在2015年的论文《U-Net: Convolutional Networks for Biomedical Image …

右键新建没有TXT文本文档的解决办法

电脑右键新建&#xff0c;发现没有txt了&#xff0c;我查网上办法都有点复杂&#xff0c;诸如注册表的&#xff0c;但是其实很简单&#xff0c;重启windows资源管理器就可以了。 点击重新启动&#xff0c;之后新建就有txt文档了。

C++20中的Feature Test Mocros

C20定义了一组预处理器宏&#xff0c;用于测试各种语言和库的feature。 Feature Test Mocros(特性测试宏)是C20中引入的一种强大机制&#xff0c;用于应对兼容性问题。Feature Test Mocros作为预处理器指令(preprocessor directives)出现&#xff0c;它使你能够在编译过程中仔细…

区块链的优势与挑战:为什么区块链如此重要?

区块链听起来像是一种高科技的魔法&#xff0c;很多人都想知道它到底是怎么回事&#xff0c;为什么会引起如此大的关注。今天&#xff0c;我们就来揭开区块链的神秘面纱&#xff0c;看看它的优势和挑战&#xff0c;顺便聊聊为什么它会变得如此重要。 优势篇 1. 去中心化&…

流水线作业模拟程序

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 流水线作业模拟 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private int Count 0;private bool IsStop false;private void uiLight1_Click(object sender, EventArgs e…

[MYSQL] MYSQL库的操作

前言 本文主要介绍MYSQL里 库 的操作 请注意 : 在MYSQL中,命令行是不区分大小写的 1.创建库 create database [if not exists] database_name [charsetutf8 collateutf8_general_ci] ...] create database 是命名语法,不可省略[if not exists] 如果不存在创建,如果存在跳过…

GESP 四级急救包(2):客观题真题集

客观题真题集 一、选择题1. 真题梳理2. 真题答案3. 重难点点播(1) 指针和地址(2) 时间复杂度 二、判断题1. 真题梳理2. 真题答案 一、选择题 1. 真题梳理 若函数声明为 void f(int &a, int b, const int &c)&#xff0c;且在主函数内已经声明了 x , y , z x,y,z x,y,…

最新Node.js安装及配置详细教程

文章目录 下载Node.js安装Node.js配置Node.js1、修改npm包的全局安装路径和缓存路径2、环境变量设置3、镜像源配置4、安装其他包管理工具 下载Node.js 下载&#xff1a;https://nodejs.org/en/download/prebuilt-installer&#xff0c;下载LTS版本的&#xff0c;LTS(Long Time…

代码随想录算法训练营day67 | 110.字符串接龙、105. 有向图的完全可达性、106. 岛屿的周长

本次题目全部来自卡码网 110.字符串接龙 本题只需要求出最短路径的长度就可以了&#xff0c;不用找出具体路径。 所以这道题要解决两个问题&#xff1a; 图中的线是如何连在一起的起点和终点的最短路径长度 首先题目中并没有给出点与点之间的连线&#xff0c;而是要我们自…

驼峰命名法在编程中的应用

驼峰命名法在编程中的应用 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;驼峰命名法&#xff08;Camel Case&#xff09;是一种常见的命名约定&#xff0c;在编…