深度学习——多分类问题(SOFTMAX MNIST)-学习笔记
深度学习——多分类问题在深度学习里有个经典的数据集MNIST-dataset,它是一个手写的数字照片集合,也是一个经典的做多分类的一个集合。这个集合是由0~9 10个数组成的集合,我们需求是分析输入的数字对应真实数字的概率是多少,说明需要十个标签,十个分类。多分类问题逻辑图把原来只有一个输出,加到10个每个输出对应一个数字,这样可以得到每个数字对应的概率值,这里每个输出做的都是sigmoid二分类
深度学习——多分类问题
在深度学习里有个经典的数据集MNIST-dataset ,它是一个手写的数字照片集合,也是一个经典的多分类的问题
这个集合是由0~9 10个数组成的集合,我们需求是分析输入的数字对应真实数字的概率是多少,说明需要十个标签,十个分类。
多分类问题
逻辑图
把原来只有一个输出,加到10个 每个输出对应一个数字,这样可以得到每个数字对应的概率值,这里每个输出做的都是sigmoid二分类(即是非1即0),所以只要有一项输出为1时,其他非1的输出都规定为0,以此来判断。
但是这种情况下出现一个问题,每个sigmoid的输出都是独立的,当一个类别的输出概率较高时,其他类别的概率仍然会高,也就是说在输出了1的概率后,2输出的概率不会因为1的出现而受影响,这点说明了所有输出的概率值之和大于1。
所以我们希望输出的概括要满足分布性质的要求:
1、每个分类出现的概率都大于0
2、所有分类出现的概率的和为1
多分类问题的每个输出需要有竞争性
增加SOFTmax Layer
为了解决以上两个问题需要对神经网络进行改进,在神经网络最终输出层加入Softmax Layer能很好的解决这两个问题
SOFTmax
定义:
Applies the Softmax function to an n-dimensional input Tensor rescaling them so that the elements of the n-dimensional output Tensor lie in the range [0,1] and sum to 1.
将Softmax函数应用于n维输入张量,重新缩放它们,使n维输出张量的元素位于[0,1]范围内,总和为1。
从定义看出Softmax输出的范围在[0,1]之内,然后总和为1,这两点能很好的解决我们的问题
函数:
SOFTmax函数运作流程步骤分析:
- 接收到Linear layer 的每个输出结果进行以e为底的指数幂运算,这样能确保所有的输出为正数
- 把所有的输出进行exp运算后全部加和,然后除以每个输出的exp运算的结果,这样就能保证全部输出和为1,满足每个输出之间有竞争性
损失函数怎么做?
Cross Entropy Loss Function(交叉熵损失函数)
1、二分类的损失函数:
其中:
—— 表示样本 i的label,正类为1,负类为0
—— 表示样本 i预测为正类的概率
在二分的情况下,模型最后需要预测的结果只有两种情况,对于每个类别我们的预测得到的概率为 或者 1-
2、多分类的情况就是在二分类的基础上扩展:
就是在二分类的基础上加一个求和
M——类别的数量
——符号函数(0或1),如果样本i的真实类别等于c取1,否 则取0
——观测样本i属于类别c的预测概率
由于上述计算过程中非0即1,且有且只能有一个1,因此一个样本所有分类的loss计算过程可以简化为:
代码实现:
import numpy as np
y = np.array([1,0,0])
z = np.array([0.99,0.1,-0.1])
y_pead = np.exp(z) / np.exp(z).sum()
loss = (-y*np.log(y_pead)).sum()
print(loss)
在pytorch中后面这段被称为NLLLoss函数
pytorch把Softmax和NLLLoss封装在Cross Entropy Loss 函数中,
代码改变如下:
import torch
y = torch.LongTensor([0])#这里的y需要长整型的张量
z = torch.Tensor([[0.99,0.1,-0.1]])
criterion = torch.nn.CrossEntropyLoss()
loss1 = criterion(z,y)
print(loss1)
这里代码上整体进行封装所以,输入的数据不需要激活只用做线性的处理
MNIST数据集
用多分类的模型训练MNIST数据集
MNIST数据集是由很多个28*28=784个像素的图片组成的,这些是灰阶图像所以是一层三维的数据,
原始图像
输入的图像计算机看不懂,把图片用torchvision的工具的映射转化成一维Tensor数据
对图像做映射(可视化)
代码实现:
引入包:
import torch
'''为准备数据集导入的包'''
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
'''做rule'''
import torch.nn.functional as f
'''做回归'''
import torch.optim as optim
数据准备预处理:
'''1、数据准备及处理'''
batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize(0.1307, 0.3081, )]) # 把图片处理成张量,
# 用Normalize是希望数据满足平均分布(0,1)之间,第一个为均值,第二个为标准差,这两个值是MNIST这个数据均值和标准差,这都是前辈们算好的。
train_datast = datasets.MNIST(root='./', train=True,
download=True, transform=transform) # 加载数据,实例化数据集
train_loader = DataLoader(train_datast,
shuffle=True, batch_size=batch_size)
test_datast = datasets.MNIST(root='./', train=False,
download=True, transform=transform)#训练集
test_loader = DataLoader(test_datast,
shuffle=False, batch_size=batch_size)
制作模型:
模型的激活层选择了Relu
'''2、制作模型'''
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) #最后一层没有非线性激活,因为CrossEntropyLoss里包装了SOFTmax数,
# 所以CrossEntropyLoss希望得到的是线性数据
model = Net()
损失函数和优化器
'''3、制作损失函数和优化器'''
criterion = torch.nn.CrossEntropyLoss() # 交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5) # momentum冲量目的是能冲过鞍点和局部最优,优化更好
训练与测试:
训练:
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()
# 累计loss ,这里要用item()取数据要不回构建计算图
if batch_idx % 300 == 299:
# 每300次输出一次loss
print('[%d,%5d] loss:%.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0.0
测试:
1、不需要进行反向传播,不需要计算梯度
2、只需要计算分类正确率
这行代码会让下面的循环不计算梯度
with torch.no.grad()
def test():
'''测试'''
correct = 0
total = 0
with torch.no_grad(): # 不计算梯度,只需要预测值
for data in test_loader:
images, labels = data
outputs = model(images)
_, pred = torch.max(outputs.data, dim=1)
# 取每一行(dim=1)最大值(max)的下标(_,)及最大值(pred)
total += labels.size(0) # 求预测的总数,label的形状为[N,1]
correct += (pred == labels).sum().item() # pred(预测y) == labels(真值y)相等得1,然后求相等的个数
print('Accuracy on test set: %d %%' % (100 * correct / total))
预测后会得到一个结果的矩阵,我们需要用torch.max函数找最大值还有最大值的下标,拿推测的结果和原始的数据进行张量之间的比较运算 (相等为真(1),不等为假(0)),再行求和算概率,得到我想要的概率值。
运行:
if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()
运行结果:
训练10次准确率达到97%
更多推荐
所有评论(0)