基本操作

导包

1
2
3
4
5
6
7
8
9
import torch
#torch.nn内含有Module等常用的类
from torch import nn
#torch.utils.data.DataLoader用来处理数据以及存储数据
from torch.utils.data import DataLoader
#torchvision.datasets用来下载常用的数据集
from torchvision import datasets
#torchvision.transforms.ToTensor:transforms相关
from torchvision.transforms import ToTensor

下载及导入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Download training data from open datasets.
training_data = datasets.FashionMNIST(
root="data",
train=True,
download=True,
transform=ToTensor(),
)
# Download test data from open datasets.
test_data = datasets.FashionMNIST(
root="data",
train=False,
download=True,
transform=ToTensor(),
)
#dataset中有大量常用的数据集标准格式,常用的方式是通过datasets.'对应的数据集'(root,train,download,transform)进行下载,返回的是数据集

分批量读取数据

1
2
3
4
5
6
7
8
9
batch_size = 64
train_dataloader=DataLoader(training_data,batch_size=batch_size)
test_dataloader=DataLoader(test_data,batch_size=batch_size)
#DataLoader:处理训练集和测试集,并分成对应batch
for X,y in test_dataloader:
print("Shape of X [N, C, H, W]: ", X.shape)
print("Shape of y: ", y.shape, y.dtype)
break
#检验数据是否处理成功

定义神经网络模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
device=torch.accelerator.current_accelerator().type if torch.accelerator.is_available() else "cpu"
#默认使用的设备是当前加速器,如果当前没有加速器如cuda或者mtx,则使用cpu
print(f"Using {device} device")

#继承nn.Module类
class NeuralNetwork(nn.Module):
#初始构造:定义一个带两个隐藏层的全连接层模型
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10)
)

#向前传播:输入数据集,首先展平数据,输入到Sequential中进行处理得到一个范围不确定的未规范化预测
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits

#实例化模型
model = NeuralNetwork().to(device)
print(model)

损失函数和优化算法定义

1
2
loss_fn=nn.CrossEntropyLoss()#因为这里是分类问题,所以选择交叉熵损失
optimizer=torch.optim.SGD(model.parameters(),lr=1e-3)#优化器选择随机梯度下降,torch.optim.SGD(model.parameters(),lr)

定义训练函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#训练和测试都是传入dataloader,model,loss_function和optimizer
def train(dataloader,model,loss_fn,optimizer):
#size:规模,指的是数据的总数量
size=len(dataloader.dataset)
#将model转为train状态
model.train()
#循环读取数据
for batch,(X,y) in enumerate(dataloader):
#将数据都转入默认的device中,因为模型之前已经存储在device中了,如果模型和数据不在同一个device中会报错
X,y=X.to(device),y.to(device)
#得到预测值
pred=model(X)
#得到损失值,这里loss是一个tensor,loss_fn(pred,y).item()得到的才是具体的数值
loss=loss_fn(pred,y)
#反向传播
loss.backward()
#optimizer更新参数
optimizer.step()
#将optimizer中存储的梯度清零,因为pytorch中梯度记录是累积的
optimizer.zero_grad()

#输出前一百次train log
if batch%100==0:
loss,current=loss.item(),(batch+1)*len(X)
print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]")

定义测试函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#与上述类似
def test(dataloader,model,loss_fn):
size=len(dataloader.dataset)
#这里的num_batches是
num_batches=len(dataloader)
#将模型转为评估状态
model.eval()
test_loss,correct=0,0
#这里使用with torch.no_grad():提醒pytorch不用记录此处的梯度,节省内存
with torch.no_grad():
for X,y in dataloader:
X,y=X.to(device),y.to(device)
pred=model(X)
#这里记录的是训练的总损失值
test_loss+=loss_fn(pred,y).item()
#这里记录的是整个训练中正确预测的个数
correct+=(pred.argmax(1)==y).type(torch.float).sum().item()
#除以每个批次的总数得到损失的平均值
test_loss/=num_batches
#这里得到的是accuracy
correct/=size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")

正式训练

1
2
3
4
5
6
epochs = 5
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)
print("Done!")