网上找了一个代码,阅读代码,加上了相应的注释
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
BATCH_SIZE=512 #大概需要2G的显存
EPOCHS=20 # 总共训练批次
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 让torch判断是否使用GPU
#获取数据
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('data', train=True, download=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('data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=BATCH_SIZE, shuffle=True)
#定义模型
class ConvNet(nn.Module):
def __init__(self):
super().__init__()
# 1,28x28
self.conv1=nn.Conv2d(1,10,5) # 10, 24x24
self.conv2=nn.Conv2d(10,20,3) # 128, 10x10
self.fc1 = nn.Linear(20*10*10,500)
self.fc2 = nn.Linear(500,10)
def forward(self,x):
in_size = x.size(0)
out = self.conv1(x) #24
out = F.relu(out)
out = F.max_pool2d(out, 2, 2) #12
out = self.conv2(out) #10
out = F.relu(out)
out = out.view(in_size,-1)#展开成一维,方便进行FC
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
out = F.log_softmax(out,dim=1)
return out
model = ConvNet().to(DEVICE)
optimizer = optim.Adam(model.parameters())
#训练过程
'''
1 获取loss:输入图像和标签,通过infer计算得到预测值,计算损失函数;
2 optimizer.zero_grad() 清空过往梯度;
3 loss.backward() 反向传播,计算当前梯度;
4 optimizer.step() 根据梯度更新网络参数
链接:https://www.zhihu.com/question/303070254/answer/573037166
'''
def train(model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()#梯度置零,清空过往梯度,这种操作模式的好处可参考https://www.zhihu.com/question/303070254
output = model(data)
loss = F.nll_loss(output, target)#调用内置函数
loss.backward()#反向传播,计算当前梯度
optimizer.step()#根据梯度更新网络参数
if(batch_idx+1)%30 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))#Use torch.Tensor.item() to get a Python number from a tensor containing a single value:
#测试过程
def test(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)#正向计算预测值
test_loss += F.nll_loss(output, target, reduction='sum').item() # 将一批的损失相加
pred = output.max(1, keepdim=True)[1] # 找到概率最大的下标
correct += pred.eq(target.view_as(pred)).sum().item()#找到正确的预测值
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)))
#运行,这里也可以改成main的形式
for epoch in range(1, EPOCHS + 1):
train(model, DEVICE, train_loader, optimizer, epoch)
test(model, DEVICE, test_loader)
代码部分比较简单
1、数据读取
2、构建网络模型 ConvNet(nn.Module)
3、构建训练函数train
4、构建测试函数test
5、关于代码中的model.train(),model.eval()的说明:
参考 PyTorch进行训练和测试时指定实例化的model模式为:train/eval:
eval即evaluation模式,train即训练模式。仅仅当模型中有Dropout和BatchNorm是才会有影响。因为训练时dropout和BN都开启,而一般而言测试时dropout被关闭,BN中的参数也是利用训练时保留的参数,所以测试时应进入评估模式。
(在训练时,𝜇和𝜎2是在整个mini-batch 上计算出来的包含了像是64 或28 或其它一定数量的样本,但在测试时,你可能需要逐一处理样本,方法是根据你的训练集估算𝜇和𝜎2,估算的方式有很多种,理论上你可以在最终的网络中运行整个训练集来得到𝜇和𝜎2,但在实际操作中,我们通常运用指数加权平均来追踪在训练过程中你看到的𝜇和𝜎2的值。还可以用指数加权平均,有时也叫做流动平均来粗略估算𝜇和𝜎2,然后在测试中使用𝜇和𝜎2的值来进行你所需要的隐藏单元𝑧值的调整。在实践中,不管你用什么方式估算𝜇和𝜎2,这套过程都是比较稳健的,因此我不太会担心你具体的操作方式,而且如果你使用的是某种深度学习框架,通常会有默认的估算𝜇和𝜎2的方式,应该一样会起到比较好的效果)
6、损失函数,这是torch的loss function,这里用的是负对数似然,推导可以参考负对数似然
网友评论