准备知识

1. NumPy

为什么要学 NumPy?弄懂了 NumPy 的 array,可以轻松上手 PyTorch 的 tensor。请看这个对比:torch v.s. numpy

这里毛遂自荐一下我制作的 NumPy视频 ,结合例子、绘图讲解,看过之后会明白 shape, 轴运算和轴变换等等重要知识点。

2. OOP(面向对象编程)

PyTorch 里面数据集和模型都是以对象的方式定义的。因此,了解一点面向对象编程的知识很有帮助。当然,你也可以先试试看,觉得困惑再补充知识。

3.Deep Learning 基础知识

了解 Deep Neural Network 基础知识,比如:网络架构(可阅读我的文章:李宏毅老师《机器学习》课程笔记-1深度学习简介),Back Propagation 等,对于理解代码很有帮助。

PyTorch tutorial

我先根据 Pytorch 网站上的 tutorial 来学 PyTorch,有两个实例教程:

1.A 60 Minute Blitz-cifar10数据集例子

2.Quickstart-FashionMNIST数据集例子

收获:发现 Deep Neural Network 的流程为:准备数据–>定义 model, criterion,optimizer–>训练和测试

接着学习了李宏毅老师《机器学习2021》Homework1-2 助教老师的示例代码:

1.李宏毅老师《机器学习2021》homework1 sample code: (By Heng-Jui Chang) https://github.com/ga642381/ML2021-Spring/blob/main/HW01/HW01.ipynb

2.李宏毅老师《机器学习2021》homework2 sample code: https://github.com/ga642381/ML2021-Spring/blob/main/HW02/HW02-1.ipynb

收获:补充了一些知识,包括自定义数据集对象 Dataset,如何在训练中加入验证。

参考以上示例代码,我总结了一下用 PyTorch 实现 Deep Neural Network 的常用代码(或者说 pipeline)。这是基于我对知识点的学习和理解,可能有疏漏和错误之处,欢迎交流,请多多指教,谢谢!

Deep Neural Network pipeline

下图所示为训练一个 Deep Neural Network 模型的基本流程。一般有 5 个步骤,接下来我会依次介绍各步骤的工作和常用代码。代码中有的地方并没有写细节,只是给出了框架。你可以把这个代码当作模板或是 cheatsheet,对照着示例代码学习,帮助你更好地理清思路,然后可以照着这个框架试着写一写。

PyTorch DNN pipeline

1. Data
1.1 load the dataset

PyTorch tutorial 使用的是公开数据集。在 torchvision.datasets 模块有一些函数,可以下载并定义知名的公开数据集。

如果是外部数据集,就需要自己定义数据集对象。这里假设数据集名为 “MyDataset”,要定义三个函数,分别是:

  1. __init__ :初始化,把 data(输入) 和 label(如果是训练集)整理后成对放在一起,一般是用 pandas 或 NumPy 读取数据的,要转成 PyTorch 中的 tensor。
  2. __getitem__ :根据索引,返回某条数据的值。
  3. __len__ :返回数据集大小。
import torch
from torch.utils.data import Dataset,DataLoader

class MyDataset():
    def __init__(self,data,label=None):
        if label is not None: #train set/val set
            self.data=...
            self.label=...
        else: #test set
            self.data=...
            
        
    def __getitem__(self,index):
        if self.label is not None: #for train set/val set
            return self.data[index],self.label[index]
        else: #for test set(no label)
            return self.data[index]
        
    def __len__(self):
        return len(self.data)
        
1.2 DataLoader

DataLoader 其实就是对数据分组 (batch) 打包。Load 是载重的意思,你可以把 DataLoader 想象成是去仓库 (Dataset)运东西的卡车,每次都装一样多的货物 (设置 batch_size)。

还有一点要注意的是,training set 要把数据打乱 (shuffle) 再分组。validation set 和 test set 不用做 shuffle。

train_loader=DataLoader(trainset,batch_size=batch_size,shuffle=True)
test_loader/val_loader=DataLoader(testset/valset,batch_size=batch_size,shuffle=False)
2. Define the model

建立 model object,我感觉这一步像搭积木,简单有趣。当然,这要感谢 Pytorch 的开发者们写好了这些模块,直接从 torch.nn 中调用就可以。这里假设模型名为 “MyNet”,要定义两个函数,分别是:

  1. __init__(self) :定义模块。可以写单个模块,如 nn.Linear(), nn.Sigmoid()。也可以用 nn.Sequential() 串起几个模块。
  2. forward(self,x) :按网络架构从输入到输出走一遍。
import torch.nn as nn

class MyNet(nn.Module):
    def __init__(self):
        super(MyNet,self).__init__()
        self.module1=nn.Linear(...)
        self.module2=nn.Sigmoid(...)
        #以pipeline的方式写几个函数
        self.module3=nn.Sequential(nn.Linear(...),nn.ReLU(...))
        
    def forward(self,x):
        x=self.module1(x)
        x=self.module2(x)
        x=self.module3(x)
        return x             
3. Define criterion(loss function) and optimizer

我们知道,机器学习三要素:model, criterion, optimizer,这一步就要设定。先把上一步定义的 MyNet() 实例化,创建模型。如果使用 GPU 加速,也要在这一步设置模型移动到 (move to) GPU 上。然后设置 criterion 和 optimizer,在 torch 中都有函数可调用。

import torch.optim as optim
device="cuda" if torch.cuda.is_available else "cpu" #查看是否有GPU可用 

model=MyNet().to(device)#实例化和GPU
criterion=nn.CrossEntropyLoss()/nn.MSELoss() #分类用CrossEntropy,回归用MSE
optimizer=optim.SGD(model.parameters(),lr=.., momentum=...) #或optim.Adam(...)
4. training and validation

这里写了两个函数:train(): 处理训练集数据和 val(): 处理验证集数据,train( ) 函数中会调用 val( ) 函数。具体来说,就是在每个 epoch, 在 training set 做完 training 之后,在 validation set 做 validation,计算 val_loss。如果 val_loss 小于最小值 min_val_loss,就保存此时的模型参数(model.state_dict()) ,也就是 weights, bias 等参数。

注意:1.使用 GPU 加速的话,要设置数据 move to GPU。

  1. dataloader 的两个参数,可能在计算 average loss, accuracy 时会用到:

(1)数据集的长度:size=len(dataloader.dataset)

(2)分组数:num_batches=len(dataloader)

4.1 training
def train(n_epochs,dataloader,model,criterion,optimizer):
    train_loss=0
    min_val_loss=1000  
    num_batches=len(dataloader)
    
    model.train() #重要!设置模式
    for i in range(n_epochs):
        print(f"Epoch:{i+1}")
        for batch_idx,(inputs,labels) in enumerate(dataloader):
            inputs,labels=inputs.to(device),labels.to(device) #GPU
            optimizer.zero_grad()
            outputs=model(inputs)
            loss=criterion(outputs,labels)
            loss.backward()
            optimizer.step()
            
            #(可选)每隔100个batches,打印一次结果
            if batch_idx%100==0:
                print(f"current batch:{batch_idx}/all:{num_batches}, 
                      loss:{loss.item():.6f}")

            train_loss+=loss.item()       
        train_loss=train_loss/num_batches
        print(f"average training loss:{train_loss:.6f}")              
        
        #validation              
        val_loss=val(dataloader,model,criterion)
        print(f"average val loss:{val_loss:.6f}")
        if val_loss < min_val_loss:
            min_val_loss=val_loss
            #保存模型参数
            print("saving the model...")
            torch.save(model.state_dict(),".\model.pth")   
4.2 validation
def val(dataloader,model,criterion):  
    val_loss=0
    num_batches=len(dataloader)
    
    model.eval() #重要!设置模式
    with torch.no_grad():    
        for inputs,labels in dataloader:
            inputs,labels=inputs.to(device),labels.to(device) #GPU 
            outputs=model(inputs) 
            val_loss+=criterion(outputs,labels).item()
    val_loss=val_loss/num_batches   
    return val_loss
5. Test the model

首先要加载训练中得到的最佳模型参数,然后把测试集输入模型,输出结果。

注意:1.使用 GPU 加速的话,要设置数据 move to GPU。训练完的预测结果,又要转换回 cpu,numpy 的格式。

2.对于分类问题,预测得到的是各类别的概率,不能直接当作结果输出,需要判断类别(选择概率最大的类别)后得到结果。

#加载优化好的模型参数
model=MyNet().to(device)
model.load_state_dict(torch.load(".\model.pth"))

def test(dataloader,model):    
    predicts=[]
    
    model.eval() #重要!设置模式
    with torch.no_grad():
        for inputs in dataloader:
            inputs=inputs.to(device) #GPU 
            outputs=model(inputs)       
            #根据每个batch的outputs,输出预测结果
            pred=...(from outputs)
            #存入predicts_all中
            predicts.append(pred)        
    return predicts
补充

在训练中会用到随机,比如在 DataLoader 中,要设置 shuffle,打乱训练数据。如果想保持每次产生的随机分组相同,可以在代码的开头设定 random seed。

def set_seed(seed):
    np.random.seed(seed)
    torch.manual_seed(seed)
    if torch.cuda.is_available(): 
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark=False
    torch.backends.cudnn.deterministic=True

myseed=42
set_seed(myseed)

觉得本文不错的话,请点赞支持一下吧,谢谢!

关注我 宁萌Julie,互相学习,多多交流呀!

欢迎点击 李宏毅老师《机器学习》笔记–合辑目录,阅读更多笔记

参考:

1.A 60 Minute Blitz-cifar10数据集例子: https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html

2.Quickstart-FashionMNIST数据集例子: https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html

3.李宏毅老师《机器学习2021》homework1 sample code: (By Heng-Jui Chang) https://github.com/ga642381/ML2021-Spring/blob/main/HW01/HW01.ipynb

4.李宏毅老师《机器学习2021》homework2 sample code: https://github.com/ga642381/ML2021-Spring/blob/main/HW02/HW02-1.ipynb

5.介绍了模型参数的保存和加载:https://pytorch.org/tutorials/beginner/saving_loading_models.html

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐