【CV】Pytorch一小时入门教程-代码详解

请添加图片描述
以下神经网络构建均以上图为例

一、关键部分代码分解

1.定义网络

import torch
import torch.nn as nn
import torch.nn.functional as F
# 注释均为注释下一行

class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        # 第一个卷积,输入1通道,用6个5×5的卷积核
        self.conv1 = nn.Conv2d(1, 6, 5)
        # 第二个卷积,输入6个通道(因为上一层卷积中用了6个卷积核),用16个5×5的卷积核
        self.conv2 = nn.Conv2d(6, 16, 5)
        # 第一个全连接层,输入16个5×5的图像(5×5是因为最开始输入的是32×32的图像,然后经过2个卷积2个池化变成了5×5),用全连接将其变为120个节点(一维化)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        # 将120个节点变为84个
        self.fc2 = nn.Linear(120, 84)
        # 将84个节点变为10个
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
    	# conv1的结果先用ReLU激活,再以2×2的池化核做max pool池化
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # conv2的结果先用ReLU激活,再以2×2的池化核做max pool池化,(池化核为正方形的时候,写2等于写2×2)
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        # 将高维向量转为一维
        x = x.view(-1, self.num_flat_features(x))
        # 用ReLU激活fc1的结果
        x = F.relu(self.fc1(x))
        # 用ReLU激活fc2的结果
        x = F.relu(self.fc2(x))
        # 计算出fc3的结果
        x = self.fc3(x)
        return x
        
	# 返回总特征数量
    def num_flat_features(self, x):
        size = x.size()[1:]  # all dimensions except the batch dimension
        # 计算总特征数量
        num_features = 1
        for s in size:
            num_features *= s
        return num_features


net = Net()
print(net)

"""
Net(
  (conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)
"""

params = list(net.parameters())
# 共有5层网络,每层网络包含一个weight(权重)和bias(偏差),所以一共有10个。并且在每一层中,weight保存在前面,bias保存在后面
print(len(params))
print(params[0].size())  # conv1's .weight
print(params[1].size())	 # conv1's .bias
"""
10
torch.Size([6, 1, 5, 5])
torch.Size([6])
"""
# randn中4个参数分别表示batch_size=1, 1通道(即灰度图像),图片尺寸为32x32
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)

"""
tensor([[ 0.0114,  0.0476, -0.0647,  0.0381,  0.0088, -0.1024, -0.0354,  0.0220,
         -0.0471,  0.0586]], grad_fn=<AddmmBackward>)
"""

#清空缓存
net.zero_grad()
out.backward(torch.randn(1, 10))

Pytorch(六)(模型参数的遍历)——net.parameters() & net.named_parameters() & net.state_dict()

2.损失函数(代价函数)

"""
input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
      -> view -> linear -> relu -> linear -> relu -> linear
      -> MSELoss
      -> loss
"""
output = net(input)
target = torch.randn(10)  # a dummy target, for example
target = target.view(1, -1)  # make it the same shape as output
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

print(loss.grad_fn)  # MSELoss
print(loss.grad_fn.next_functions[0][0])  # Linear
print(loss.grad_fn.next_functions[0][0].next_functions[0][0])  # ReLU

"""
<MseLossBackward object at 0x7efbcad51a58>
<AddmmBackward object at 0x7efbcad51b38>
<AccumulateGrad object at 0x7efbcad51b38>
"""

# 反向传播计算梯度(就是偏导数)
net.zero_grad()     # zeroes the gradient buffers of all parameters

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

"""
conv1.bias.grad before backward
tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward
tensor([ 0.0087, -0.0073,  0.0013,  0.0006, -0.0107, -0.0042])
"""

3.更新权值

这里用随机梯度下降(SGD),梯度下降中的偏导数值(即梯度) g r a d i e n t gradient gradient已经在上一节中计算出,更新权值的公式为: w e i g h t = w e i g h t − l e a r n i n g r a t e ∗ g r a d i e n t weight=weight-learning rate*gradient weight=weightlearningrategradient,写成代码如下

# 梯度下降更新权值的代码
learning_rate = 0.01
for f in net.parameters():
    f.data.sub_(f.grad.data * learning_rate)

在神经网络中用下面的代码

import torch.optim as optim

# create your optimizer
optimizer = optim.SGD(net.parameters(), lr=0.01)

# in your training loop:
optimizer.zero_grad()   # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()    # Does the update

二、训练完整的分类器

1.数据处理

当我们需要处理图像、文本、音频或者视频的时候,可以使用标准的python库来将这些数据转化为numpy array,然后可以其再转化为Tensor。下面列出一些相应的python库:

  • 图片:Pillow、OpenCV
  • 音频:scipy、librosa
  • 文本:原始的Python、Cython、NLTK、SpaCy

对于视觉领域,有torchvision,他可以将很多知名数据的数据集涵盖在内。并且,通过torchvision.datasetstorch.utils.data.DataLoader进行数据的转化。
在这里使用 CIFAR10 数据集,它有以下各类: ‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’。在这个数据集中的图像尺寸都是32×32的。

2. 训练模型(代码详解)

训练步骤:
1.装载数据,并将其标准化;
2.定义CNN;
3.定义损失函数;
4.训练神经网络;
5.测试网络;

CPU训练

import torch
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import torch.utils.data
import torch.nn as nn
import torch.nn.functional as F

# 数据处理
transform = transforms.Compose([
    transforms.ToTensor(),  # 转换为tensor格式
    # 对图像进行标准化,即让数据集的图像的均值变为0,标准差变为1,把图片3个通道中的数据整理到[-1,1]的区间中
    # 输入的参数第一个括号内是3个通道的均值,第二个是3个通道的标准差,这些数据需要自己算好再放进这个函数里,不然每次运行normalize函数都要遍历一遍数据集
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])

# 定义训练集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
# 如果没有import torch.utils.data,这里会出现Warning:Cannot find reference ‘data‘ in ‘__init__.py‘
# torch.utils.data.DataLoader用于将已有的数据读取接口的输入按照batch size封装成Tensor
# shuffle参数表示是否在每个epoch后打乱数据;num_workers表示用多少个子进程加载数据,0表示数据将在主进程中加载,默认为0,这里不知道为啥设置多线程会报错
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True)
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False)
# testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)


classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')


# 显示图片函数
def imshow(img):
    img = img / 2 + 0.5  # 逆归一化,公式似乎是img/(均值*batchsize)+方差
    npimg = img.numpy()
    # plt.imshow()中应有的参数为(imagesize1,imagesize2,channels),在RGB图像中,channels=3,imagesize1为行数,imagesize2为列数,即分别为图片的高和宽
    # npimg中的参数顺序为(channels,imagesize1,imagesize2)
    # np.transpose(0,2,1)表示将数据的第二维和第三维交换
    # 则np.transpose(npimg, (1, 2, 0))就能将npimg变成(imagesize1,imagesize2,channels)的参数顺序,然后输入plt.imshow()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# get some random training images得到随机的batchsize张图片(随机是因为之前定义trainloader的时候设置开启了随机)
# dataloader本质上是一个可迭代对象,可以使用iter()进行访问,采用iter(dataloader)返回的是一个迭代器,然后可以使用next()或者enumerate访问
dataiter = iter(trainloader)
# 访问iter(dataloader)时,imgs在前,labels在后,分别表示:图像转换0~1之间的值,labels为标签值(在这里labels就是图像所属的分类的标号)。并且imgs和labels是按批次进行输入的。
# 因为之前设置了batch_size=4,所以这里的images中会有4张图片
images, labels = dataiter.next()

# show images
# torchvision.utils.make_grid()将多张图片组合成一张图片,padding为多张图片之间的间隙
imshow(torchvision.utils.make_grid(images, padding=2))
# 按顺序输出四张图片的标签(所属分类的名字)
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))


# 定义网络
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, (5, 5))
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, (5, 5))
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


net = Net()

for epoch in range(2):  # 多次循环访问整个数据集(这里用了两个epoch,即循环访问2遍整个数据集)

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs   得到输入的batchsize张图片,放在inputs中,labels存储该图片所属分类的名字
        inputs, labels = data

        # 计算交叉熵https://zhuanlan.zhihu.com/p/98785902
        criterion = nn.CrossEntropyLoss()
        # optim.SGD表示使用随机梯度下降算法
        # lr是学习率;momentum是动量(在梯度下降算法中添加动量法)https://blog.csdn.net/weixin_40793406/article/details/84666803
        optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
        # 归零参数梯度
        optimizer.zero_grad()

        # forward + backward + optimize
        # 向神经网络输入数据,然后得到输出outputs
        outputs = net(inputs)
        # 输入神经网络输出的预测和实际的数据的labels,计算交叉熵(偏差)
        loss = criterion(outputs, labels)
        # 将误差反向传播
        loss.backward()
        # 更新所有参数(权重)
        optimizer.step()

        # 累加经过这一个batchsize张图片学习后的误差
        # 《pytorch学习:loss为什么要加item()》https://blog.csdn.net/github_38148039/article/details/107144632
        running_loss += loss.item()
        if i % 2000 == 1999:  # 每2000个mini-batches(即2000个batchsize次)打印一次,然后归零running_loss
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

# 创建测试集的迭代器
dataiter = iter(testloader)
# 读取测试集中的前四张图片
images, labels = dataiter.next()

# 显示前面读取出来的四张图片和其所属的分类的名字(label)
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

# 传入神经网络得到预测结果
outputs = net(images)

# 输入的第一个参数是softmax输出的一个tensor,这里就是outputs所存储的内容;第二个参数是max函数索引的维度,0是取每列的最大值,1是每行的最大值
# 返回的第一个参数是预测出的实际概率,由于我们不需要得知实际的概率,所以在返回的第一个参数填入_不读取,第二个返回是概率的最大值的索引,存在predicted中
# 《torch.max()使用详解》https://www.jianshu.com/p/3ed11362b54f
_, predicted = torch.max(outputs, 1)

# 打印四张图片预测的分类
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

# 计数器初始化置零
correct = 0
total = 0
# 计算总准确率
# 被该语句包裹起来的代码将不会被跟踪梯度,如果测试集进行的运算被跟踪进度可能会导致显存爆炸
with torch.no_grad():
    for data in testloader:
        # 读取数据(batchsize个数据,这里为4张图片)
        images, labels = data
        # 得到神经网络的输出
        outputs = net(images)
        # 返回每行概率最大值的索引
        _, predicted = torch.max(outputs.data, 1)
        # labels.size(0)指batchsize的值,这里batchsize=4
        total += labels.size(0)
        # predicted == labels对predicted和labels中的每一项判断是否相等
        # (predicted == labels).sum()返回一个tensor,tensor中是判断为真的数量,比如有一项是相同的,则返回tensor(1)
        # 如果有一项是相同的,(predicted == labels).sum().item()返回1
        # correct在这里即为4张图片中预测正确的数量(这里计算的是总概率)
        correct += (predicted == labels).sum().item()

# 输出神经网络在测试集上的准确率
print('Accuracy of the network on the 10000 test images: %d %%' % (
        100 * correct / total))

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
# 计算每个分类的准确率
# 被该语句包裹起来的代码将不会被跟踪梯度
with torch.no_grad():
    for data in testloader:
        # 读取数据(batchsize个数据,这里为4张图片)
        images, labels = data
        # 得到神经网络的输出
        outputs = net(images)
        # 返回每行概率最大值的索引
        _, predicted = torch.max(outputs, 1)
        # squeeze()用于去除维数为1的维度,比如1行3列矩阵就会去掉行这个维度,变成第一维含有3个元素
        c = (predicted == labels).squeeze()
        for i in range(4):
            # label存储当前图像所属分类的索引号
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1
# 输出神经网络在测试集上的每个分类准确率
for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

GPU训练

import torch
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import torch.utils.data
import torch.nn as nn
import torch.nn.functional as F

# 数据处理
transform = transforms.Compose([
    transforms.ToTensor(),  # 转换为tensor格式
    # 对图像进行标准化,即让数据集的图像的均值变为0,标准差变为1,把图片3个通道中的数据整理到[-1,1]的区间中
    # 输入的参数第一个括号内是3个通道的均值,第二个是3个通道的标准差,这些数据需要自己算好再放进这个函数里,不然每次运行normalize函数都要遍历一遍数据集
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])

# 定义训练集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
# 如果没有import torch.utils.data,这里会出现Warning:Cannot find reference ‘data‘ in ‘__init__.py‘
# torch.utils.data.DataLoader用于将已有的数据读取接口的输入按照batch size封装成Tensor
# shuffle参数表示是否在每个epoch后打乱数据;num_workers表示用多少个子进程加载数据,0表示数据将在主进程中加载,默认为0,这里不知道为啥设置多线程会报错
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True)
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)

testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False)
# testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)


classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')


# 显示图片函数
def imshow(img):
    img = img / 2 + 0.5  # 逆归一化,公式似乎是img/(均值*batchsize)+方差
    # numpy不能读取CUDA tensor 需要将它转化为 CPU tensor
    npimg = img.cpu().numpy()
    # plt.imshow()中应有的参数为(imagesize1,imagesize2,channels),在RGB图像中,channels=3,imagesize1为行数,imagesize2为列数,即分别为图片的高和宽
    # npimg中的参数顺序为(channels,imagesize1,imagesize2)
    # np.transpose(0,2,1)表示将数据的第二维和第三维交换
    # 则np.transpose(npimg, (1, 2, 0))就能将npimg变成(imagesize1,imagesize2,channels)的参数顺序,然后输入plt.imshow()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


# get some random training images得到随机的batchsize张图片(随机是因为之前定义trainloader的时候设置开启了随机)
# dataloader本质上是一个可迭代对象,可以使用iter()进行访问,采用iter(dataloader)返回的是一个迭代器,然后可以使用next()或者enumerate访问
dataiter = iter(trainloader)
# 访问iter(dataloader)时,imgs在前,labels在后,分别表示:图像转换0~1之间的值,labels为标签值(在这里labels就是图像所属的分类的标号)。并且imgs和labels是按批次进行输入的。
# 因为之前设置了batch_size=4,所以这里的images中会有4张图片
images, labels = dataiter.next()

# show images
# torchvision.utils.make_grid()将多张图片组合成一张图片,padding为多张图片之间的间隙
imshow(torchvision.utils.make_grid(images, padding=2))
# 按顺序输出四张图片的标签(所属分类的名字)
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))


# 定义网络
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, (5, 5))
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, (5, 5))
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x


net = Net()

# 如果GPU(CUDA)可用,则用GPU,否则用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 打印使用的是GPU/CPU
print(device)
# 将网络放置到GPU
net.to(device)


for epoch in range(2):  # 多次循环访问整个数据集(这里用了两个epoch,即循环访问2遍整个数据集)

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the inputs   得到输入的batchsize张图片,放在inputs中,labels存储该图片所属分类的名字
        inputs, labels = data
        # 将数据放置到GPU上
        inputs, labels = inputs.to(device), labels.to(device)
        # 计算交叉熵https://zhuanlan.zhihu.com/p/98785902
        criterion = nn.CrossEntropyLoss()
        # optim.SGD表示使用随机梯度下降算法
        # lr是学习率;momentum是动量(在梯度下降算法中添加动量法)https://blog.csdn.net/weixin_40793406/article/details/84666803
        optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
        # 归零参数梯度
        optimizer.zero_grad()

        # forward + backward + optimize
        # 向神经网络输入数据,然后得到输出outputs
        outputs = net(inputs)
        # 输入神经网络输出的预测和实际的数据的labels,计算交叉熵(偏差)
        loss = criterion(outputs, labels)
        # 将误差反向传播
        loss.backward()
        # 更新所有参数(权重)
        optimizer.step()

        # 累加经过这一个batchsize张图片学习后的误差
        # 《pytorch学习:loss为什么要加item()》https://blog.csdn.net/github_38148039/article/details/107144632
        running_loss += loss.item()
        if i % 2000 == 1999:  # 每2000个mini-batches(即2000个batchsize次)打印一次,然后归零running_loss
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

# 创建测试集的迭代器
dataiter = iter(testloader)
# 读取测试集中的前四张图片
images, labels = dataiter.next()
# 将数据放置到GPU上
images, labels = images.to(device), labels.to(device)

# 显示前面读取出来的四张图片和其所属的分类的名字(label)
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

# 传入神经网络得到预测结果
outputs = net(images)

# 输入的第一个参数是softmax输出的一个tensor,这里就是outputs所存储的内容;第二个参数是max函数索引的维度,0是取每列的最大值,1是每行的最大值
# 返回的第一个参数是预测出的实际概率,由于我们不需要得知实际的概率,所以在返回的第一个参数填入_不读取,第二个返回是概率的最大值的索引,存在predicted中
# 《torch.max()使用详解》https://www.jianshu.com/p/3ed11362b54f
_, predicted = torch.max(outputs, 1)

# 打印四张图片预测的分类
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
                              for j in range(4)))

# 计数器初始化置零
correct = 0
total = 0
# 计算总准确率
# 被该语句包裹起来的代码将不会被跟踪梯度,如果测试集进行的运算被跟踪进度可能会导致显存爆炸
with torch.no_grad():
    for data in testloader:
        # 读取数据(batchsize个数据,这里为4张图片)
        images, labels = data
        # 将数据放置到GPU上
        images, labels = images.to(device), labels.to(device)
        # 得到神经网络的输出
        outputs = net(images)
        # 返回每行概率最大值的索引
        _, predicted = torch.max(outputs.data, 1)
        # labels.size(0)指batchsize的值,这里batchsize=4
        total += labels.size(0)
        # predicted == labels对predicted和labels中的每一项判断是否相等
        # (predicted == labels).sum()返回一个tensor,tensor中是判断为真的数量,比如有一项是相同的,则返回tensor(1)
        # 如果有一项是相同的,(predicted == labels).sum().item()返回1
        # correct在这里即为4张图片中预测正确的数量(这里计算的是总概率)
        correct += (predicted == labels).sum().item()

# 输出神经网络在测试集上的准确率
print('Accuracy of the network on the 10000 test images: %d %%' % (
        100 * correct / total))

class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
# 计算每个分类的准确率
# 被该语句包裹起来的代码将不会被跟踪梯度
with torch.no_grad():
    for data in testloader:
        # 读取数据(batchsize个数据,这里为4张图片)
        images, labels = data
        # 将数据放置到GPU上
        images, labels = images.to(device), labels.to(device)
        # 得到神经网络的输出
        outputs = net(images)
        # 返回每行概率最大值的索引
        _, predicted = torch.max(outputs, 1)
        # squeeze()用于去除维数为1的维度,比如1行3列矩阵就会去掉行这个维度,变成第一维含有3个元素
        c = (predicted == labels).squeeze()
        for i in range(4):
            # label存储当前图像所属分类的索引号
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1
# 输出神经网络在测试集上的每个分类准确率
for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        classes[i], 100 * class_correct[i] / class_total[i]))

CPU版本与GPU版本代码区别

GPU版本相较于CPU版本的主要区别有:

  • 第40行
npimg = img.cpu().numpy()
  • 第86~91行
# 如果GPU(CUDA)可用,则用GPU,否则用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 打印使用的是GPU/CPU
print(device)
# 将网络放置到GPU
net.to(device)
  • 第101行
inputs, labels = inputs.to(device), labels.to(device)
  • 第135行
images, labels = images.to(device), labels.to(device)
  • 第163行
images, labels = images.to(device), labels.to(device)
  • 第189行
images, labels = images.to(device), labels.to(device)




参考自以下文档
pytorch一小时教程
pytorch基础入门教程/一小时学会pytorch_CSDN
如若文中有误,欢迎批评指正

猜你喜欢

转载自blog.csdn.net/qq_42475234/article/details/123022150