在Mnist数据集中,我们要得到的输出是0-9,共有十类,这种情况下我们希望输出0-9的概率都大于0,且和为1

是最后一层线性层的输出,
softmax函数:

损失函数:LOSS=-Y*logY_hat
NLLLoss:nagative log likelihood loss
输入一个 y是真实标签,另一个输入要求是softmax之后求对数

实现过程:

在PyTorch中,交叉熵损失全部封装成了Torch.nn.CrossEntropyLoss()
要求y是长整形张量LongTensor([0])表示第几个标签分类,在构造时直接用CrossEntropyLoss,然后计算loss
举例~

代码在pytroch中跑不通不知道为啥,参考了别人的代码
import torch
y = torch.LongTensor([2, 0, 1]) # 注意此处是LongTensor
# z_1和z_2是最后一层输出,进入Softmax之前的值,所以每个分类之和不为1
# 每行元素代表对一个对象的分类情况,共三个对象
z_1 = torch.Tensor([[0.1, 0.2, 0.9],
[1.1, 0.1, 0.2],
[0.2, 2.1, 0.1]])
z_2 = torch.Tensor([[0.9, 0.2, 0.1],
[0.1, 0.1, 0.5],
[0.2, 0.1, 0.7]])
criterion = torch.nn.CrossEntropyLoss()
print(criterion(z_1, y), criterion(z_2, y))结果:
输出为:
![]()
应用在MNIST中:

第零步:首先导入包
transoform是用来对图像处理的 ,functional用的relu激活函数,optium优化器的包

第一步:准备数据集
transform把Pillow图像转换成Tensor,把0-255像素值转换成0-1,然后把维度28*28变成1*28*28的张量,这个过程用transform中的totensor实现,normalize(mean均值,std标准差)变成0-1分布~给神经网络训练
黑白图像单通道图像,彩色是RGB三通道图像

第二步:设计模型

改动:激活层采用ReLu,最后一个输出层并不做激活因为用交叉熵做softmax
输入维度:N样本(4个参数,4维),每个样本是一维,28*28的图像,但在神经网络中要求输入样本为矩阵,所以第一步把1*28*28的三阶张量变成一阶的向量,怎么变呢?把图片的每一行拼起来构成一串~
view(-1,784)把张量变成2阶张量(2个参数),矩阵784列,-1表示自动去算batchsize
经过view之后变成了(N,784)的矩阵
然后经过第一个线性层变成512,然后做relu
然后512降成256,然后relu激活~数字一样就可以对接起来~
最后降成10,表示0-9对应的线性值
网络:
需要5层将784-10层
forward 第一步view改变形状,用relu对每一层结果激活,最后一层不激活,直接接softmax
将网络定义成model=Net()

第三步:损失函数和优化器
交叉熵损失,由于样本较大,优化器用带冲量的SGD梯度下降

第四步:训练、测试
train:把训练的一轮循环封装成函数
每训练300轮打印一次running loss

test:
不用计算梯度~with torch.no_grad
步骤:从test_loader拿数据,那完了做预测,预测出了output,把每行最大值的下标拿出来,对应他的分类,用max(,dim=1)dim=1表示第一个维度,行,返回的值有两个,第一个是最大值,第二个是最大值的下标。找完之后total总数先加批量的总数,label是一个矩阵,N个样本就是N*1,size就是元组(N,1)
然后预测与标签做等于比较。然后求和
等所有数据跑完之后用正确的/总数求accuracy

假设训练10轮:

结果:
损失不断降低。测试的准确率上升!但最后准确率上不去是因为对图像用全连接神经网络忽略了对局部信息的利用,把所有的元素都全连接了,处理时权重不够多,处理图像时更关心高级别的特征~如果特征提取会好一点~人工特征提取方法:傅里叶变换、小波变化,深度学习中可以自动特征提取
全部代码:
import torch
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
import torch.nn.functional as F
batch_size =64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307, ), (0.3081, ))])
#将原始像素数据归一到(0,1)中 并基于均值0.1307和标准差0.3081来对数据进行标准化处理
train_dataset = datasets.MNIST(root='D:\Code\Pytorch exercise/dataset/mnist', train=True, download=True,transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True,batch_size=batch_size)
#(下载)加载训练集,之后进行batch分组
test_dataset = datasets.MNIST(root='D:\Code\Pytorch exercise/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) #784 = 28 x 28 ,像素点平铺后的大小
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()
#---计算损失和更新
criterion = torch.nn.CrossEntropyLoss()#交叉熵 size_average=False
optimizer = torch.optim.SGD(model.parameters(), lr = 0.01, momentum=0.5)
#---计算损失和更新
def train(epoch):
running_loss = 0.0 #计算loss的累积
for batch_idx, data in enumerate(train_loader, 0):
inputs, target = data
optimizer.zero_grad()
#forward + backward + update
outputs = model(inputs)
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
total = 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))
if __name__ == '__main__':
for epoch in range(10):
train(epoch)
test()
如果出现报错
UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the ten参考CSDN解决办法:
结果:
[7, 300] loss: 0.059
[7, 600] loss: 0.063
[7, 900] loss: 0.060
Accuracy on test set: 96 %
[8, 300] loss: 0.050
[8, 600] loss: 0.045
[8, 900] loss: 0.052
Accuracy on test set: 97 %
[9, 300] loss: 0.038
[9, 600] loss: 0.042
[9, 900] loss: 0.038
Accuracy on test set: 97 %
[10, 300] loss: 0.028
[10, 600] loss: 0.032
[10, 900] loss: 0.034
Accuracy on test set: 97 %
练习:
