老饼讲解-深度学习 机器学习 神经网络 深度学习
pytorch模型

【例子】pytorch训练一个卷积神经网络

作者 : 老饼 发表日期 : 2024-03-15 04:18:41 更新日期 : 2024-04-02 02:41:46
本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com






    01. pytorch训练一个卷积神经网络     




本节介绍手写数字样本数据




      pytorch训练一个卷积神经网络    


手写数字数据集MNIST是pytorch的自带数据之一,利用torchvision.datasets.MNIST就可以下载
手写数字数据集MNIST包含了10个手写数字(0-9)的7W个样本(训练样本6W个,测试样本1W个)
MNIST样本示例如下:
  
每个样本是28*28的单通道灰度图片
下面使用pytorch实现一个卷积神经网络,用于数字识别,
 具体代码如下:
import torch
from   torch import nn
from   torch.utils.data   import DataLoader
import torchvision
import numpy as np

#--------------------模型结构--------------------------------------------
# 卷积神经网络的结构
class ConvNet(nn.Module):
    def __init__(self,in_channel,num_classes):
        super(ConvNet, self).__init__()
        self.nn_stack=nn.Sequential(
            #--------------C1层-------------------
            nn.Conv2d(in_channel,3, kernel_size=5,stride=1,padding=2),
            nn.ReLU(inplace=True),  
            nn.AvgPool2d(kernel_size=2,stride=2),
            # 输出14*14
            #--------------C2层-------------------
            nn.Conv2d(3,6, kernel_size=5,stride=1,padding=2),
            nn.ReLU(inplace=True),
            nn.AvgPool2d(kernel_size=2,stride=2),
            # 输出7*7*6
            #--------------全连接层F3----------
            nn.Flatten(),          # 对C2的结果进行展平
            nn.Linear(294, 80),  
            nn.ReLU(inplace=True),                                   
            #--------------全连接层F4----------                      
            nn.Linear(80, num_classes)                       
            )
    def forward(self, x):
        y = self.nn_stack(x)
        return y

#-----------------------模型训练---------------------------------------
# 参数初始化函数
def init_param(model):
    # 初始化权重阈值                                             
    param_dict = dict(model.named_parameters())                             # 获取模型的参数字典
    for key in  param_dict:                                                 # 历遍每个参数,对其初始化
        param_name = key.split(".")[-1]                                     # 获取参数的尾缀作为名称
        if (param_name=='weight'):                                          # 如果是权重
            torch.nn.init.normal_(param_dict[key],mean=0,std=0.01)          # 则正态分布初始化
        elif (param_name=='bias'):                                          # 如果是阈值
            torch.nn.init.zeros_(param_dict[key])                           # 则初始化为0

# 训练函数                                                                                     
def train(dataloader,model,optimizer,epochs,goal,device):                                      
    for epoch in range(epochs):                                                                
        print('-----------当前epoch:',str(epoch),'----------------')                           
        for batch, (imgs, labels) in enumerate(dataloader):                 
		    # -----训练模型-----                                            
            x, y = imgs.to(device), labels.to(device)                       # 将数据发送到设备
            optimizer.zero_grad()                                           # 将优化器里的参数梯度清空
            py   = model(x)                                                 # 计算模型的预测值   
            loss = lossFun(py, y)                                           # 计算损失函数值
            loss.backward()                                                 # 更新参数的梯度
            optimizer.step()                                                # 更新参数
            if(batch%10==0):                                                # 每10批打印一次结果
                print('loss:',loss.data)                                    # 打印损失函数值
        # -----------验证数据误差---------------------------                
        err_rate = 1-calAcc(model,dataloader,device)                        # 计算验证数据集的错误率
        print('本次训练样本错误率:',err_rate)                                # 打印本次训练样本错误率
        if(err_rate<=goal):                                                 # 检查退出条件
            break                                                           
# 计算数据集的准确率                                                        
def calAcc(model,dataLoader,device):                                        
    py = np.empty(0)                                                        # 初始化预测结果
    y  = np.empty(0)                                                        # 初始化真实结果
    for batch, (imgs, labels) in enumerate(dataLoader):                     # 逐批预测
        cur_py =  model(imgs.to(device))                                    # 计算网络的输出
        cur_py = torch.argmax(cur_py,axis=1)                                # 将最大者作为预测结果
        py     = np.hstack((py,cur_py.detach().cpu().numpy()))              # 记录本批预测的y
        y      = np.hstack((y,labels))                                      # 记录本批真实的y
    acc_rate = sum(y==py)/len(y)                                            # 计算测试样本的准确率
    return acc_rate                                                            

#--------------------------主流程脚本--------------------------------------
#-------------------加载数据--------------------------------
train_data = torchvision.datasets.MNIST(
    root       = 'D:\pytorch\data'                                          # 路径,如果路径有,就直接从路径中加载,如果没有,就联网获取
    ,train     = True                                                       # 获取训练数据
    ,transform = torchvision.transforms.ToTensor()                          # 转换为tensor数据
    ,download  = True                                                       # 是否下载,选为True,就下载到root下面
    ,target_transform= None)                                                
val_data = torchvision.datasets.MNIST(
    root       = 'D:\pytorch\data'                                          # 路径,如果路径有,就直接从路径中加载,如果没有,就联网获取
    ,train     = False                                                      # 获取测试数据
    ,transform = torchvision.transforms.ToTensor()                          # 转换为tensor数据
    ,download  = True                                                       # 是否下载,选为True,就下载到root下面
    ,target_transform= None)                                                
                                                                            
#-------------------模型训练--------------------------------                
trainLoader = DataLoader(train_data, batch_size=1000, shuffle=True)         # 将数据装载到DataLoader
valLoader   = DataLoader(val_data  , batch_size=1000)                       # 将验证数据装载到DataLoader 
device      = torch.device('cuda' if torch.cuda.is_available() else 'cpu')  # 设置训练设备  
model       = ConvNet(in_channel =1,num_classes=10).to(device)              # 初始化模型,并发送到设备  
lossFun     = torch.nn.CrossEntropyLoss()                                   # 定义损失函数为交叉熵损失函数
optimizer   = torch.optim.SGD(model.parameters(), lr=0.01,momentum =0.9)    # 初始化优化器
train(trainLoader,model,optimizer,1000,0.01,device)                         # 训练模型,训练100步,错误低于1%时停止训练

# -----------模型效果评估--------------------------- 
model.eval()                                                                # 将模型切换到评估状态(屏蔽Dropout)
train_acc_rate = calAcc(model,trainLoader,device)                           # 计算训练数据集的准确率
print("训练数据的准确率:",train_acc_rate)                                    # 打印准确率
val_acc_rate = calAcc(model,valLoader,device)                               # 计算验证数据集的准确率
print("验证数据的准确率:",val_acc_rate)                                      # 打印准确率







     运行结果    


运行结果如下:
 
  
可以看到,模型的训练准确率与验证数据的准确率都达到了极高的水平,说明模型是有效的





好了,在pytorch中实现一个CNN的例子展示就到这里了~







 End 






联系老饼