Pytorch学习
环境配置及安装
六十分钟快速入门
Pytorch官方教程中文版
Github代码examples
MNIST数据集:手写数字图片识别
参考Github代码:https://github.com/pytorch/examples/tree/master/mnist
# -*- coding: utf-8 -*-
"""
Created on Sun Jan 12 14:56:02 2020
"""
from __future__ import print_function#则意味着在新旧版本的兼容性方面存在差异,处理方法是按照最新的特性来处理
import torch
import argparse #python自带的命令行参数解析包,可以用来方便地读取命令行参数
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms #torchvision包由流行的数据集、模型架构和用于计算机视觉的常见图像转换组成
from torch.optim.lr_scheduler import StepLR #每过step_size个epoch,做一次学习率更新
class Net(nn.Module): #torch.nn.Module所有神经网络模块的基类
def __init__(self):
super(Net, self).__init__() #对继承自父类的属性进行初始化。而且是用父类的初始化方法来初始化继承的属性。
#输入(N, C_in, H, W) 输出(N, C_out, H_out, W_out)
#MNIST图像:28 * 28
self.conv1 = nn.Conv2d(1, 32, 3, 1) # 二维卷积层:输入通道数,输出通道数,kernel_size,stride
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout2d(0.25)
self.dropout2 = nn.Dropout2d(0.5)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10) #10个数字,10类
def forward(self, x):
#28 * 28
x = self.conv1(x)
#26 * 26
x = F.relu(x)
x = self.conv2(x)
#24 * 24
x = F.max_pool2d(x, 2) #池化
#12 * 12
x = self.dropout1(x)
x = torch.flatten(x, 1)
#9216 * 1
x = self.fc1(x)
#128 * 1
x = F.relu(x)
x = self.dropout2(x)
x = self.fc2(x)
#10 * 1
output = F.log_softmax(x, dim = 1) #(N, C, H, W) 转换成概率分布的形式,并且取对数
return output
def train(args, model, device, train_loader, optimizer, epoch):
model.train()#针对在网络train和eval时采用不同方式的情况,比如 BatchNormalization 和 Dropout
for batch_idx, (data, target) in enumerate(train_loader): #enumerate返回索引和值
data, target = data.to(device), target.to(device)#将所有最开始读取数据时的tensor变量copy一份到device所指定的GPU上去
optimizer.zero_grad() #梯度置零
output = model(data)
loss = F.nll_loss(output, target) #log_softmax对应nll_loss softmax对应CrossEntopyLoss
loss.backward() #反向
optimizer.step() #更新参数空间。step函数使用的是当前参数空间对应的梯度,所以在optimizer使用之前要清零一下
#间隔输出 某个batch的loss
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())) #item获得一个元素tensor的value
#dataset的长度:数据集的长度
#loader的长度:batch的数量
#data的长度:一个batch的大小 batch_size
def test(args, 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
pred = output.argmax(dim = 1, keepdim = True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
#view_as:返回被视作与给定的tensor相同大小的原tensor
test_loss /= len(test_loader)
#test_loss是累计了所有batch的loss, 所以取平均
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
def main():
# Training settings
parser = argparse.ArgumentParser(description = 'Pytorch MNIST Example') #ArgumentParser类生成一个对象,description描述信息
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 = 1, metavar = 'N', #避免跑太久,先设为1
help = 'number of eopchs to train (default:14)') #help用来描述这个选项的作用
parser.add_argument('--lr', type = float, default = 1.0, metavar = 'LR', #metavar用在help信息的输出中
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('--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 = False,
help = 'For Saving the current Model')
args = parser.parse_args() #parser对象的parse_args()获取解析的参数
use_cuda = not args.no_cuda and torch.cuda.is_available() #有GPU:args.no_cuda=false,torch.cuda.is_available=true
torch.manual_seed(args.seed)#设置种子用于生成随机数,以使得结果是确定的
device = torch.device("cuda" if use_cuda else "cpu")
#num_workers:加载数据时使用多少子进程
kwargs = {'num_workers' : 1, 'pin_memory' : True} if use_cuda else{}
train_loader = torch.utils.data.DataLoader(
#在训练模型时使用到此函数,用来把训练数据分成多个小组,此函数每次抛出一组数据。
#直至把所有的数据都抛出。就是做一个数据的初始化。
#DataLoader就是用来包装所使用的数据,每次抛出一批数据
# 从数据库中每次抽出batch_size个样本
datasets.MNIST('../data',train = True, download = True,
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,),(0.3081,))
])),
batch_size = args.batch_size, shuffle = True, **kwargs) #batch_size表示batch大小,shuffle:是否打乱数据顺序
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=args.test_batch_size, shuffle=True, **kwargs)
model = Net().to(device)
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(args, model, device, test_loader)
scheduler.step() #用来更新优化器的学习率
if args.save_model:
torch.save(model.state_dict(), "mnist_cnn.pt")#state_dict 是一个简单的python的字典对象,将每一层与它的对应参数建立映射关系
if __name__ == '__main__':
main()
#(注释皆为自己理解,如有错误,欢迎指出)
只跑了一轮