【PyTorch学习03】【手写数字识别02】实践篇

#1 加载必要的库
import torch
import torch.nn as nn #加载网络库
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets,transforms
#2 定义超参数
#  参数   模型学习训练出的,可以通过优化算法进行学习
#  超参数 自己决定的,定义模型结构或优化策略
BATCH_SIZE = 64 #每批处理的数据数量
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") #是否用GPU还是CPU训练
EPOCHS = 10 #训练数据集的轮次
#3 构件pipeline,对图像做处理
pipeline = transforms.Compose([
    transforms.ToTensor(), #将图片转换成tensor格式 pytorch运行的全是tensor
    transforms.Normalize((0.1307,),(0.3081,)) #正则化 模型出现过拟合现象时 降低模型复杂度
])
#过拟合:只认识数据集内的数据 没法举一反三
#4 下载 加载数据
from torch.utils.data import DataLoader

# 下载数据集
train_set = datasets.MNIST("data",train=True,download=True,transform=pipeline) #文件夹的名字

test_set = datasets.MNIST("data",train=False,download=True,transform=pipeline)

# 加载数据
train_loader = DataLoader(train_set,batch_size=BATCH_SIZE,shuffle=True) #shuffle打乱训练 有助于提高精度

test_loader = DataLoader(test_set,batch_size=BATCH_SIZE,shuffle=True)
#如何查看MNIST中的图片
with open("./data/MNIST/raw/train-images-idx3-ubyte","rb") as f:
    file=f.read()

image1 = [int(str(item).encode('ascii'),16) for item in file[16 : 16+784]]
print(image1)

#保存下图片
import cv2
import numpy as np

image1_np = np.array(image1,dtype=np.uint8).reshape(28,28,1)

print(image1_np.shape)

cv2.imwrite("digit.jpg",image1_np)
#5 构件网络模型
class Digit(nn.Module):
    def __init__(self):
        super().__init__()
        #卷积层
        self.conv1 = nn.Conv2d(1,10,5) #1 灰度图片的通道 10 输出通道 5 kernel卷积和
        self.conv2 = nn.Conv2d(10,20,3) #10 输入通道 20 输出通道 3 kernel
        #全连接层
        self.fc1 = nn.Linear(20*10*10,500) #输入通道 输出通道
        self.fc2 = nn.Linear(500,10) #输入通道 输出通道

    def forward(self,x) :
        input_size = x.size(0) #batch_size x 1 x 28 x 28
        x=self.conv1(x) #输入 batch*1*28*28 输出 batch*1*24*24(28-5+1)
        x=F.relu(x) #激活函数 输出
        x=F.max_pool2d(x,2,2) #最大池化层 对图片进行压缩 圈了一块区域作为代表 输出batch*10*12*12

        x=self.conv2(x) #输入batch*10*12*12 输出batch*20*10*10(12-3+1)
        x=F.relu(x)

        x=x.view(input_size,-1) #拉平 平面的拉成一长条 送给网络处理 -1 自动计算维度 20*10*10=2000

        #送入到全连接层
        x=self.fc1(x) #输入 batch*2000 输出batch*500
        x=F.relu(x) #激活 保持shpae不变

        x=self.fc2(x) #输入 batch*500 输出batch*10

        output=F.log_softmax(x,dim=1) #计算分类后 每个数字的概率值 哪个数字的概率最大 就选最大的作为结果

        return output #概率值返回

#卷积层 池化层 激活层 损失函数
#6 定义优化器
model = Digit().to(DEVICE)

optimizer=optim.Adam(model.parameters())
#7 定义训练方法
def train_model(mocel,device,train_loader,potimize,epoch):
    #模型训练
    mocel.train()
    #数据 图片上的标签
    for batch_index,(data,target) in enumerate(train_loader):
        #部署到DEVICE
        data,target=data.to(device),target.to(device)
        #梯度初始化为0
        optimizer.zero_grad()
        #计算后的结果
        output=model(data)
        #计算损失 预测值 真实值
        loss=F.cross_entropy(output,target) #交叉熵损失 针对多分类任务
        #找到10个概率中最大的那个
        #pred=output.max(1,keepdim=True) #1表示横轴 返回每一行中最大的下标
        #反向传播 从右往左 
        loss.backward()
        #前向传播 从上往下 每一层处理完后给下层处理
        optimizer.step()
        if batch_index%3000==0:
            print("Train Epoch:{} \t Loss:{:.6f}".format(epoch,loss.item()))
        
#8 定义测试方法
def test_model(model,device,test_loader):
    #模型验证
    model.eval()
    #正确率
    correct=0.0
    #测试损失
    test_loss=0.0
    with torch.no_grad():#不会计算梯度 也不会进行反向传播
        for data,target in test_loader:
            #部署到device
            data,target=data.to(device),target.to(device)
            #测试数据
            output=model(data)
            #计算测试损失
            test_loss += F.cross_entropy(output,target).item()
            #找到概率值最大的下标
            pred=output.max(1,keepdim=True)[1]
            #累计正确率
            correct += pred.eq(target.view_as(pred)).sum().item()
        test_loss /= len(test_loader.dataset)
        print("Test _Average loss{:.4g} Accuracy {:.3f}\n".format(test_loss,100.0*correct/len(test_loader.dataset)))
#9 调用 方法7 8
for epoch in range(1,EPOCHS+1):
    train_model(model,DEVICE,train_loader,optimizer,epoch)
    test_model(model,DEVICE,test_loader)

最后的结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值