Pytorch实战总结篇之使用GPU训练模型

1. 写在前面

这段时间一直在持续学习Pytorch, 也大约整理了20篇左右的笔记, 主要包括系统学习Pytorch的10篇, 这里面主要是从原理的层次看Pytorch的运行机制, 一方面是可以大致上对学习Pytorch有一个整体的框架, 另一方面是能理解很多知识的背后原理, 然后是Pytorch的入门与实战8篇, 这里面是使用Pytorch进行一些实战任务, 从图像到语音, 大致上可以知道Pytorch在各个领域是怎么发挥作用的, 但是经过前面的这些文章, 可能依然无法把Pytorch运用起来, 第一个系列是偏底层原理和知识框架, 而第二个系列作为一个桥梁纽带, 更多的是介绍图像和语音方面的知识, 然后用Pytorch进行了一些任务的完成,如果换了任务, 可能依然不知道如何使用Pytorch, 所以这个终结系列的几篇文章从纯使用的角度来总结Pytorch,毕竟Pytorch还是作为一种工具, 下面我们就来看看真正的使用方法。

通过前面的学习, 使用Pytorch实现神经网络建模一般包括数据准备、模型建立、模型训练、模型评估使用和保存, 所以接下来会整理四篇文章对这几方面进行使用总结。今天是最后一篇, 通过前面的三篇文章, 已经可以使用Pytorch完成相应的任务了, 这次整理一些番外的技巧, 那就是GPU加速训练。

深度学习的训练过程常常非常耗时,一个模型训练几个小时是家常便饭,训练几天也是常有的事情,有时候甚至要训练几十天。训练过程的耗时主要来自于两个部分,一部分来自数据准备,另一部分来自参数迭代。

  • 当数据准备过程还是模型训练时间的主要瓶颈时,我们可以使用更多进程来准备数据。
  • 当参数迭代过程成为训练时间的主要瓶颈时,我们通常的方法是应用GPU来进行加速。

这个也是直接参考的下面的链接。 具体的可以去GitHub上进行学习。

2. Pytorch使用GPU加速

Pytorch中使用GPU加速模型非常简单,只要将模型和数据移动到GPU上。核心代码只有以下几行。

# 定义模型
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device) # 移动模型到cuda

# 训练模型

features = features.to(device) # 移动数据到cuda
labels = labels.to(device) # 或者  labels = labels.cuda() if torch.cuda.is_available() else labels

如果要使用多个GPU训练模型,也非常简单。只需要在将模型设置为数据并行风格模型。 则模型移动到GPU上之后,会在每一个GPU上拷贝一个副本,并把数据平分到各个GPU上进行训练。核心代码如下。

# 定义模型
if torch.cuda.device_count() > 1:
    model = nn.DataParallel(model) # 包装为并行风格模型

# 训练模型
features = features.to(device) # 移动数据到cuda
labels = labels.to(device) # 或者 labels = labels.cuda() if torch.cuda.is_available() else labels

3. 一些和GPU有关的基本操作汇总

# 1,查看gpu信息
if_cuda = torch.cuda.is_available()
print("if_cuda=",if_cuda)

# GPU 的数量
gpu_count = torch.cuda.device_count()
print("gpu_count=",gpu_count)


# 2,将张量在gpu和cpu间移动
tensor = torch.rand((100,100))
tensor_gpu = tensor.to("cuda:0") # 或者 tensor_gpu = tensor.cuda()
print(tensor_gpu.device)
print(tensor_gpu.is_cuda)

tensor_cpu = tensor_gpu.to("cpu") # 或者 tensor_cpu = tensor_gpu.cpu() 
print(tensor_cpu.device)

# 3,将模型中的全部张量移动到gpu上
net = nn.Linear(2,1)
print(next(net.parameters()).is_cuda)
net.to("cuda:0") # 将模型中的全部参数张量依次到GPU上,注意,无需重新赋值为 net = net.to("cuda:0")
print(next(net.parameters()).is_cuda)
print(next(net.parameters()).device)

# 4,创建支持多个gpu数据并行的模型
linear = nn.Linear(2,1)
print(next(linear.parameters()).device)

model = nn.DataParallel(linear)
print(model.device_ids)
print(next(model.module.parameters()).device) 

#注意保存参数时要指定保存model.module的参数
torch.save(model.module.state_dict(), "./data/model_parameter.pkl") 

linear = nn.Linear(2,1)
linear.load_state_dict(torch.load("./data/model_parameter.pkl")) 

# 5,清空cuda缓存
# 该方在cuda超内存时十分有用
torch.cuda.empty_cache()

4. 使用线性回归模型的范例

# 准备数据
n = 1000000 #样本数量

X = 10*torch.rand([n,2])-5.0  #torch.rand是均匀分布 
w0 = torch.tensor([[2.0,-3.0]])
b0 = torch.tensor([[10.0]])
Y = X@w0.t() + b0 + torch.normal( 0.0,2.0,size = [n,1])  # @表示矩阵乘法,增加正态扰动

# 移动到GPU上
print("torch.cuda.is_available() = ",torch.cuda.is_available())
X = X.cuda()
Y = Y.cuda()

# 定义模型
class LinearRegression(nn.Module): 
    def __init__(self):
        super().__init__()
        self.w = nn.Parameter(torch.randn_like(w0))
        self.b = nn.Parameter(torch.zeros_like(b0))
    #正向传播
    def forward(self,x): 
        return x@self.w.t() + self.b
        
linear = LinearRegression() 

# 移动模型到GPU上
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
linear.to(device)

# 训练模型
optimizer = torch.optim.Adam(linear.parameters(),lr = 0.1)
loss_func = nn.MSELoss()

def train(epoches):
    tic = time.time()
    for epoch in range(epoches):
        optimizer.zero_grad()
        Y_pred = linear(X) 
        loss = loss_func(Y_pred,Y)
        loss.backward() 
        optimizer.step()
        if epoch%50==0:
            print({
    
    "epoch":epoch,"loss":loss.item()})
    toc = time.time()
    print("time used:",toc-tic)
    
train(500)

5. torchkeras使用单GPU范例

这个对应的CPU训练就是上一篇文章的第三种方法, 这里只需要在模型编译的时候指定GPU

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

model.compile(loss_func = nn.CrossEntropyLoss(),
             optimizer= torch.optim.Adam(model.parameters(),lr = 0.02),
             metrics_dict={
    
    "accuracy":accuracy},device = device) # 注意此处compile时指定了device

dfhistory = model.fit(3,dl_train = dl_train, dl_val=dl_valid, log_step_freq=100) 

6. torchkeras使用多GPU范例

注:以下范例需要在有多个GPU的机器上跑。如果在单GPU的机器上跑,也能跑通,但是实际上使用的是单个GPU。数据准备部分和上一篇的一样, 这里定义模型的时候要注意:

class CnnModule(nn.Module):
    def __init__(self):
        super().__init__()
        self.layers = nn.ModuleList([
            nn.Conv2d(in_channels=1,out_channels=32,kernel_size = 3),
            nn.MaxPool2d(kernel_size = 2,stride = 2),
            nn.Conv2d(in_channels=32,out_channels=64,kernel_size = 5),
            nn.MaxPool2d(kernel_size = 2,stride = 2),
            nn.Dropout2d(p = 0.1),
            nn.AdaptiveMaxPool2d((1,1)),
            nn.Flatten(),
            nn.Linear(64,32),
            nn.ReLU(),
            nn.Linear(32,10)]
        )
    def forward(self,x):
        for layer in self.layers:
            x = layer(x)  
        return x

net = nn.DataParallel(CnnModule())  #Attention this line!!!   这一行, 要封装成并行的方式
model = torchkeras.Model(net)

model.summary(input_shape=(1,32,32))

下面模型训练

from sklearn.metrics import accuracy_score

def accuracy(y_pred,y_true):
    y_pred_cls = torch.argmax(nn.Softmax(dim=1)(y_pred),dim=1).data
    return accuracy_score(y_true.cpu().numpy(),y_pred_cls.cpu().numpy()) 
    # 注意此处要将数据先移动到cpu上,然后才能转换成numpy数组

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.compile(loss_func = nn.CrossEntropyLoss(),
             optimizer= torch.optim.Adam(model.parameters(),lr = 0.02),
             metrics_dict={
    
    "accuracy":accuracy},device = device) # 注意此处compile时指定了device

dfhistory = model.fit(3,dl_train = dl_train, dl_val=dl_valid, log_step_freq=100) 

保存的时候, 也需要注意一下:

# save the model parameters
torch.save(model.net.module.state_dict(), "model_parameter.pkl")  # 这里的model.net.module

net_clone = CnnModel()
net_clone.load_state_dict(torch.load("model_parameter.pkl"))

model_clone = torchkeras.Model(net_clone)
model_clone.compile(loss_func = nn.CrossEntropyLoss(),
             optimizer= torch.optim.Adam(model.parameters(),lr = 0.02),
             metrics_dict={
    
    "accuracy":accuracy},device = device)
model_clone.evaluate(dl_valid)

这一块的相应报错, 可以参考我整理的初级篇的最后一篇文章。

参考

猜你喜欢

转载自blog.csdn.net/wuzhongqiang/article/details/108881845