"""
使用Mnist数据集来测试上节使用的cross entropy
"""
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
#1、设置网络超参数
batch_size=200
learning_rate=0.01
epochs=10
#2、从网上下载MNIST的数据集
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('mnist_data', train=True, download=False,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('mnist_data', train=False, download=False,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=batch_size, shuffle=True)
#3、这里是网络--为了便于理解优化过程,所以这样写
w1, b1 = torch.randn(200, 784, requires_grad=True), torch.zeros(200, requires_grad=True)
w2, b2 = torch.randn(200, 200, requires_grad=True), torch.zeros(200, requires_grad=True)
w3, b3 = torch.randn(10, 200, requires_grad=True), torch.zeros(10, requires_grad=True)
#这里使用了kaiming (He initialization)---凯明初始化方法,专门针对relu激活函数的初始化方法---加了这个凯明初始化以后结果出现了很好地变换
torch.nn.init.kaiming_normal_(w1)
torch.nn.init.kaiming_normal_(w2)
torch.nn.init.kaiming_normal_(w3)
#4、网络的搭建
def forward(x):
x = x@w1.t() + b1
x = F.relu(x) #使用relu函数,不会出现梯度弥散的情况---loss长时间得不到更新,loss最后出现一个常值---梯度信息接近于0
x = x@w2.t() + b2
x = F.relu(x)
x = x@w3.t() + b3
x = F.relu(x) #最后的输出层,relu激活函数是可以不要的
return x
"""
影响training的因素有:
1、learning rate过大
2、gradient vanish---梯度弥散(参数梯度为0,导致loss保持为常数,loss长时间得不到更新)
3、初始化问题----参数初始化问题
"""
#我们使用的是SGD优化器
optimizer = optim.SGD([w1, b1, w2, b2, w3, b3], lr=learning_rate)
criteon = nn.CrossEntropyLoss() #计算分类误差--LOSS
#训练模型---train
for epoch in range(epochs): #一个epoch是指train完整个数据集
#batch_idx=[0-299]
for batch_idx, (data, target) in enumerate(train_loader): # data[b,1,28,28]--->[b,784]; target[b] b--->batch_size
data = data.view(-1, 28*28) #这个view的用法还不是很熟悉,这个是再不更改数据量大小的情况在,改变tensor的shape
logits = forward(data) #这里是网络的输出
loss = criteon(logits, target) #调用cross—entorpy计算输出值和真实值之间的loss
optimizer.zero_grad() #然后是一系列的优化梯度更新,优化参数
loss.backward()
optimizer.step()
if batch_idx % 100 == 0: #每100个bachsize打印输出的结果,看看loss的情况
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx/ len(train_loader), loss.item()))
"""
len(data)---指的是一个batch_size;
len(train_loader.dataset)----指的是train_loader这个数据集中总共有多少张图片(数据)
len(train_loader)---- len(train_loader.dataset)/len(data)---就是这个train_loader要加载多少次batch
"""
#测试网络---test----每训练完一个epoch检测一下测试结果---因为每一个epoch已经优化了batch次参数,得到的参数信息还是OK的
test_loss = 0
correct = 0
for data, target in test_loader:
data = data.view(-1, 28 * 28) #[200,1,28,28]
logits = forward(data) #logits的shape=[200,10]--200是batchsize,10是最后输出结果的10分类
test_loss += criteon(logits, target).item() #每次将test_loss进行累加 #target=[200,1]---每个类只有一个正确结果
pred = logits.data.max(1)[1]
#这里losgits.data是一个二维数组;其dim=1;max()---返回的是每行的最大值和最大值对应的索引
#max(1)----是指每行取最大值;max(1)[1]---取每行最大值对应的索引号
correct += pred.eq(target.data).sum() #预测值和目标值相等个数进行求和--在for中,将这个test_loader中相等的个数都求出来
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))