🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:pytorch深度学习
🎀CSDN主页 发狂的小花
🌄人生秘诀:学习的本质就是极致重复!
《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibili
目录
1 one-hot编码
2 Softmax 用于多分类
3 交叉熵
4 Minist手写数字识别
1 one-hot编码
one-hot 编码用于将离散的分类标签转换为二进制向量,关键是离散的分类和二进制向量。
- 离散的分类:
就是分类之间相互独立,不存在大小、前后关系等
- 二进制向量:
向量里面的数字只有0和1,分类问题中,我们需要对类别进行标签。最容易想到的是0:猫,1:狗,2:人,这种方式。
由于对于分类标签我们的要求是不同分类标签之间的距离应该是相等的,如果使用0 1 2 这样的数字,不同标签之间的距离不同,即互相独立的标签是不对等的,计算loss时就会不准确。因此提出了one-hot编码,也叫独热编码。使用二进制向量来表示这种离散的分类标签。
- one-hot编码表示:
对于猫、狗、人 三分类问题,对于分类标签是猫的位置就是1,是狗的位置就是1,是人的位置就是1,这样对于猫 one-hot编码为[ 1,0,0] ,狗 [0,1,0],人[0,0,1],这三个向量的距离是相等的,且互相垂直,这样就满足了独立标签的对等性问题。
- one-hot的使用:
softmax激活函数输出一系列的概率值,表示每一种分类的概率是多少。
分类 | Softmax得分 |
猫 | 0.7 |
狗 | 0.2 |
人 | 0.1 |
上述分类对应的真实的独热编码是[1,0,0],需要计算loss
为了让最终loss值最小,会根据真实标签和预测得分值来调整权重,使得预测得分朝着理想的真实标签靠近。
上图中,猫的得分是0.7,而真实得分是1,因此这一类的得分还需要继续增大,计算完loss值后,反向传播调整神经网络的权重,使这一类的得分继续增大。
狗和人的得分相反,得分需要继续减小,计算完loss值后,反向传播调整权重,使这一类的得分继续减少。
如果预测得分为[1, 0, 0],那么就和真实标签完全相同,此时的loss值就为0, 就说明本轮训练拟合的很好了。
当然 one-hot 编码有它的局限性,上面的例子是 3 分类的例子,那如果分类数量有 1 万个,我们是不是需要将 1 万个离散的分类,编码成 1 万维的向量来计算呢?
这就出现了维度灾难了,而且大量的数据为 0,向量编码变为了非常稀疏的向量,此时就可能需要使用其他的优化手段来处理,这里一般会使用embeding 嵌入层来解决,转化为稠密向量。
总之,one-hot编码通过将分类转换到多维空间中的二进制向量表示,可以有效的解决一些类别不对称不独立的问题。
2 Softmax 用于多分类
假设要使用神经网络做图片分类。现在有3个类别:猫,狗,人。给你下面一张图片,神经网络需要在这3个类别中选出一个。
我们很容易知道这是一只猫,是因为我们的大脑已经建立了猫的模型,但是神经网络需要去计算
好,我们使用Resnet50这一分类网络进行推理运算。算到最后面的全连接层时,全连接输出了3个数值,分别为2,1,0.1。我们知道全连接输出的结果大致代表得分。
现在我们假设猫、狗、人这三个分类的得分分别为:
分类 | 得分 |
猫 | 2 |
狗 | 1 |
人 | 0.1 |
猫得了2分,狗得了1分,人得了0.1分。
单看这个结果,我们大概知道,因为猫的得分最高,那最终神经网络会认为这张图片是一只猫。
这么理解是可以的,但是大概两个地方有点问题。
第一,神经网络最终选择某一分类,依据的不是得分,而是概率。
也就是说,最终神经网络会选择一个概率最高的分类作为它识别的结果。
为什么要把得分转为概率呢?因为多分类模型中,输出值为概率更利于反向推导和模型的迭代,概率之间更好的计算距离,而数值之间的计算的距离是无含义的。
所以,我们需要一种方法,将上面的得分转换为概率。
第二,得分相近如何准确判断的问题。
例子中猫的得分是2,狗的得分是1,人的得分是0.1,我们可以比较肯定的说,因为猫的得分最高,而且比狗和人都高很多,肯定就是猫。
但实际中,有很大的可能算出的猫的得分是2.1,狗的得分是1.9,人的得分是0.1。
这个时候,我们可能就没有像刚才那么肯定了。
因为猫的得分和狗的得分相差很少,而且两者都很高!
这也是为什么,很多神经网络最终都会以TOP1 和 TOP5的识别准确度来衡量神经网络的识别精度。
由于上述两个原因的存在,人们想到了SoftMax算法,而这个算法,也几乎完美地解决了这两个问题。
- 为什么叫SoftMax以及它的实现原理
不知你有没有想过,为什么这个算法叫 SoftMax 呢?
Soft 是软的意思,与之对应肯定有 HardMax。而 HardMax,可以理解为我们平时认知的Max。比如两个数(3, 4), 那么这两个数的 HardMax(3,4) 结果就是4。
这个逻辑,小学生学会了10以内的加减法都知道。
但正如上面所说,SoftMax 不一样,它是要处理多个类别分类的问题。
并且,需要把每个分类的得分值换算成概率,同时解决两个分类得分值接近的问题。
先从公式上看,SoftMmax是怎么做到的。
公式中,每个 z 就对应了多个分类的得分值。SoftMax对得分值进行了如下处理:
- 以e为底数进行了指数运算,算出每个分类的 eZi,作为公式的分子
- 分母为各分类得分指数运算的加和。
- 根据公式很自然可以想到,各个分类的SoftMax值加在一起是1,也就是100%。所以,每个分类的SoftMax的值,就是将得分转化为了概率,所有分类的概率加在一起是100%。
这个公式很自然的就解决了从得分映射到概率的问题。
那它又是怎么解决两个得分相近的问题的呢?
其实也很简单,重点在选择的指数操作上。我们知道指数的曲线是下面的样子。
指数增长的特性就是,横轴变化很小的量,纵轴就会有很大的变化。
所以,从1.9变化到2.1,经过指数的运算,两者的差距立马被的拉大了。从而,我们可以更加明确的知道,图片的分类应该属于最大的那个。
下面是将猫、狗、人三个分类经过SoftMax计算之后得到的概率。
分类 | 得分 | softmax 得分 |
猫 | 2 | 70% |
狗 | 1 | 20% |
人 | 0.1 | 10% |
可以看到,分类是猫的概率遥遥领先。
所以,神经网络在经过softmax层之后,会以70%的概率,认为这张图片是一张猫。
这就是 SoftMax 的底层原理。
指数让得分大的分类最终的概率更大,得分小的分类最终的概率更小,而得分为负数的分类,几乎可以忽略。
多分类问题利用Softmax实现,SoftMax 可以用来做分类,输出属于某个类别的概率
3 交叉熵
计算两个概率之间的差异性
- Softmax:(LogSoftmax)
将score转化为概率
- Cross Entropy:(NLLLoss)
计算两个概率之间的差异
- CrossEntropyLoss:(SoftMax+CrossEntropy)
一些代码说明:
torch.max的返回值有两个,第一个是每一行的最大值是多少,第二个是每一行最大值的下标(索引)是多少。
Python中with的用法_python中with用法-CSDN博客
torch.max()使用讲解_torch.max accuracy 准确率评估-CSDN博客
- 归一化:
将像素转化到0~1之间,方便使用交叉熵损失函数计算,归一化使用正太分布,menan是均值,std是标准差
4 Minist手写数字识别
(1)数据集准备
(2)模型的建立
(3)交叉熵损失函数和优化器
(4)训练和测试
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
# PIL 图像需要转换为Tensor
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)
# design model using class
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) # 表示输入的图像变为1行784列的向量,通俗的说就是将一张28 ✖ 28的图像的所有像素值拼起来,-1表示自动计算N的值(N表示样本数量)
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()
# 获得模型预测结果(64, 10)
outputs = model(inputs)
# 交叉熵代价函数outputs(64,10),target(64)
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()
🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏⭐→关注🔍,如果能评论下就太惊喜了!
感谢大家的观看和支持!最后,☺祝愿大家每天有钱赚!!!欢迎关注、关注!