【PyTorch基础教程12】图像多分类问题

简介: (1)本次图像多分类中的最后一层网络不需要加激活,因为在最后的Torch.nn.CrossEntropyLoss已经包括了激活函数softmax。这里注意softmax的dim参数问题,如下面这个是(3,2)的一个变量,dim = 0 实际上是对第一维的3个变量进行对数化,而dim = 1是对第二维进行操作。

学习总结

(1)本次图像多分类中的最后一层网络不需要加激活,因为在最后的Torch.nn.CrossEntropyLoss已经包括了激活函数softmax。这里注意softmax的dim参数问题,如下面这个是(3,2)的一个变量,dim = 0 实际上是对第一维的3个变量进行对数化,而dim = 1是对第二维进行操作。

a = torch.Tensor([[1,1],[2,2],[3,3]])
a.size()
Out[89]: torch.Size([3, 2])
b = torch.nn.Softmax(dim=0)(a)
b
Out[91]: 
tensor([[0.0900, 0.0900],
        [0.2447, 0.2447],
        [0.6652, 0.6652]])
b = torch.nn.Softmax(dim=1)(a)
b
Out[93]: 
tensor([[0.5000, 0.5000],
        [0.5000, 0.5000],
        [0.5000, 0.5000]])

(2)本次pytorch在读图像时,将PIL图像(现在都用Pillow了)转为Tensor,神经网络一般希望input比较小,最好在-1到1之间,最好符合正态分布。三种主流图像处理库的比较:

image.png

一、多分类问题

注意验证/测试的流程基本与训练过程大体一致,不同点在于:

需要预先设置torch.no_grad,以及将model调至eval模式

不需要将优化器的梯度置零

不需要将loss反向回传到网络

不需要更新optimizer

二、分布和API

image.png

法一:把每一个类别的确定看作是一个二分类问题。利用交叉熵。

为了解决抑制问题,就不要输出每个类别的概率,且满足每个概率大于0和概率之和为1的条件。(二分类我们输出的是分布,求出一个然后用1减去即可,多分类虽然也可以这样,但是最后1减去其他所有概率的计算,还需要构建计算图有点麻烦)。

之前二分类中的交叉熵的两项中只能有一项为0.

image.png

(1)NLLLoss函数计算如下红色框:

image.png

(2)可以直接使用torch.nn.CrossEntropyLoss(将下列红框计算纳入)。注意右侧是由类别生成独热编码向量。

image.png

交叉熵,最后一层网络不需要激活,因为在最后的Torch.nn.CrossEntropyLoss已经包括了激活函数softmax。

(1)交叉熵手写版本

import numpy as np
y = np.array([1, 0, 0])
z = np.array([0.2, 0.1, -0.1])
y_predict = np.exp(z) / np.exp(z).sum()
loss = (- y * np.log(y_predict)).sum()
print(loss)
# 0.9729189131256584

(2)交叉熵pytorch栗子

image.png交叉熵损失和NLL损失的区别(读文档):

https://pytorch.org/doc s/stable/nn.html#crossentropyloss

https://pytorch.org/docs/stable/nn.html#nllloss

搞懂为啥:CrossEntropyLoss <==> LogSoftmax + NLLLoss

三、交叉熵代码实践

前面是sigmoid,后面是softmax(使得概率大于0,概率值和为1)。 两点注意。

# -*- coding: utf-8 -*-
"""
Created on Mon Oct 18 22:48:55 2021
@author: 86493
"""
# 用CrossEntropyLoss计算交叉熵
import torch 
# 注意1:设定的第0个分类
y = torch.LongTensor([0])
z = torch.Tensor([[0.2, 0.1, -0.1]])
# 注意2:CrossEntropyLoss
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z, y)
print(loss.item())
# 0.9729189276695251
# 举栗子:mini-batch:batch_size = 3
import torch
criterion = torch.nn.CrossEntropyLoss()
# 三个样本
Y = torch.LongTensor([2, 0, 1]) 
# 第一个样本比较吻合,loss会较小
Y_pred1 = torch.Tensor([[0.1, 0.2, 0.9], # 2 该层为原始的线性层的输出
                        [1.1, 0.1, 0.2], # 0
                        [0.2, 2.1, 0.1]])# 1
# 第二个样本差的比较远,loss较大
Y_pred2 = torch.Tensor([[0.8, 0.2, 0.3], # 2 
                        [0.2, 0.3, 0.5], # 0 
                        [0.2, 0.2, 0.5]])# 1
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)

四、代码实践

(1)pytorch在读图像时,将PIL图像(现在都用Pillow了)转为Tensor,神经网络希望input比较小,最好在-1到1之间,最好符合正态分布。

image.png

三种主流图像处理库的比较:

image.png

(2)transforms.Normalize,转为标准正态分布即是一种映射到(0, 1)函数。image.png

(3)激活层改用relu,最后一层不用加,因为交叉熵损失函数里面已经包括了。

(4)_, predicted = torch.max(outputs.data, dim = 1)求出每一行(样本)的最大值的下标,dim = 1即行的维度;返回最大值和最大值所在的下标。image.png

# -*- coding: utf-8 -*-
"""
Created on Mon Oct 18 19:25:46 2021
@author: 86493
"""
import torch
from torchvision import transforms 
from torchvision import datasets
from torch.utils.data import DataLoader 
# 使用relu激活函数
import torch.nn.functional as F
import torch.optim as optim 
import torch.nn as nn
import matplotlib.pyplot as plt
losslst = []
batch_size = 64 
transform = transforms.Compose([
    # 将PIL图片转为Tensor
    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)
# 模型
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.l1 = nn.Linear(784, 512)
        self.l2 = nn.Linear(512, 256)
        self.l3 = nn.Linear(256, 128)
        self.l4 = nn.Linear(128, 64)
        self.l5 = nn.Linear(64, 10)
    def forward(self, x):
        # -1位置会自动算出N,即变成(N, 784)矩阵
        x = x.view(-1, 784)
        x = F.relu(self.l1(x))
        x = F.relu(self.l2(x))
        x = F.relu(self.l3(x))
        x = F.relu(self.l4(x))
        # 注意最后一层不用加上relu,因为交叉熵已经含有softmax
        return self.l5(x)
model = Net()
# 交叉熵作为loss
criterion = torch.nn.CrossEntropyLoss()
# 优化器SGD加上冲量以优化训练过程
optimizer = optim.SGD(model.parameters(),
                      lr = 0.01,
                      momentum = 0.5)
def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        # 1.准备数据
        inputs, labels = data  # data为元组
        # 2.向前传递
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        losslst.append(loss)
        # print(losslst,"+++++++++++++")
        # 3.反向传播
        optimizer.zero_grad()
        loss.backward()
        # 4.更新参数
        optimizer.step()
        # 记得取loss值用item(),否则会构建计算图  
        running_loss += loss.item()
        losslst.append(loss.item())
        # 每300个batch打印一次
        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这句后面就不会产生计算图
    with torch.no_grad():
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            # 求出每一行(样本)的最大值的下标,dim = 1即行的维度
            # 返回最大值和最大值所在的下标
            _, predicted = torch.max(outputs.data,
                                     dim = 1)
            # label矩阵为N × 1
            total += labels.size(0)
            # 猜对的数量,后面算准确率
            correct += (predicted == labels).sum().item()
    print('Accuracy on test set: %d %%' % 
          (100 * correct / total))
# print("losslst的长度为:", len(losslst))
if __name__ == '__main__':
    for epoch in range(10):
        # if epoch % 10 == 9: # 每10个输出一次
        train(epoch)
        test()
[1,   300] loss: 2.216
[1,   600] loss: 0.872
[1,   900] loss: 0.423
Accuracy on test set: 89 %
[2,   300] loss: 0.333
[2,   600] loss: 0.272
[2,   900] loss: 0.232
Accuracy on test set: 93 %
[3,   300] loss: 0.189
[3,   600] loss: 0.176
[3,   900] loss: 0.160
Accuracy on test set: 95 %
[4,   300] loss: 0.135
[4,   600] loss: 0.127
[4,   900] loss: 0.121
Accuracy on test set: 95 %
[5,   300] loss: 0.104
[5,   600] loss: 0.096
[5,   900] loss: 0.097
Accuracy on test set: 96 %
[6,   300] loss: 0.080
[6,   600] loss: 0.071
[6,   900] loss: 0.083
Accuracy on test set: 97 %
[7,   300] loss: 0.062
[7,   600] loss: 0.062
[7,   900] loss: 0.062
Accuracy on test set: 97 %
[8,   300] loss: 0.050
[8,   600] loss: 0.052
[8,   900] loss: 0.053
Accuracy on test set: 97 %
[9,   300] loss: 0.034
[9,   600] loss: 0.045
[9,   900] loss: 0.043
Accuracy on test set: 97 %
[10,   300] loss: 0.032
[10,   600] loss: 0.032
[10,   900] loss: 0.036
Accuracy on test set: 97 %
相关文章
|
2月前
|
机器学习/深度学习 算法 PyTorch
用PyTorch轻松实现二分类:逻辑回归入门
用PyTorch轻松实现二分类:逻辑回归入门
用PyTorch轻松实现二分类:逻辑回归入门
|
2月前
|
机器学习/深度学习 数据采集 PyTorch
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
|
2月前
|
机器学习/深度学习 PyTorch 算法框架/工具
Pytorch使用VGG16模型进行预测猫狗二分类
深度学习已经在计算机视觉领域取得了巨大的成功,特别是在图像分类任务中。VGG16是深度学习中经典的卷积神经网络(Convolutional Neural Network,CNN)之一,由牛津大学的Karen Simonyan和Andrew Zisserman在2014年提出。VGG16网络以其深度和简洁性而闻名,是图像分类中的重要里程碑。
215 0
|
2月前
|
数据可视化 PyTorch 算法框架/工具
使用PyTorch搭建VGG模型进行图像风格迁移实战(附源码和数据集)
使用PyTorch搭建VGG模型进行图像风格迁移实战(附源码和数据集)
325 1
|
11月前
|
数据采集 PyTorch 数据处理
Pytorch学习笔记(3):图像的预处理(transforms)
Pytorch学习笔记(3):图像的预处理(transforms)
802 1
Pytorch学习笔记(3):图像的预处理(transforms)
|
9月前
|
机器学习/深度学习 自然语言处理 PyTorch
PyTorch应用实战六:利用LSTM实现文本情感分类
PyTorch应用实战六:利用LSTM实现文本情感分类
198 0
|
19天前
|
机器学习/深度学习 自然语言处理 算法
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
【从零开始学习深度学习】49.Pytorch_NLP项目实战:文本情感分类---使用循环神经网络RNN
|
10天前
|
机器学习/深度学习 人工智能 PyTorch
PyTorch 图像篇
计算机视觉是多学科交叉的科技,属人工智能关键分支,应用于智能安防、自动驾驶、医疗和制造。技术包括物体检测、语义分割、运动跟踪等。早期依赖手工特征,但深度学习尤其是卷积神经网络(CNN)的发展改变了这一状况,CNN通过自动学习特征,改善了图像分类效率。CNN包含卷积层、池化层和全连接层,解决传统方法参数多、易丢失空间信息的问题。卷积操作在图像处理中用于特征提取,通过二维互相关运算学习图像特征。
|
2月前
|
机器学习/深度学习 JSON PyTorch
图神经网络入门示例:使用PyTorch Geometric 进行节点分类
本文介绍了如何使用PyTorch处理同构图数据进行节点分类。首先,数据集来自Facebook Large Page-Page Network,包含22,470个页面,分为四类,具有不同大小的特征向量。为训练神经网络,需创建PyTorch Data对象,涉及读取CSV和JSON文件,处理不一致的特征向量大小并进行归一化。接着,加载边数据以构建图。通过`Data`对象创建同构图,之后数据被分为70%训练集和30%测试集。训练了两种模型:MLP和GCN。GCN在测试集上实现了80%的准确率,优于MLP的46%,展示了利用图信息的优势。
37 1
|
19天前
|
机器学习/深度学习 算法 PyTorch
【从零开始学习深度学习】50.Pytorch_NLP项目实战:卷积神经网络textCNN在文本情感分类的运用
【从零开始学习深度学习】50.Pytorch_NLP项目实战:卷积神经网络textCNN在文本情感分类的运用