从0设计并训练一个神经网络

以下使用手写数字识别如何涉及,实现并训练一个标准的前馈神经网络

我们涉及并训练一个三层的神经网络,以数字图像作为输入,经过神经网络的计算就会识别图像中的数字是几,从而实现数字图像的分类

1.神经网络的设计和实现

首先明确输入图像数据的大小和格式,我们要处理分辨率为28*28的灰色通道图像,这样的灰色通道包含了28*28=784个数据点,我们要先将他展平为1*784的向量,再将这个向量输入到神经网络当中。

我们使用一个三层神经网络来处理图片对应的向量x

隐藏层用于特征提取,将输入的特征向量处理为更高级的特征向量,由于手下数字图像并不复杂,将隐藏层的神经个数设置为256,输入层和隐藏层之间就会有一个784*256大小的线性层,该256维的输出向量会继续向前传播到达输出层,由于最终要将数字图像识别为0~9,10种可能的数字,因此输出层需要定义10个神经元,对应着10种数字。这10维的输出向量就代表着十个数字的预测得分。为了继续得到10个数字的预测概率,我们还要将输出层的输出输入到softmax层,softmax层会将10维的向量转换为10个概率值

 

import torch
from torch import nn

#定义神经网络Network
class Network(nn.Moudle):
    def __init__(self):
        super().__init__()
        #线性层1,输入层和隐藏层之间的线性层
        self.layer1 = nn.Linear(784,256)
        #线性层2,隐藏层和输出层之间的线性层
        self,layer2 = nn.Linear(256,10)

    # 在向前传播,forward函数中,输入为图像x
    def forward(self,x):
        x = x.view(-1,28*28) #使用view函数,将x展平
        x = self.layer1(x) #将x输入至layer1
        x = torch relu(x)  #使用rulu激活
        return self.layer2(x) #输入至layer2计算结果


#这里我们没有直接定义softmax层
#这是因为后面会使用CrossEntropyloss损失函数
#在这个损失函数中,会实现softmax的计算

2.训练数据的准备和处理 

手写数字识别的训练数据可以直接使用MNISTS数据集,可以从torchvision.datasets中获取,将数据分别保存到train和test两个目录中,其中train有60000个数据,用作训练,test有10000个数据,用作测试。这两个目录中都包含了10个子目录,子目录的名字就是对应图像中的数字

from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader

#初学者在学习这一部分时,只要知道大致的数据处理流程即可
if __name__ == '__main__':
    #实现图像的预处理pipeline
    transform = transforms.Compose([
        transforms.Grayscale(num_output_channels=1), #转换为单通道灰度图
        transforms.ToTensor() #转换为张量
    ])
    # 使用ImageFolder函数,读取数据文件夹,构建数据集dataset
    # 这个函数会将保存数据的文件夹的名字,作为数据的标签,组织数据
    # 例如,对于名字为“3”的文件夹
    # 会将“3”作为文件夹中图像数据的标签,和图像配对,用于后续的训练,使用起来非常的方便
    train_dataset = datasets.ImageFolder(root='./mnist_images/train',transform=transform)
    test_dataset = datasets.ImageFolder(root='./mnist_images/test',transform=transform)
    
    #使用train_loder,实现小批量的数据读取
    #这里设置小批量的大小,batch_size=64.也就是每个批次,包括64个数据
    train_loader = DataLoader(train_dataset,batch_size=64,shuffle=True)
    #打印train_loader的长度
    print("train_loader length:",len(train_loader))
    #60000个训练数据,如果每个小批量,读入64个样本,那么60000个数据会被分成938组
    #计算938*64=60032,这说明最后一组,会不够64个数据


    #循环遍历train_loader
    #每一次循环,都会取出64个图像数据,作为一个小批量batch 
    for batch_idx == 3:  #打印前3个batch观察
        break
    print("batch_idx:",batch_idx)
    print("data.shape:",data,shape) #数据的尺寸
    print("label:",label.shape) #图像中的数字
    print(label)

程序会输出 data.shape:torch.Size([64,1,28,28])   每组数据包括64个图像,每个图像有1个灰色通道,图像的尺寸是28*28

3.模型的训练和测试

inprot torch 
from torch import nn
from torch import optim
from model import Network
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader

if __name__ == '__main__':
    #图像的预处理
    transform = transforms.Compose([
        transforms.Grayscale(num_output_channels=1), #转换为单通道灰度图
        transforms.ToTensor() #转换为张量
    ])
   
    #读入并构造数据集
    train_dataset = datasets.ImageFolder(root='./mnist_images/train',transform=transform)
    print("train_datase length:",len(train_dataset))
    
    #使用train_loder,实现小批量的数据读取
    train_loader = DataLoader(train_dataset,batch_size=64,shuffle=True)
    print("train_loader length:",len(train_loader))
    
    #使用Pytorch训练模型时,需要创建三个对象:
    model = Network() #1.模型本身,它就是我们设计的神经网络
    optimizer = optim.Adam(model.parameters()) #2.优化器,优化模型中的参数
    criterion = nn.CrossEntropyLoss() #3.损失函数,分类问题,使用交叉熵损失误差


    #进入模型的迭代循环
    for epoch in range(10): #外层循环,代表了整个训练数据集的遍历次数
        #整个训练集要循环多少轮,是10次,20次或者100次都是可能的,
        #内层循环使用train_loader,进行小批量的数据读取
        for batch_idx,(data,label) in enumerate(train_loader):
        #内层每循环一次,就会进行一次梯度下降算法
        #包括了5个步骤:
        output = model(data) #1.计算神经网络先前传播结果
        loss = criterion(output,label) #2.计算output和标签label之间的损失loss
        loss.backward() #3.使用backward计算梯度
        optimizer.step() #4.使用optimizer.step更新参数
        optimizer.zero_grad() #5.将梯度清零
        #这5个步骤,是使用pytroch框架训练模型的定式,初学的时候,先记住就可以了
        
        #每迭代100个小批量,就打印一次模型的损失,观察训练的过程
        if batch_idx %100 == 0:
            print(f"Epoch{epoch+1}/10"
                  f"| Batch{batch_idx}/{len(train_loader)}"
                  f"|Loss:{loss.item():.4f}")
    torch.save(model.state_dict(),'mnist.pth')#保存模型

对模型进行测试

from model import Network
from torchvision import transforms
from torchvision import datasets
import torch 

if __name__=='__main__':
    transform = transforms.Compose([
        transforms.Grayscale(num_output_channels=1),
        transforms.ToTensor()
    ])
    #读取测试数据集
    test_dataset = datesets.ImageFolder(root='./mninst_images/test',transform=transform)
    print("test_dataset lengeh:",len(test_dataset))
    
    model= Network() #定义神经网络模型
    model.load_state_dict(torch.load('mnist.pth')) #加载刚刚训练好的模型文件
    right = 0 #保存正确识别的数量
    for i,(x,y) in enumerate (test_dataset):
        output = model(x) #将其中的数据x输入到模型
        predict = output.argmax(1).item() #选择概率最大标签的作为预测结果
        #对比预测值predict和真实标签y
        if predict == y:
            right+=1
        else:
            #将识别错误的样例打印了出来
            img_path = test_dataset.samples[i][0]
            print(f"wrong case: predict = {predict} y= {y} img_path={img_path}")
            
    #计算出测试效果
    sample_num = len(test_dataset)
    acc=right*1.0/sample_num
    print("test accuracy =%d/%d=%.3lf"%(right,sample_num,acc))

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值