在安装好pytorch环境之后开始跑代码。
一、解析代码
1.导入包
import argparse #用于解析命令行参数
import torch
import torch.nn as nn #构建神经网络的核心模块
import torch.nn.functional as F #包含了许多神经网络的功能函数,例如激活函数和损失函数等
import torch.optim as optim #优化器
from torchvision import datasets, transforms #torchvision是PyTorch的一个拓展包,提供数据集、模型架构和图形变化等功能,transforms提供了图形变化的功能
from torch.optim.lr_scheduler import StepLR #调整学习率的一个模块
2.定义神经网络模型
class Net(nn.Module): #定义了一个名为Net的神经网络类,继承自nn.Module(父类)(在pytorch中所有的神经网络都应该继承此类)
def __init__(self): #初始化
super(Net, self).__init__() #执行父类的构造函数,使能够调用父类的属性
self.conv1 = nn.Conv2d(1, 32, 3, 1) #二维卷积层
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout(0.25) #丢弃层
self.dropout2 = nn.Dropout(0.5)
self.fc1 = nn.Linear(9216, 128) #全连接层
self.fc2 = nn.Linear(128, 10)
def forward(self, x): #前向传播方法,x是输入数据
x = self.conv1(x)
x = F.relu(x)
x = self.conv2(x)
x = F.relu(x)
x = F.max_pool2d(x, 2) #使用2*2的最大池化来减少空间维度
x = self.dropout1(x)
x = torch.flatten(x, 1) #将多维输入x展平成一维
x = self.fc1(x)
x = F.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1) #应用log_softmax函数,该函数是softmax函数的对数版本,常用于多分类的对数层,dim=1指定维度
return output
3.定义训练函数
def train(args, model, device, train_loader, optimizer, epoch): #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() #重置参数梯度为0
output = model(data) #执行前向传播
loss = F.nll_loss(output, target) #计算负对数似然损失(Negative Log Likelihood Loss, NLL Loss)
loss.backward() #计算反向传播
optimizer.step() #更新模型参数
if batch_idx % args.log_interval == 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()))
if args.dry_run: #为了方便测试的代码
break
4.定义测试函数
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() # sum up batch loss 计算负对数似然损失,所有样本的,.item()将损失值转换成Python标量
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
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)))
5.主函数
def main():
# Training settings 使用argparse库来解析命令行参数
parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
parser.add_argument('--batch-size', type=int, default=64, metavar='N',
help='input batch size for training (default: 64)')
parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
help='input batch size for testing (default: 1000)')
parser.add_argument('--epochs', type=int, default=14, metavar='N',
help='number of epochs to train (default: 14)')
parser.add_argument('--lr', type=float, default=1.0, metavar='LR',
help='learning rate (default: 1.0)')
parser.add_argument('--gamma', type=float, default=0.7, metavar='M',
help='Learning rate step gamma (default: 0.7)')
parser.add_argument('--no-cuda', action='store_true', default=False,
help='disables CUDA training')
parser.add_argument('--no-mps', action='store_true', default=False,
help='disables macOS GPU training')
parser.add_argument('--dry-run', action='store_true', default=False,
help='quickly check a single pass')
parser.add_argument('--seed', type=int, default=1, metavar='S',
help='random seed (default: 1)')
parser.add_argument('--log-interval', type=int, default=10, metavar='N',
help='how many batches to wait before logging training status')
parser.add_argument('--save-model', action='store_true', default=True,
help='For Saving the current Model')
args = parser.parse_args()
use_cuda = not args.no_cuda and torch.cuda.is_available()
# use_mps = not args.no_mps and torch.backends.mps.is_available()
torch.manual_seed(args.seed)
if use_cuda:
device = torch.device("cuda")
# elif use_mps:
# device = torch.device("mps") mps好像只有mac电脑才能用
else:
device = torch.device("cpu")
train_kwargs = {'batch_size': args.batch_size}
test_kwargs = {'batch_size': args.test_batch_size}
if use_cuda:
cuda_kwargs = {'num_workers': 1, #cuda_kwargs 是一个字典,代表使用CUDA时,DataLoader 的一些额外参数, 数据加载的子进程数
'pin_memory': True,
'shuffle': True} #打乱数据顺序,仅对训练数据有用
train_kwargs.update(cuda_kwargs)
test_kwargs.update(cuda_kwargs)
transform=transforms.Compose([ #使用图像变换工具变换
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
dataset1 = datasets.MNIST('../data', train=True, download=True,
transform=transform)
dataset2 = datasets.MNIST('../data', train=False,
transform=transform)
train_loader = torch.utils.data.DataLoader(dataset1,**train_kwargs)
test_loader = torch.utils.data.DataLoader(dataset2, **test_kwargs)
model = Net().to(device) #创建一个Net类的示例,并传到CPU和GPU上
optimizer = optim.Adadelta(model.parameters(), lr=args.lr) #优化器优化参数
scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma) #调整学习率
for epoch in range(1, args.epochs + 1):
train(args, model, device, train_loader, optimizer, epoch)
test(model, device, test_loader)
scheduler.step()
if args.save_model:
torch.save(model.state_dict(), "mnist_cnn.pt")
6.最后一步
if __name__ == '__main__':
main()