【显卡】服务器炼丹代码配置
写在最前面
深度学习(Deep Learning)已经成为众多领域中的重要技术,尤其在图像识别、自然语言处理、语音识别等方面表现出色。然而,深度学习模型的训练通常需要大量的计算资源,因此高性能计算(HPC)和GPU(图形处理单元)显卡变得至关重要。
在大型机构分配的服务器集群中,需要使用GPU的程序默认都会在第一张卡上进行,如果第一张卡倍别人占用或者显存不够的情况下,程序就会报错说没有显存容量,所以能够合理地利用GPU资源能帮助你更快更好地跑出实验效果。
本篇博客将介绍在服务器上进行深度学习炼丹(即训练模型)时如何配置代码,以及如何在Python中指定特定的GPU显卡来运行代码。
参考:https://cloud.tencent.com/developer/article/2352733
一、查看哪几块显卡能用
在进行深度学习任务之前,需要配置服务器环境。
登陆服务器,查看gpu是否可用,并确定CUDA版本
用ssh命令登录服务器(账号密码略),输入命令:nvidia-smi
,查看gpu是否可用。
在我的这个案例中,可用显卡为:
- 可用显卡: GPU 0, GPU 1, GPU 2, GPU 3
- 部分使用中的显卡: GPU 4, GPU 5
- 高负载使用中的显卡: GPU 6, GPU 7
GPU 0 到 GPU 3 目前几乎未被使用,温度和内存利用率都很低,适合用于新任务。GPU 4 和 GPU 5 在中等负载下,但仍有一定余量。GPU 6 和 GPU 7 负载较高,建议避免使用或等负载减小后再使用。
二、使用指定gpu运行代码
1、指定使用GPU0运行脚本(默认是第一张显卡, 0代表第一张显卡的id,其他的以此类推)
import os os.environ["CUDA_VISIBLE_DEVICES"] = "0"
2、指定使用多张显卡运行脚本
import os os.environ["CUDA_VISIBLE_DEVICES"] = "0,2,3" # 注意:这两行代码必须在文件的最开头,在加载各种包之前
三、如何使用
1、单块显卡使用
在python文件中,定义需要加速的模型之后,加上:
model = ...... model.train(True) or model.train(False) # 看你是要训练还是测试 model.to('cuda') # 或者model.cuda() # 后面需要输入model的变量也是需要.to('cuda')或者.cuda()的,不然会报错既用了cpu又用gpu,不兼容
2、多GPU训练
假如:为了让你的PyTorch代码在多块显卡(0,1,2,3)上运行,你可以使用torch.nn.DataParallel
或者torch.nn.parallel.DistributedDataParallel
来进行多GPU训练。
使用DataParallel
DataParallel
是一个相对简单的方法,它可以在多块GPU上进行数据并行处理。下面是如何使用DataParallel
的方法:
import torch import torch.nn as nn import torch.optim as optim # 假设你有一个简单的模型 class SimpleModel(nn.Module): def __init__(self): super(SimpleModel, self).__init__() self.fc = nn.Linear(100, 10) def forward(self, x): return self.fc(x) # 创建模型 model = SimpleModel() # 将模型转换为DataParallel,并指定使用的显卡 model = nn.DataParallel(model, device_ids=[0, 1, 2, 3]) # 将模型移至GPU model = model.cuda() # 创建一个优化器 optimizer = optim.SGD(model.parameters(), lr=0.01) # 创建数据 inputs = torch.randn(64, 100).cuda() labels = torch.randn(64, 10).cuda() # 训练步骤 outputs = model(inputs) loss = nn.MSELoss()(outputs, labels) loss.backward() optimizer.step()
使用DistributedDataParallel
DistributedDataParallel
是一种更高级的方法,通常在大规模分布式训练中使用,但在单机多卡上也可以提升性能。下面是如何使用DistributedDataParallel
的方法:
启动代码:
在使用DistributedDataParallel
时,你需要使用多进程方式启动程序。可以通过torch.multiprocessing
或命令行启动。代码修改:
import torch import torch.distributed as dist import torch.multiprocessing as mp import torch.nn as nn import torch.optim as optim from torch.nn.parallel import DistributedDataParallel as DDP # 简单模型定义 class SimpleModel(nn.Module): def __init__(self): super(SimpleModel, self).__init__() self.fc = nn.Linear(100, 10) def forward(self, x): return self.fc(x) def setup(rank, world_size): # 初始化进程组 dist.init_process_group("nccl", rank=rank, world_size=world_size) torch.cuda.set_device(rank) def cleanup(): dist.destroy_process_group() def train(rank, world_size): setup(rank, world_size) # 模型 model = SimpleModel().to(rank) ddp_model = DDP(model, device_ids=[rank]) optimizer = optim.SGD(ddp_model.parameters(), lr=0.01) inputs = torch.randn(64, 100).to(rank) labels = torch.randn(64, 10).to(rank) outputs = ddp_model(inputs) loss = nn.MSELoss()(outputs, labels) loss.backward() optimizer.step() cleanup() if __name__ == "__main__": world_size = 4 mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)
两种方法的对比
DataParallel
:简单易用,适用于轻量级并行处理,但扩展性较差,在大规模分布式训练中性能不如DistributedDataParallel
。DistributedDataParallel
:适用于大规模训练,可以获得更好的性能,但代码复杂度略高,需要使用多进程启动。
注意事项
- 模型和数据要发送到指定的设备:确保模型和数据都发送到指定的GPU,否则可能会报错。
- 同步BN:在多GPU环境下,使用同步批标准化(Batch Normalization)可能需要特殊处理。
选择合适的方法
- 对于简单的多GPU训练任务,使用
DataParallel
。 - 对于需要高性能、扩展性强的任务,使用
DistributedDataParallel
。
参考资料
这两种方法可以帮助你在多块显卡上高效地运行你的深度学习代码,选择适合你的需求的方法,来实现模型的多GPU训练。
四、小结
关键点小结
- 设置
CUDA_VISIBLE_DEVICES
: 指定多个GPU设备,使得代码只看到这些设备。 - 多GPU并行: 使用
torch.nn.DataParallel
包装模型,利用多个GPU。 - 数据加载优化: 设置
num_workers
参数优化数据加载,减少CPU负载。
这段代码展示了如何在PyTorch中配置多GPU训练和优化数据加载。这样可以有效利用多GPU的计算能力,并优化CPU资源使用。
为了将多GPU并行训练设置在代码中的适当位置并优化数据加载器,你需要在运行的第一个文件的开头设置os.environ["CUDA_VISIBLE_DEVICES"]
,并根据设备情况设置模型的多GPU并行。以下是如何进行这些设置的步骤和示例代码。
配置多GPU并行和数据加载器
1. 设置CUDA_VISIBLE_DEVICES
在运行的第一个文件的最前面,添加设置环境变量的代码。这会使得后续的代码只看到指定的GPU设备:
import os os.environ["CUDA_VISIBLE_DEVICES"] = "0,1,6,7"
2. 配置PyTorch设备和模型
根据设备情况,使用torch.nn.DataParallel
进行多GPU并行:
import torch import torch.nn as nn import torch.optim as optim # 定义设备 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
3. 优化数据加载器
使用num_workers
参数优化数据加载,通常设置为CPU核心数的一半或略低于核心数。对于高效的训练,可以设置为20或40,这取决于你的CPU能力和任务需求。
from torch.utils.data import DataLoader, Dataset # 假设你有一个简单的数据集 class SimpleDataset(Dataset): def __init__(self, size): self.size = size def __len__(self): return self.size def __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)
整合后的代码示例
以下是整合后的代码示例,涵盖了从配置GPU、定义模型、设置数据加载器到运行训练过程的完整流程。
import os import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, Dataset # 设置环境变量 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 = size def __len__(self): return self.size def __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(2): 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()}")
欢迎大家添加好友交流。