之前提到的分类任务都是二分类,也就是是或否。本节提到的是多分类任务。
此节会运用到之前提到的MNIST,也是就数字分类任务,此时就是多分类(10)了。
一:多分类思想
对于一个多分类任务,我们如何去设计。
那现在需要解决的问题就是softmax是如何解决所有概率大于等于0,且和为1的这样一个任务。
softmax的思想如下:
对于上面的思想,用于下面的简单实例:
其实到这里我们就可以拿到一共我们想要的y_hat的值了,但是想要进行训练,还需要得到损失值。
二:多分类损失值的思想
在得到y_hat后需要对其进行梯度计算才能得到相应的loss损失值。
关于二分类计算loss的方法Logistic回归(Logistic Regression)-CSDN博客
还有一个关键需要学习的,关于one-hot,大家也可以找视频观看,比较容易理解。机器学习:数据预处理之独热编码(One-Hot)详解-CSDN博客
关于实现多分类的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() #loss的计算过程
print(loss)
交叉熵损失(softmax+log+loss计算),在交叉熵损失计算之前不需要进行非线性变换。
对于交叉熵损失相关的代码:
import torch
y = torch.LongTensor([0])
z = torch.Tensor([[0.2,0.1,-0.1]])
criterion = torch.nn.CrossEntropyLoss()
loss = criterion(z,y)
print(loss)
三:MNIST实战
对于下面这个手写的数字,图片是28x28的矩阵,数值比较大的颜色比较深(对应右图)。
写MNIST多分类的步骤:
①准备数据集Prepare dataset(Dataset and Dataloader)
②设计相应的模型Design model using Class
③构造损失函数和优化器Construct loss and optimizer
④Training cycle +test
(1)数据集的准备
此处的train_dataset,train_loader和test_dataset,test_loader和之前
Logistic回归(Logistic Regression)-CSDN博客文章内容相同,并且后面关于MNIST文件可以根据这篇文章下载。
transform的作用如下。image中28x28的像素,每个像素都是0-255的,但是对于神经网络来说,输入的值最好是比较小的,因此就需要将原来的图变成一个张量,相关的变化见下图(相关变化在代码中是 ToTensor())
在转化完张量后,Normalize归一化, Normalize(均值mean,标准差std)
(2)设计模型
模型整体的流程如下(注意最后一层不进行激活):
与上面流程符合的代码如下(最后一层不激活,直接return):
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()
(3) 损失函数和优化器
损失使用交叉熵损失,优化器使用SGD
代码:
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.5)
(4)训练过程
def train(epoch):
running_loss = 0.0
for batch_idx,data in enumerate(train_loader,0):
input,target = data
optimizer.zero_grad() #优化器清零
#forword+backward+updata
outputs = model(input)#输出
loss = criterion(outputs,target)#损失
loss.backward()#反馈
optimizer.step()#优化
running_loss +=loss.item()
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.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 按照第一个维度,行进行比较最大值
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()