栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

PyTorch 05—手写数字分类-全连接模型

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

PyTorch 05—手写数字分类-全连接模型

使用torchvision加载内置数据集

torchvision内置了常用数据集和最常见的模型,其中,最常见的两个包就是datasets和models,另外它还内置了转换数据集的办法,叫transforms,它是一系列的转换数据集的方法。

transforms提供的ToTensor()方法是最常用的转换,可以将我们读取的图片或者其他数据转换成tensor,它主要有三个作用:

将我们读取的图片或者其他类型的数据转换成一个tensor;会将数据归一化,转化到0~1之间;会将通道放到第一维度上,比如说用python的pillow库读入一张图片,它的表现形式是 [长,宽,通道数],经过ToTensor后通道数会放在第一个维度上,即[通道数,长,宽]。


加载数据集 
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim 
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

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

# 定义数据要做哪些变换
# transforms为我们提供了Compose方法,我们可以将所有的这些变换都以列表的形式放在Compose里面。
transformation = transforms.Compose([
                 transforms.ToTensor(), # 这个转换最常用的转换,在处理图片的过程当中是非常重要的。
                 # transforms.Normalize(),# 标准化到-1~1之间。这一步并不是必须的。
])

加载数据集

# datasets.MNIST会返回一个dataset数据类型,可以用来创建DataLoader。
# 第一个参数是要把下载下来的数据集放在哪个位置
# 第二个参数表示这个数据是否是训练数据
# 第三个参数表示是否要做变换
# 第四个参数表示数据集是否要下载下来
train_ds = datasets.MNIST('data/',train=True,transform=transformation,download=True)

test_ds = datasets.MNIST('data/',train=False,transform=transformation,download=True)

#创建dataloader
train_dl = DataLoader(train_ds,batch_size=64,shuffle=True)
test_dl = DataLoader(test_ds,batch_size=256,shuffle=False) # 测试数据集并不需要做反向传播,占用的内存和显存都比较少,所以批次大小可以稍微大一些。

认识一下数据集

imgs,labels = next(iter(train_dl)) # 取出一个批次的数据。iter(train_dl)生成迭代器
# imgs.shape 是torch.Size([64, 1, 28, 28]),0维度是批次,一维度是channel
# 在pytorch里面图片的表示形式: 【batchSize, channel(通道), height, width】

img = imgs[0] # 取出第一张图片绘图
img.shape # 结果是:torch.Size([1, 28, 28]),单张图片没有批次大小

img = img.numpy() #我们把img这张图片进行一个绘图,需要把tensor转换为ndarray

"""
img是 [1,28,28] ,第0个维度是通道数,其实并没有什么卵用,我们要squeeze掉
squeeze就是删除单维度条目,即把shape中为1的维度去掉
"""
img = np.squeeze(img)
img.shape # 结果:(28, 28)

plt.imshow(img) # imshow就是imageShow,绘制图片

labels[0] # 查看img对应的标签

运行结果:

 

 

可以看到,标签与图片是一一对应的。


# 定义一个显示图片的函数
def imshow(img):
    np_img = img.numpy()
    np_img = np.squeeze(np_img)
    plt.imshow(np_img)

#绘制返回一个批次数据的前10张图片
plt.figure(figsize=(10,1)) # 创建一张画布,画布大小 1行10列。figsize=(宽,高)
for i,img in enumerate(imgs[:10]): 
    plt.subplot(1,10,i+1)
    imshow(img)

labels[:10]

 运行结果:

 

创建模型 

 

我们要将 [1,28,28] 这样的数据格式做展平,展平成 [28*28] 这么长的一个tensor,然后将这个tensor连接在linear层...,展平的处理实际上取消掉了模型中的空间维度,但还是可以做出一些效果出来。

 创建模型。使用全连接的模型
将数据做展平处理,变成28X28的一个tensor
再把这个tensor连接到linear层,再连接到输出,创建一个多分类的模型。

模版代码:
1. 创建输入(dataloader)
2. 创建模型(model)
3  创建损失函数

class Model(nn.Module):
    def __init__(self):
    
        #首先要继承父类中所有的变量
        super().__init__()
        
        # 开始初始化所有的层
        self.linear1 = nn.Linear(28*28,120 ) # 第一个线性层。将输入的28*28个特征输出到120个隐藏层单元。
        self.linear2 = nn.Linear(120,84) 
        self.linear3 = nn.Linear(84,10)  # 输出层。因为是10分类,所以输出特征长度为10。
       
    def forward(self,input):
        # forward方法有一个input参数,你的输入是交给forward方法,然后forward方法调用这些层对输入数据处理。
        
        # (1)将输入数据进行展平;展开成一个28x28这么长的一个tensor。
        input = input.view(-1,28*28)
        
        #(2)开始前向传播
        x1 = F.relu(self.linear1(input)) # 中间的影藏层单元,需要进行一个relu激活,提升模型的非线性表达能力
        x2 =  F.relu(self.linear2(x1))
        x3 = self.linear3(x2) # 损失函数是CrossEntropyLoss,输出不需要进行激活。
        return x3

 

model = Model() # 创建模型
loss_fn = torch.nn.CrossEntropyLoss()  # 损失函数。交叉熵
opt = torch.optim.Adam(model.parameters(),lr=0.001) # Adam优化器
epochs = 20 #训练批次大小

# 使用模板代码
def fit(epoch, model, trainloader, testloader):
    correct = 0 # 记录模型正确预测对了多少个样本
    total = 0 # 总共对多少个样本进行了预测
    running_loss = 0 # 累加每一个batch的loss
    for x, y in trainloader: # 返回的是每一个batch的数据
        y_pred = model(x) # 前向传播
        loss = loss_fn(y_pred, y)
        opt.zero_grad()
        loss.backward() # 反向传播
        opt.step() # 优化模型参数
        with torch.no_grad():
            y_pred = torch.argmax(y_pred, dim=1) # 将预测结果转换为相应的预测值
            correct += (y_pred == y).sum().item() # 单个tensor转python标量(取值)。每一个batch都将算对的个数加到correct里面。
            total += y.size(0) #  每一个batch的样本个数
            running_loss += loss.item() # 对每一个batch(批次)的loss进行累加
    
    # dataloader有一个对象dataset,反映创建这个dataloader的那个dataset,使用len函数取得它的总的长度。
    epoch_loss = running_loss / len(trainloader.dataset) # 每一个批次的loss/总的样本数==每个样本的平均loss 
    epoch_acc = correct / total # 预测对的样本数/总的预测样本数(对于一个epoch)。每个样本的平均acc
        
        
    test_correct = 0
    test_total = 0
    test_running_loss = 0 
    
    with torch.no_grad():
        for x, y in testloader:
            y_pred = model(x)
            loss = loss_fn(y_pred, y)
            y_pred = torch.argmax(y_pred, dim=1)
            test_correct += (y_pred == y).sum().item()
            test_total += y.size(0)
            test_running_loss += loss.item()
    
    epoch_test_loss = test_running_loss / len(testloader.dataset)
    epoch_test_acc = test_correct / test_total
    
        
    print('epoch:', epoch, 
          '  loss:', round(epoch_loss, 3),
          '  accuracy:', round(epoch_acc, 3),
          '  test_loss:', round(epoch_test_loss, 3),
          '  test_accuracy:', round(epoch_test_acc, 3)
             )
    # 返回一个epoch在训练集和测试数据集上的损失和准确率    
    return epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc

开始训练: 

train_loss = []
train_acc = []
test_loss = []
test_acc = []
for epoch in range(epochs):
    epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch, model,train_dl,test_dl)
    train_loss.append(epoch_loss)
    train_acc.append(epoch_acc)
    test_loss.append(epoch_test_loss)
    test_acc.append(epoch_test_acc)

运行结果: 


训练可视化 

plt.plot(range(1, epochs+1), train_loss, label='train_loss')
plt.plot(range(1, epochs+1), test_loss, label='test_loss')
plt.legend()

 

 


plt.plot(range(1, epochs+1), train_acc, label='train_acc')
plt.plot(range(1, epochs+1), test_acc, label='test_acc')
plt.legend()

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/766882.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号