Pytorch学习笔记09——多分类问题

发布时间:2024-09-01 10:01

Pytorch学习笔记09——多分类问题

在上一篇文章的糖尿病数据集当中,输出只有0和1俩种可能值。
P(y=0) = 1-P(y=1)
如何实现多分类问题?
Pytorch学习笔记09——多分类问题_第1张图片
经过最后一步softmax后得到10个预测值,如果我们仍然用二分类的思维去想这个问题:
y1^hat属于第一类的概率是0.8, 不属于第一类的概率是0.2.
y2^hat属于第二类的概率是0.9, 不属于第二类的概率是0.1.
y3^hat属于第一类的概率是0.9, 不属于第一类的概率是0.1.
。。。。
y1^hat属于第一类的概率是0.3, 不属于第一类的概率是0.7.
这样就会产生矛盾了,我们希望输出是带有竞争性的,让他们的合为1,之间互相排斥。一个大了其他就小了。p(y = 0)、p(y = 1)…p(y = 9)整个我们希望他是符合一个概率分布的。
比如p(y=0)=0.8, p(y = 1、2…、8)=0.01,p(y = 10) = 0.12, 如下图所示,这是我们想要的表现。
Pytorch学习笔记09——多分类问题_第2张图片
Softmax就帮助我们做了这样一件事:
对最后一层输出的{y1, y2 …}作np.exp(), 计算总和Sum,再用np.exp(yi)/Sum就可以了。
Pytorch学习笔记09——多分类问题_第3张图片

Pytorch学习笔记09——多分类问题_第4张图片
在上面的例子中,{0.2, 0.1, -0.1}经过softmax转成了{0.38, 0.34, 0.28}:

import numpy as np
import torch
x = torch.tensor([0.2, 0.1, -0.1])
y_softmax = np.exp(x)/np.exp(x).sum()
y_softmax

tensor([0.3780, 0.3420, 0.2800])
那么如何计算损失呢?
我们假设标签是1,就需要对1进行one-hot编码,与y_softmax长度对齐。
Pytorch学习笔记09——多分类问题_第5张图片
NLLLoss做的是红色方框里的事儿。我们需要自己写softmax。

import numpy as np
import torch
y = torch.tensor([1, 0, 0])
x = torch.tensor([0.2, 0.1, -0.1])
y_softmax = np.exp(x)/np.exp(x).sum()
loss = (-y * np.log(y_softmax)).sum()
loss.item()
0.9729189872741699

而crossentropy做的是下面红色方框的事儿。最后一层不需要再做softmax激活了,同样也不需要自己对标签one-hot编码。
Pytorch学习笔记09——多分类问题_第6张图片

import torch
y = torch.LongTensor([0])#注意使用长整型,0就表示one-hot后只有第0个是1
z = torch.Tensor([[0.2, 0.1, -0.1]])
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z, y)
loss.item()
0.9729189276695251

我们来看这样一段代码

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], #0
                        [0.2, 0.3, 0.5], #2
                        [0.2, 0.2, 0.5]])#2
loss1 = criterion(Y_pred1, Y)
loss2 = criterion(Y_pred2, Y)
print(loss1.item())
print(loss2.item())

Y_pred1很明显看起来更符合标签,结果也是如此。虽然[0.1, 0.2, 0.9]这里面并不是一个合为1的概率分布,但0.9也能看出来最大,是属于第二类的。

用全连接神经网络实现MNIST数据集分类

在mnist数据集当中,我们输入的是图像,这个图像上是0-9十个数字,我们需要进行十分类任务。那么如何将图像送到模型中训练呢?一种方式是我们可以把图像映射成一个矩阵,再送到模型中训练。
如下所示,这是一个28 * 28 = 784像素的图片,越深的地方越接近0,越亮的地方越接近1.
Pytorch学习笔记09——多分类问题_第7张图片
Pytorch学习笔记09——多分类问题_第8张图片

transform:pytorch读图像的时候,用的是python的PIL Image,
神经网络希望我们输入的数值比较小,这对训练是最有帮助的。 读入的时候值是0-255量化的,代表了256种亮度。我们要把他转成图像张量,并希望转成一个0-1之间的分布。

我们把这个黑白的叫做单通道的图像。我们看到的彩色图像有三个通道RGB.
正常处理的时候,我们读进来的图像是W * H* C样的,需要转成C * W * H,通道放第一位。这是为了在pytorch进行更高校的图像处理、卷积运算。

0-255压缩到0-1的浮点数。把28 * 28转换成1 * 28 * 28的图像张量.1 * 28 * 28, 1是通道,28分别是是宽和高。

在概率统计当中,我们学过把普通正态分布如何转换到标准正态分布N(0, 1):
在这里插入图片描述
对于mnist数据集,均值mean为0.1307, 方差std为0.3081。
第一步,加载数据集:

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)

把要下载的路径写到root里就可以自动下载了(无法下载记得挂)
Pytorch学习笔记09——多分类问题_第9张图片
我们来看一下train_loader和test_loader的信息

train_dataset

Dataset MNIST
Number of datapoints: 60000
Root location: …/dataset/mnist/
Split: Train
StandardTransform
Transform: Compose(
ToTensor()
Normalize(mean=(0.1307,), std=(0.3081,))
)

可以看到,这个训练集有60000个样本,我们构成的批量数据集是以batch_size=64为单位划分的,同时进行了Shuffle打乱操作。也就是说我们分成了60000/64=937块。训练时按照小批量进行训练。

test_dataset

Dataset MNIST
Number of datapoints: 10000
Root location: …/dataset/mnist/
Split: Test
StandardTransform
Transform: Compose(
ToTensor()
Normalize(mean=(0.1307,), std=(0.3081,))
)

Test测试集一共有10000个测试样本,同样也64个地测试。测试集不需要shuffle打乱,这方便我们以后查看哪里测试有问题。
Pytorch学习笔记09——多分类问题_第10张图片
四个.gz文件已经解压好了。
第二步:设计模型
Pytorch学习笔记09——多分类问题_第11张图片

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.linear1 = torch.nn.Linear(784, 512)
        self.linear2 = torch.nn.Linear(512, 256)
        self.linear3 = torch.nn.Linear(256, 128)
        self.linear4 = torch.nn.Linear(128, 64)
        self.linear5 = torch.nn.Linear(64, 10)
        self.relu = torch.nn.ReLU()
        
    def forward(self, x):
    	x = x.view(-1, 784)
        x = self.relu(self.linear1(x))
        x = self.relu(self.linear2(x))
        x = self.relu(self.linear3(x))
        x = self.relu(self.linear4(x))
        x = self.linear5(x)
        return x
model = Net()

第三步:确定损失和优化器

criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr = 0.01)

第四步:硬train一发

epoch_list = []
loss_list = []
loss_sum = 0
for epoch in range(10):
    for index, data in enumerate(train_loader, 0):
        inputs, labels = data
        optimizer.zero_grad()
        y_pred = model(inputs)
        loss = criterion(y_pred, labels)
        loss.backward()
        optimizer.step()
        
        loss_sum += loss.item()
        batch = index
    print('epoch = ', epoch, 'loss = ', loss_sum/batch)
    epoch_list.append(epoch)
    loss_list.append(loss_sum/batch)
    loss_sum = 0

epoch = 0 loss = 1.8594086992702463
epoch = 1 loss = 0.463400487898349
epoch = 2 loss = 0.29753065994059075
epoch = 3 loss = 0.2263508649521061
epoch = 4 loss = 0.1784982799841618
epoch = 5 loss = 0.145680181410267
epoch = 6 loss = 0.1220758174344293
epoch = 7 loss = 0.10426992276661583
epoch = 8 loss = 0.09011199540051601
epoch = 9 loss = 0.07850728131541952
Pytorch学习笔记09——多分类问题_第12张图片
第五步:测试

total = 0
correct = 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)
        correct += (predicted == labels).sum().item()
print( 'Accuracy on test set: %d %%' % (100 * correct / total))
Accuracy on test set: 97 %

测试的时候,只需要前向传播计算输出即可,不涉及梯度。所以这里用了with torch.no_grad:

得到的输出outputs是一个(N, 10)的矩阵,对于这N个样本,我们只要找到每一行10个数里最大的数字就可以了,就能对应到属于哪一类。

_,predicted = torch.max(outputs.data, dim = 1)就是对output一行一行找最大值得操作。输出最大值及最大值索引。

Python 各种下划线都是啥意思_、xx、xx、__xx、xxclassname

End~~~

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号