第5章 机器学习基础(3/3)-GPU加速

5.7 GPU加速

深度学习涉及很多向量或多矩阵运算,如矩阵相乘、矩阵相加、矩阵-向量乘法等。深层模型的算法,如BP、自编码器、CNN等,都可以写成矩阵运算的形式,无须写成循环运算。然而,在单核CPU上执行时,矩阵运算会被展开成循环的形式,本质上还是串行执行。GPU(Graphic Process Unit,图形处理器)的众核体系结构包含几千个流处理器,可将矩阵运算并行化执行,大幅缩短计算时间。随着NVIDIA、AMD等公司不断推进其GPU的大规模并行架构,面向通用计算的GPU已成为加速可并行应用程序的重要手段。得益于GPU众核(many-core)体系结构,程序在GPU系统上的运行速度相较于单核CPU往往提升几十倍乃至上千倍。
目前,GPU已经发展到了较为成熟的阶段。利用GPU来训练深度神经网络,可以充分发挥其数以千计计算核心的能力,在使用海量训练数据的场景下,所耗费的时间大幅缩短,占用的服务器也更少。如果对适当的深度神经网络进行合理优化,一块GPU卡相当于数十甚至上百台CPU服务器的计算能力,因此GPU已经成为业界在深度学习模型训练方面的首选解决方案。
如何使用GPU?现在很多深度学习工具都支持GPU运算,使用时只要简单配置即可。PyTorch支持GPU,可以通过to(device)函数来将数据从内存中转移到GPU显存,如果有多个GPU还可以定位到哪个或哪些GPU。PyTorch一般把GPU作用于张量(Tensor)或模型(包括torch.nn下面的一些网络模型以及自己创建的模型)等数据结构上。

5.7.1 单GPU加速

使用GPU之前,需要确保GPU是可以使用,可通过torch.cuda.is_available()的返回值来进行判断。返回True则具有能够使用的GPU。 通过torch.cuda.device_count()可以获得能够使用的GPU数量。
如何查看平台GPU的配置信息?在命令行输入命令nvidia-smi即可 (适合于Linux或Windows环境)。图5-28是GPU配置信息样例,从中可以看出共有2个GPU。
图5-28 GPU配置信息


把数据从内存转移到GPU,一般针对张量(我们需要的数据)和模型。对张量(类型为FloatTensor或者是LongTensor等),一律直接使用方法.to(device)或.cuda()即可。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#或device = torch.device("cuda:0")
device1 = torch.device("cuda:1")  
for batch_idx, (img, label) in enumerate(train_loader):
    img=img.to(device)
label=label.to(device)

 对于模型来说,也是同样的方式,使用.to(device)或.cuda来将网络放到GPU显存。

#实例化网络
model = Net()
model.to(device)   #使用序号为0的GPU
#或model.to(device1) #使用序号为1的GPU

 5.7.2 多GPU加速

这里我们介绍单主机多GPU的情况,单机多GPU主要采用的是DataParallel函数,而不是DistributedParallel,后者一般用于多主机多GPU,当然也可用于单机多GPU。
使用多卡训练的方式有很多,当然前提是我们的设备中存在两个及以上GPU。使用时直接用model传入torch.nn.DataParallel函数即可,如下代码:

#对模型
net = torch.nn.DataParallel(model)

这时,默认所有存在的显卡都会被使用。
如果你的电脑有很多显卡,但只想利用其中一部分,如只使用编号为0、1、3、4的四个GPU,那么可以采用以下方式: 

#假设有4个GPU,其id设置如下
device_ids =[0,1,2,3]
#对数据
input_data=input_data.to(device=device_ids[0])
#对于模型
net = torch.nn.DataParallel(model)
net.to(device)

或者

os.environ["CUDA_VISIBLE_DEVICES"] = ','.join(map(str, [0,1,2,3]))
net = torch.nn.DataParallel(model)

其中CUDA_VISIBLE_DEVICES 表示当前可以被PyTorch程序检测到的GPU。
下面为单机多GPU的实现代码。
1)背景说明。这里使用波士顿房价数据为例,共506个样本,13个特征。数据划分成训练集和测试集,然后用data.DataLoader转换为可批加载的方式。采用nn.DataParallel并发机制,环境有2个GPU。当然,数据量很小,按理不宜用nn.DataParallel,这里只是为了说明使用方法。
2)加载数据。

boston = load_boston()
X,y   = (boston.data, boston.target)
 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
#组合训练数据及标签
myset = list(zip(X_train,y_train))

3)把数据转换为批处理加载方式。 批次大小为128,打乱数据。

from torch.utils import data
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
dtype = torch.FloatTensor
train_loader = data.DataLoader(myset,batch_size=128,shuffle=True)

4)定义网络。

class Net1(nn.Module):
    """
    使用sequential构建网络,Sequential()函数的功能是将网络的层组合到一起
    """
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(Net1, self).__init__()
        self.layer1 = torch.nn.Sequential(nn.Linear(in_dim, n_hidden_1))
        self.layer2 = torch.nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2))
        self.layer3 = torch.nn.Sequential(nn.Linear(n_hidden_2, out_dim))
        
 
    def forward(self, x):
        x1 = F.relu(self.layer1(x))
        x1 = F.relu(self.layer2(x1))
        x2 = self.layer3(x1)
        #显示每个GPU分配的数据大小
        print("\tIn Model: input size", x.size(),"output size", x2.size())
        return x2

5)把模型转换为多GPU并发处理格式。

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#实例化网络
model = Net1(13, 16, 32, 1)
if torch.cuda.device_count() > 1:
    print("Let's use", torch.cuda.device_count(), "GPUs")
    # dim = 0 [64, xxx] -> [32, ...], [32, ...] on 2GPUs
    model = nn.DataParallel(model)
model.to(device)

运行结果如下:
Let's use 2 GPUs
DataParallel(
(module): Net1(
(layer1): Sequential(
(0): Linear(in_features=13, out_features=16, bias=True)
)
(layer2): Sequential(
(0): Linear(in_features=16, out_features=32, bias=True)
)
(layer3): Sequential(
(0): Linear(in_features=32, out_features=1, bias=True)
)
)
)
6)选择优化器及损失函数。

optimizer_orig = torch.optim.Adam(model.parameters(), lr=0.01)
loss_func = torch.nn.MSELoss()

7)模型训练,并可视化损失值。

from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(log_dir='logs')
for epoch in range(100):        
    model.train()
    for data,label in train_loader:
        input = data.type(dtype).to(device)
        label = label.type(dtype).to(device)
        output = model(input)       
        loss = loss_func(output, label)
        # 反向传播
        optimizer_orig.zero_grad()
        loss.backward()
        optimizer_orig.step()
        print("Outside: input size", input.size() ,"output_size", output.size())
writer.add_scalar('train_loss_paral',loss, epoch)

运行的部分结果如下:
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
In Model: input size torch.Size([64, 13]) output size torch.Size([64, 1])
Outside: input size torch.Size([128, 13]) output_size torch.Size([128, 1])
从运行结果可以看出,一个批次数据(batch-size=128)拆分成两份,每份大小为64,分别放在不同的GPU上。此时用GPU监控也可发现,两个GPU都同时在使用,如图5-29所示。 

图5-29 同时使用多个GPU的情况
8)通过web查看损失值的变化情况,如图5-30所示。

图5-30 并发运行训练损失值变化情况
图形中出现较大振幅是由于采用批次处理,而且数据没有做任何预处理,对数据进行规范化应该更平滑一些,大家可以尝试一下。
单机多GPU也可使用DistributedParallel,它多用于分布式训练,但也可以用在单机多GPU的训练,配置比使用nn.DataParallel稍微麻烦一点,但是训练速度和效果更好一点。具体配置为:

#初始化使用nccl后端
torch.distributed.init_process_group(backend="nccl")
#模型并行化,使用多进程,可单机或分布式训练
model=torch.nn.parallel.DistributedDataParallel(model)

单机运行时使用下列方法启动:

python -m torch.distributed.launch main.py

 5.7.3使用GPU的注意事项

使用GPU可以提升训练的速度,但如果使用不当,可能影响使用效率,具体使用时要注意以下几点:
• GPU的数量尽量为偶数,奇数的GPU有可能会出现异常中断的情况;
• GPU很快,但数据量较小时,效果可能没有单GPU好,甚至还不如CPU;
• 如果内存不够大,使用多GPU训练的时候可通过设置pin_memory为False,当然使用精度稍微低一点的数据类型有时也有效果。

5.8 小结

本章从机器学习的这个比深度学习更宽泛的概念出发,首先说明其基本任务、一般流程等,然后说明在机器学习中解决过拟合、欠拟合的一些常用技巧或方法。同时介绍了各种激活函数、损失函数、优化器等机器学习、深度学习的核心内容。最后说明在程序中如何设置GPU设备、如何用GPU加速训练模型等内容。这章是深度学习的基础,接下来我们将从视觉处理、自然语言处理、生成式网络等方面,深入介绍深度学习的基础又核心的内容。

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MideaPipe是一个轻量级的Python机器学习框架,支持使用GPU进行模型训练和推理。使用GPU可以大幅提升模型训练和推理的速度,尤其是在处理大规模数据时。 使用MideaPipe进行GPU加速的步骤如下: 1. 确认你的电脑或服务器上已经安装了支持GPU加速的显卡和相应的驱动程序。 2. 安装CUDA和cuDNN。CUDA是NVIDIA提供的并行计算平台,cuDNN是NVIDIA提供的针对深度学习加速库。这两个软件包的安装可以参考NVIDIA官网的文档。 3. 安装TensorFlow-GPU。TensorFlow-GPU是支持GPU加速的TensorFlow版本,安装方法可以参考TensorFlow官网的文档。 4. 在MideaPipe的代码中指定使用GPU。在代码中指定使用GPU的方法如下: ```python import tensorflow as tf from MideaPipe import Pipeline tf.config.experimental.set_memory_growth(tf.config.list_physical_devices('GPU')[0], True) # 创建Pipeline对象并进行模型训练或推理 ``` 在代码中,我们首先导入TensorFlow模块,并调用`set_memory_growth`方法来配置GPU内存的使用方式。这个方法的参数是一个物理GPU设备的句柄,可以通过`list_physical_devices`函数来获取。在这个例子中,我们假定只有一个GPU设备,因此使用了`[0]`来获取第一个设备的句柄。如果有多个GPU设备,可以通过循环来遍历所有设备并进行配置。 5. 运行代码并观察GPU占用情况。在代码运行过程中,可以通过NVIDIA System Monitor等工具来监控GPU的占用情况,以确保代码正确地使用了GPU加速。 需要注意的是,使用GPU加速不仅可以提升模型训练和推理的速度,也会增加系统的功耗和温度。因此在使用GPU加速时,需要注意电源和散热等问题,以避免硬件损坏或系统崩溃等情况的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值