目录
以下神经网络构建均以上图为例
一、关键部分代码分解
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=weight−learningrate∗gradient,写成代码如下
# 梯度下降更新权值的代码
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.datasets
和torch.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
如若文中有误,欢迎批评指正