深度学习09——多分类问题

Source

目录

1. 手写数字识别的多分类问题 

1.1  Softmax 

1.2 交叉熵损失 

1.2.1 numpy计算交叉熵 

1.2.2 PyTorch计算交叉熵

1.2.3 Mini-Batch 交叉熵计算 

 2. 手写数字识别实战

2.1 导入库 

 2.1.1 torchvision库

2.1.2  torch.utils.data

2.1.3 torch.nn与torch.nn.functional的区别

2.1.4  torch.optim

 2.2 准备数据集

2.2.1 transforms.Compose()函数 

2.3 构建网络模型 

2.4 计算损失,选择优化器

2.5 训练 

3.完整代码



课代表的文章:PyTorch 深度学习实践 第9讲_错错莫的博客-CSDN博客

全连接网络 :

1. 手写数字识别的多分类问题 

 

 1.1  Softmax 

 

 

1.2 交叉熵损失 

1.2.1 numpy计算交叉熵 

import numpy as np
y = np.array([1,0,0])
z = np.array([0.2,0.1,-0.1])

y_pred = np.exp(z) / np.exp(z).sum() #softmax原理
loss = (-y * np.log(y_pred)).sum()
print(loss)

 1.2.2 PyTorch计算交叉熵(其中有存疑)

勘误代码:

import torch

y = torch.LongTensor([0]) #将y做成长整型张量  # target: [1]
z = torch.Tensor([0.2,0.1,-0.1])              #上下两行数据的维度不等,所以会报错
criterion = torch.nn.CrossEntropyLoss()    # input: [3] 
loss = criterion(z,y)
print(loss)

 修正:

import torch

#y = torch.LongTensor([0]) #输出:tensor(0.9729)    #将y做成长整型张量  # target维度:[1]
y = torch.LongTensor([1])  # 输出: tensor(1.0729)
z = torch.Tensor([[0.2,0.1,-0.1]])              #上下两行数据的维度不等,所以会报错
criterion = torch.nn.CrossEntropyLoss()    # input维度:[3]
loss = criterion(z,y)
print(loss)

  

存疑的理解:

 以上理解可能有误,看见的大佬可以指点一下:如下一个奇怪的规律:

1.2.3 Mini-Batch 交叉熵计算 

import torch

criterion = torch.nn.CrossEntropyLoss()
Y = torch.LongTensor([2,0,1])

Y_pred1 = torch.Tensor(
    [[0.1,0.2,0.9],[1.1,0.1,0.2],[0.2,2.1,0.1]]
)

Y_pred2 = torch.Tensor(
    [[0.8,0.2,0.3],[0.2,0.3,0.5],[0.2,0.2,0.5]]
)
l1 = criterion(Y_pred1,Y)
l2 = criterion(Y_pred2,Y)
print('Batch Loss1 =',l1.data,"\nBatch Loss2 =",l2.data)

 输出:

Batch Loss1 = tensor(0.4966) 
Batch Loss2 = tensor(1.2389)

 2. 手写数字识别实战

 

 

 

2.1 导入库 

 

import torch
from torchvision import transforms,datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

 2.1.1 torchvision库

Pytorch torchvision库使用详情 - 知乎 (zhihu.com)

tochvision主要处理图像数据,包含一些常用的数据集、模型、转换函数等。torchvision主要包含以下四部分:

(1)torchvision.models: 提供深度学习中各种经典的网络结构、预训练好的模型,如:Alex-Net、VGG、ResNet、Inception等。

(2)torchvision.datasets:提供常用的数据集,设计上继承 torch.utils.data.Dataset,主要包括:MNIST、CIFAR10/100、ImageNet、COCO等。torchvision.datasets是从torch.utils.data.Dataset的子类,可以使用torch.utils.data.DataLoader进行多线程处理。

示例:加载MNIST:

from torchvision import datasets
dataset = datasets.MNIST('data/', download=True, train=False, transform=None)

 

(3)torchvision.transforms:提供常用的数据预处理操作,主要包括对Tensor及PIL Image对象的操作。

(4)torchvision.utils:工具类,如保存张量作为图像到磁盘,给一个小批量创建一个图像网格。

2.1.2  torch.utils.data

这个package包含数据读取预处理的一些类,其中两个最常用的类:class torch.utils.data.Dataset 和 class torch.utils.data.DataLoader。

(1)生成数据集:class torch.utils.data.Dataset

(2)加载数据集: torch.utils.data.DataLoader

torch.utils.data_爱钻研的小铭的博客-CSDN博客_torch.utils.data

torch.utils.data - PyTorch中文文档 (pytorch-cn.readthedocs.io)

 

2.1.3 torch.nn与torch.nn.functional的区别

参考文献:

【pytorch】torch.nn 与 torch.nn.functional 的区别_One__Way的博客-CSDN博客_torch.nn.functional torch.nn库和torch.nn.functional库_jk英菲尼迪的博客-CSDN博客_torch.nn.functional

类型:
(1) torch.nn中包含的是封装好的类,继承自nn.Module,调用时先实例化,然后在__init__()中初始化,再在forward()中进行操作。
(2) torch.nn.functional中包含的是实现好的函数,直接通过接口调用。

2.1.4  torch.optim

torch.optim - PyTorch中文文档 (pytorch-cn.readthedocs.io)

PyTorch学习之 torch.optim 的6种优化器及优化算法介绍_Line_Walker的博客-CSDN博客_lr_decay

PyTorch中的optimizer几种优化方法:
其中的6种方法分为2大类:一大类方法是SGD及其改进(加Momentum);另外一大类是Per-parameter adaptive learning rate methods(逐参数适应学习率方法),包括AdaGrad、RMSProp、Adam等。
 

 2.2 准备数据集

2.2.1 transforms.Compose()函数 

transforms.Compose()函数_马鹏森的博客-CSDN博客_transforms.compose

torchvision.transforms是pytorch中的图像预处理包。一般用Compose把多个步骤整合到一起:

transforms.Compose([
 
    transforms.CenterCrop(10),
 
    transforms.ToTensor(),
 
])

这样就把两个步骤整合到了一起。

介绍transforms中的函数:

 

2.3 构建网络模型 

 

 2.4 计算损失,选择优化器

2.5 训练 

 

 

 

 

 

3.完整代码

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch.optim as optim

# step1:准备数据集

batch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])  # 归一化,均值和方差
#准备并加载训练集
train_dataset = datasets.MNIST(root='../dataset/mnist/', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)
#准备并加载测试集
test_dataset = datasets.MNIST(root='../dataset/mnist/', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)


# step2:构建网络模型:继承torch.nn.Module类
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.l1 = torch.nn.Linear(784, 512)
        self.l2 = torch.nn.Linear(512, 256)
        self.l3 = torch.nn.Linear(256, 128)
        self.l4 = torch.nn.Linear(128, 64)
        self.l5 = torch.nn.Linear(64, 10)

    def forward(self, x):
        x = x.view(-1, 784)  # -1其实就是自动获取mini_batch
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        x = F.relu(self.l4(x))
        return self.l5(x)  # 最后一层不做激活,不进行非线性变换


model = Net()

# step3:construct loss and optimizer
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)


# step4:training cycle forward, backward, update
def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        # 获得一个批次的数据和标签
        inputs, target = data
        optimizer.zero_grad()
        # 获得模型预测结果(64, 10)
        outputs = model(inputs)
        # 交叉熵代价函数outputs(64,10),target(64)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if batch_idx % 300 == 299:
            print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
            running_loss = 0.0

def test():
    correct = 0
    total = 0
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)  # dim = 1 列是第0个维度,行是第1个维度
            total += labels.size(0)
            correct += (predicted == labels).sum().item()  # 张量之间的比较运算
    print('accuracy on test set: %d %% ' % (100 * correct / total))


if __name__ == '__main__':
    for epoch in range(10):
        train(epoch)
        test()