PyTorch深度学习实践——多分类问题
多分类问题
目录- 多分类问题
- Softmax
- 在Minist数据集上实现多分类问题
- 作业
课程来源:PyTorch深度学习实践——河北工业大学
《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibili
Softmax
这一讲介绍使用softmax分类器实现多分类问题。
上一节课计算的是二分类问题,也就是输出的label可以分类为0,1两类。只要计算出\(P(y=1)\)的概率,那么\(P(y=0)=1-P(y=1)\);所以只需要计算一种类型的概率即可,也就是只要一个参数。
而在使用MINIST对手写数字进行分类的时候一共是有10个分类的(数字0-9)。
处理方式:视为10个二分类问题(一个label和其他9个label),计算每一个label的概率。如下图所示,但是问题在于
- 每一个二分类问题的结果是独立的,不能保证10个结果加起来等于1,且无法解决互相抑制的问题。
- 每一个结果不能保证大于0。
我们希望输出是有竞争关系的,也就是如果有一项很大那么其他项要相对比较小。为了解决上述问题,提出softmax函数,使用结构如下:
Softmax计算公式如下:
\[P(y=i)=\frac{e^{z_i}}{\sum_{j=0}^{K-1}e^{Z_j}},i\in \{0,...,K-1\} \]Softmax函数计算简单示例如下:

接下来考虑多分类问题中的损失函数如何定义:和上述BCE基本一致,同样使用交叉熵作为损失函数,定义式如下:
\[Loss(\hat Y,Y)=-Ylog\hat Y \]上面这种计算方式也就是NLLLoss,这种损失函数的结构如下:
而NLLLoss损失函数加上Softmax就是交叉熵损失,对应PyTorch中的nn.CrossEntropyLoss(),也就是最后一层的非线性变化不需要进行,直接交给上述损失函数即可。如下图所示:
在Minist数据集上实现多分类问题
Minsit 数据介绍:每一个手写图片都可以看做是一个28x28的矩阵,如下图所示:
总体构建模型并训练还是如上四步,在最后一步加上测试过程。
注:1.在视觉处理中,灰度图可以看做单通道图像,而彩色图像事实上就是RGB三通道的矩阵,在PyTorch中要把构造成通道数量的C放在第一维的三维向量。
2.神经网络训练中尽量将图像矩阵转换为0-1分布的数据
模型结构简图:
代码如下:
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
# prepare dataset
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)
# 定义模型
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()
# construct loss and optimizer
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)
# 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()
# 预测结果
outputs = model(inputs)
# 交叉熵
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()
作业
Pytorch详解NLLLoss和CrossEntropyLoss 详见如下网址:https://blog.csdn.net/weixin_43593330/article/details/108622747
Otto Group Product Classification Challenge
import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
import torch.optim as optim
##str转数值类型
def label2id(labels):
id=[]
target_labels=['Class_1', 'Class_2', 'Class_3', 'Class_4', 'Class_5', 'Class_6', 'Class_7', 'Class_8', 'Class_9']
for label in labels:
id.append(target_labels.index(label))
return id
class MyDataset(Dataset):
def __init__(self,filepath):
data=pd.read_csv(filepath)
labels=data['target']
self.x_data=torch.from_numpy(np.array(data)[:,1:-1].astype(np.float32))
self.y_data=label2id(labels)
self.len=data.shape[0]
def __getitem__(self,index):
return self.x_data[index],self.y_data[index]
def __len__(self):
return self.len
class Module(nn.Module):
def __init__(self):
super(Module,self).__init__()
self.linear1=nn.Linear(93,64)
self.linear2 = nn.Linear(64, 32)
self.linear3 = nn.Linear(32, 16)
self.linear4 = nn.Linear(16, 9)
self.activate=nn.ReLU()
def forward(self,x):
x = self.activate(self.linear1(x))
x = self.activate(self.linear2(x))
x = self.activate(self.linear3(x))
x=self.linear4(x)
return x
def train(epoch):
running_loss=0.0
for batch_idx,data in enumerate(train_loader,1):
x,y=data
y_pred=model(x)
loss=critetion(y_pred,y)
running_loss+=loss.item()
optimizer.zero_grad()
loss.backward()
optimizer.step()
loss_list.append(loss.item())
if batch_idx %100 ==0:
print('[%d, %5d] loss = %.3f' % (epoch + 1, batch_idx, running_loss / 100))
running_loss=0.0
if __name__=="__main__":
train_data = MyDataset('train.csv')
train_loader = DataLoader(dataset=train_data, batch_size=64, shuffle=True, num_workers=0)
model=Module()
critetion=nn.CrossEntropyLoss()
optimizer=optim.SGD(model.parameters(),lr=0.01,momentum=0.5)
loss_list=[]
for epoch in range(30):
train(epoch)
plt.plot(range(len(loss_list)), loss_list)
plt.xlabel('step')
plt.ylabel('loss')
plt.show()
def test():
test_data=pd.read_csv('test.csv')
x_test=torch.from_numpy(np.array(test_data)[:,1:].astype(np.float32))
y_pred=model(x_test)
_,pred=torch.max(y_pred,dim=1)
out=pd.get_dummies(pred)#获取one-hot,其实就是0-8
labels=['Class_1', 'Class_2', 'Class_3', 'Class_4', 'Class_5', 'Class_6', 'Class_7', 'Class_8', 'Class_9']
out.columns=labels
out.insert(0,'id',test_data['id'])
result=pd.DataFrame(out)
result.to_csv('otto-group-product_predictions.csv', index=False)
test()
loss可视化:
结果:
