Pytorch深度学习实践学习笔记(九)多分类问题(数字识别)

目录

一、使用Sigmoid实现多分类

二、Softmax Layer使得输出满足分布的条件

三、Pytorch里的交叉熵损失Torch.nn.CrossEntropyLoss()

四、图像分类(简单)


SoftMAX分类器

一、使用Sigmoid实现多分类

        计算P(y=1)、P(y=2)...的概率可以变成多个二分类问题:属于x或者不属于x;

        缺点:之间的概率会互相抑制,当P(y=1)<P(y=2)时,不管P(y=1)多大,都会被忽略掉。

因此,多分类问题中,要求最终的概率满足某些分布:①各概率均不小于零;②概率之和为1;

输出应当是一个分布(distribution).

二、Softmax Layer使得输出满足分布的条件

Softmax Layer 对之前神经网络的输出做一个处理

P(y=i)=\frac{e^{z_i}}{\sum_{j=0}^{K-1} e^{z_j}}, i \in\{0, \ldots, K-1\}

分子令所有值的大小转变为正数,分母使得概率归一化。

损失函数如何做?

损失函数不应当为0,否则没有意义。

二分类的交叉熵/损失函数:

\text { Loss }=-(y \cdot \log (\hat{y})+(1-y) \cdot \log (1-\hat{y}))

多分类的损失函数/交叉熵定义为:

\text { Loss }=-y \cdot \log (\hat{y})

没有其他项,是因为其他项的y都严格等于0;

NLLLoss(Negative Log Likehood Loss):外输入标签,内输入为计算出的概率求对数之后的结果,这个函数计算相应的损失。

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)

三、Pytorch里的交叉熵损失Torch.nn.CrossEntropyLoss()

Pytorch内提供的交叉熵损失函数,将上述过程合并,不需要对神经网络做额外的激活。

import torch
y = torch.LongTensor([0])                #y需要是一个长整型的张量
z = torch.Tensor([[0.2, 0.1, -0.1]])     #设定为第0个分类
criterion = torch.nn.CrossEntropyLoss()  #交叉熵损失函数
loss = criterion(z, y)
print(loss)

一个代码示例:

import torch
criterion = torch.nn.CrossEntropyLoss()
Y = torch.LongTensor([2, 0, 1])               #第一个分类是2,第二个是0,第三个是1
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概率最大
Y_pred2 = torch.Tensor([[0.8, 0.2, 0.3],      #预测2的差距与实际相差很大,因此损失也应当更大
                        [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)

四、图像分类(简单)

图像可以转化为相应像素的矩阵,不同的颜色表示从0-1不同的大小(若图像只有黑白的话)。

  1. Prepare dataset //Dataset and Dataloader
  2. Design model using Class //inherit from nn.Module
  3. Construct loss and optimizer //using PyTorch API
  4. Training cycle +Test //forward, backward, update

1.数据处理

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F           #将激活函数改为relu函数,以替代sigmoid
import torch.optim as optim               #优化器的包
batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),
#图像数据转变为张量
    transforms.Normalize((0.1307, ), (0.3081, ))    
#数据标准化,第一个数字是均值,第二个是标准差,Mini这个数据集是这样的参数
])
#Python读入图像的时候使用的是PIL(Pillow),期望将图像的像素n*n个[0,255]的数据转变为正态分布
#在[0,1]之间的数据结构(一个张量)

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)

在图像处理领域,灰度图并非是一个简单的矩阵,灰度图是单通道;彩色图像是通道(Channel),由多层构成;数据一般是由w*H*C的数据构成,分别表示图像的宽度、高度、通道数构成,我们在Pytorch处理的过程中应当将其映射为C*w*H大小的张量数据,以提高处理的效率。

网络结构:

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)
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()

 损失函数

criterion = torch.nn.CrossEntropyLoss()        #交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
#梯度下降法,学习率0.01,更换了momentum优化算法,带冲量的

训练过程:

def train(epoch):
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        #enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时
        #列出数据和数据下标,一般用在 for 循环当中。参数0是指从0开始;
        
        inputs, target = data
        optimizer.zero_grad()    #优化器清零
        
        # forward + backward + update
        outputs = model(inputs)
        loss = criterion(outputs, target)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()    #计算累计的loss
        if batch_idx % 300 == 299:     #每300轮输出一次
            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) #拿到最大值的下标,只需要下标;
            total += labels.size(0)          #total是计算样本的总数
            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()

 在图像处理的时候,使用全连接的神经网络,会导致权重数量少,只关注于原始特征,忽略了局部特征,正确率无法达到很高的水平。

人工特征提取:傅里叶变换/小波进行特征提取

自动特征提取:CNN等

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值