Pytorch基础复习

Pytorch基础复习

Pytorch简单入门

  1. 安装以后进行简单测试:
  2. 验证GPU是否可以使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
from __future__ import print_function
import torch
x = torch.rand(5, 3)
print(x)

tensor([[0.3380, 0.3845, 0.3217],
[0.8337, 0.9050, 0.2650],
[0.2979, 0.7141, 0.9069],
[0.1449, 0.1132, 0.1375],
[0.4675, 0.3947, 0.1426]])

import torch
torch.cuda.is_available() // true就对了
  1. 张量:Pytorch 的一大作用就是可以代替 Numpy 库,Tensors张量,它相当于 Numpy 的多维数组(ndarrays)。两者的区别就是 Tensors 可以应用到 GPU 上加快计算速度
  2. Pytorch当中的张量是圆括号套中括号。中括号才是数组,外部一定是有一个圆括号的。
    张量的声明和定义
    1. 声明:
      1. torch.empty(): 声明一个未初始化的矩阵。
      2. torch.rand():随机初始化一个矩阵
      3. torch.zeros():创建数值皆为 0 的矩阵
      4. torch.tensor():直接传递 tensor 数值来创建
      5. tensor.new_ones():new_*() 方法需要输入尺寸大小。
      6. torch.randn_like(old_tensor):保留相同的尺寸大小
    2. 获取tensor的size:tensor.size()
    3. torch.Size 实际上是元组(tuple)类型,所以支持所有的元组操作。和上面的不一样,注意。
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
28
29
30
31
32
33
34
35
36
37
38
zero_x = torch.zeros(5, 3, dtype=torch.long)
print(zero_x)
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])


tensor1 = torch.tensor([5.5, 3])
print(tensor1)
tensor([5.5000, 3.0000])


# 显示定义新的尺寸是 5*3,数值类型是 torch.double
tensor2 = tensor1.new_ones(5, 3, dtype=torch.double) # new_* 方法需要输入 tensor 大小
print(tensor2)

tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=torch.float64)


# 修改数值类型
tensor3 = torch.randn_like(tensor2, dtype=torch.float)
print('tensor3: ', tensor3)

tensor3: tensor([[-0.4491, -0.2634, -0.0040],
[-0.1624, 0.4475, -0.8407],
[-0.6539, -1.2772, 0.6060],
[ 0.2304, 0.0879, -0.3876],
[ 1.2900, -0.7475, -1.8212]])

print(tensor3.size())
# 输出: torch.Size([5, 3])

加法操作。

  1. 加号运算符
  2. torch.add(tensor1, tensor2, [out=tensor3])
  3. tensor1.add_(tensor2):直接修改 tensor 变量

可以改变 tensor 变量的操作都带有一个后缀 _, 例如 x.copy_(y), x.t_() 都可以改变 x 变量

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
28
29
30
31
32
33
tensor3 = torch.rand(5, 3)
tensor4 = torch.rand(5, 3)
print('tensor3 + tensor4= ', tensor3 + tensor4)
print('tensor3 + tensor4= ', torch.add(tensor3, tensor4))
# 新声明一个 tensor 变量保存加法操作的结果
result = torch.empty(5, 3)
torch.add(tensor3, tensor4, out=result)
print('add result= ', result)
# 直接修改变量
tensor3.add_(tensor4)
print('tensor3= ', tensor3)

tensor3 + tensor4= tensor([[1.7876, 0.6522, 0.2087],
[1.3272, 0.8091, 0.7834],
[0.7197, 1.3567, 0.4729],
[1.0939, 1.0724, 0.2240],
[0.6902, 1.7552, 1.3359]])
tensor3 + tensor4= tensor([[1.7876, 0.6522, 0.2087],
[1.3272, 0.8091, 0.7834],
[0.7197, 1.3567, 0.4729],
[1.0939, 1.0724, 0.2240],
[0.6902, 1.7552, 1.3359]])
add result= tensor([[1.7876, 0.6522, 0.2087],
[1.3272, 0.8091, 0.7834],
[0.7197, 1.3567, 0.4729],
[1.0939, 1.0724, 0.2240],
[0.6902, 1.7552, 1.3359]])
tensor3= tensor([[1.7876, 0.6522, 0.2087],
[1.3272, 0.8091, 0.7834],
[0.7197, 1.3567, 0.4729],
[1.0939, 1.0724, 0.2240],
[0.6902, 1.7552, 1.3359]])

访问某一维数据。

对于 Tensor 的访问,和 Numpy 对数组类似,可以使用索引来访问某一维的数据,如下所示:

1
2
3
4
5
6
7
8
9
10
import torch
tensor3 = torch.rand(5, 3) #5行3列
# 访问 tensor3 第一列数据
print(tensor3[:, 0])
# 访问 tensor3 第一行数据
print(tensor3[0, :])

tensor([0.3894, 0.1781, 0.9123, 0.6887, 0.0363])
tensor([0.3894, 0.1461, 0.9902])

Tensor的尺寸修改。

对 Tensor 的尺寸修改,可以采用 torch.view() ,如下所示:

1
2
3
4
5
6
7
8
x = torch.randn(4, 4)
y = x.view(16)
# -1 表示除给定维度外的其余维度的乘积
z = x.view(-1, 8)
print(x.size(), y.size(), z.size())

torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])

如果 tensor 仅有一个元素,可以采用 .item() 来获取类似 Python 中整数类型的数值:

1
2
3
4
5
6
x = torch.randn(1)
print(x)
print(x.item())

tensor([0.4549])
0.4549027979373932

如果我想把Tensor里面的元素变成标量数组,需要用到numpy

1
2
3
4
5
6
7
8
9
10
11
12
import torch
import numpy as np

tensor3 = torch.rand(5, 3)
numpy_array = tensor3.numpy()
scalar_array = numpy_array.flatten()

print(scalar_array)

[0.35545653 0.4801997 0.783318 0.26430744 0.8636823 0.66436017
0.3103314 0.43500382 0.03554612 0.7856198 0.36438572 0.71389115
0.09969151 0.02212095 0.6391546 ]

Tensor 转换为 Numpy 数组.

  1. Tensor是向量,是多维向量组合。
  2. Numpy是向量,但是Numpy没有逗号,可以看做是标量
1
2
3
4
5
6
7
8
9
a = torch.ones(5)
print(a)
b = a.numpy()
print(b)
print(b.flatten())

tensor([1., 1., 1., 1., 1.])
[1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1.]

Numpy 数组转换为 Tensor。

1
2
3
4
5
6
7
8
9
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)

[2. 2. 2. 2. 2.]
tensor([2., 2., 2., 2., 2.], dtype=torch.float64)

CUDA张量。

Tensors 可以通过 .to 方法转换到不同的设备上,即 CPU 或者 GPU 上。例子如下所示:

1
2
3
4
5
6
7
8
9
10
11
# 当 CUDA 可用的时候,可用运行下方这段代码,采用 torch.device() 方法来改变 tensors 是否在 GPU 上进行计算操作
if torch.cuda.is_available():
device = torch.device("cuda") # 定义一个 CUDA 设备对象
y = torch.ones_like(x, device=device) # 显示创建在 GPU 上的一个 tensor
x = x.to(device) # 也可以采用 .to("cuda")
z = x + y
print(z)
print(z.to("cpu", torch.double)) # .to() 方法也可以改变数值类型

tensor([1.4549], device='cuda:0') # 第一个结果就是在 GPU 上的结果,打印变量的时候会带有 device='cuda:0'
tensor([1.4549], dtype=torch.float64) # 第二个是在 CPU 上的变量。

autograd

autograd库:要是提供了对 Tensors 上所有运算操作的自动微分功能,也就是计算梯度的功能。它属于 define-by-run 类型框架,即反向传播操作的定义是根据代码的运行方式,因此每次迭代都可以是不同的。

  • 设置torch.Tensor的属性:.requires_grad=True,那么就会开始追踪在该变量上的所有操作。
  • 而完成计算后,可以调用 .backward() 并自动计算所有的梯度
  • 得到的梯度都保存在属性 .grad中。
  • .detach()方法分离出计算的历史,可以停止一个 tensor 变量继续追踪其历史信息 ,同时也防止未来的计算会被追踪。
  • 防止跟踪历史(以及使用内存),可以将代码块放在 with torch.no_grad():内,因为模型会包含一些带有 requires_grad=True 的训练参数,但实际上并不需要它们的梯度信息。
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
28
29
30
31
32
33
34
35
36
37
38
39
import torch
x = torch.ones(2, 2, requires_grad=True)
# requires_grad=True 来追踪该变量相关的计算操作
# 显式的写出来,是因为默认requires_grad 是 False
# 也可以调用 x.requires_grad_(True)来设置
print(x)

tensor([[1., 1.],
[1., 1.]], requires_grad=True)

y = x + 2
print(y)

tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward>) # 操作结果都带有属性grad_fn:

print(y.grad_fn)

<AddBackward object at 0x00000216D25DCC88>

z = y * y * 3
out = z.mean()

print('z=', z)
print('out=', out)

z= tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward>) # 操作结果都带有属性grad_fn:

out= tensor(27., grad_fn=<MeanBackward1>) # 操作结果都带有属性grad_fn:

# 计算梯度,反向传播

out.backward() # out是一个标量
# 输出梯度 d(out)/dx
print(x.grad)

tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])

算出上面梯度的原因:

梯度计算

Function类

  • Tensor 和 Function 两个类是有关联并建立了一个非循环的图,可以编码一个完整的计算记录。
  • 每个 tensor 变量都带有属性 .grad_fn ,该属性引用了创建了这个变量的 Function (除了由用户创建的 Tensors,它们的 grad_fn=None)。
  • 如果要进行求导运算,可以调用一个 Tensor 变量的方法 .backward() 。如果该变量是一个标量,即仅有一个元素,那么不需要传递任何参数给方法
  • .backward(),当包含多个元素的时候,就必须指定一个 gradient 参数,表示匹配尺寸大小的 tensor

神经网络

在 PyTorch 中 torch.nn 专门用于实现神经网络。其中 nn.Module 包含了网络层的搭建,以及一个方法– forward(input) ,并返回网络的输出 output.

对于神经网络来说,一个标准的训练流程是这样的:

  • 定义一个多层的神经网络
  • 对数据集的预处理并准备作为网络的输入
  • 将数据输入到网络
  • 计算网络的损失
  • 反向传播,计算梯度
  • 更新网络的梯度,一个简单的更新规则是 weight = weight - learning_rate * gradient

首先定义一个神经网络,包含两层卷积层和三层全连接层:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):

def __init__(self):
super(Net, self).__init__()
# 输入图像是单通道,conv1 kenrnel size=5*5,输出通道 6
self.conv1 = nn.Conv2d(1, 6, 5)
# conv2 kernel size=5*5, 输出通道 16
self.conv2 = nn.Conv2d(6, 16, 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):
# max-pooling 采用一个 (2,2) 的滑动窗口
# 激活函数用relu
# 卷积->激活->池化
x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
# 核(kernel)大小是方形的话,可仅定义一个数字,如 (2,2) 用 2 即可
x = F.max_pool2d(F.relu(self.conv2(x)), 2)

# 16*5*5:方形的矩阵,展开成1行n列的矩阵,n是函数算出来的
x = x.view(-1, self.num_flat_features(x))

x = F.relu(self.fc1(x)) # 全连接->激活
x = F.relu(self.fc2(x))
x = self.fc3(x) # 只全连接,不再激活

# 计算一个张量中除批次维度外的所有维度的总特征数
def num_flat_features(self, x):
# 除了 batch 维度外的所有维度
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s

return num_features


net = Net()
print(net)

# 打印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())
print('参数数量: ', len(params))
# 参数数量: 10

# 随机定义一个变量输入网络
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)

tensor([[ 0.1005, 0.0263, 0.0013, -0.1157, -0.1197, -0.0141, 0.1425, -0.0521,
0.0689, 0.0220]], grad_fn=<ThAddmmBackward>)

# 清空所有参数的梯度缓存,然后计算随机梯度进行反向传播
net.zero_grad()
out.backward(torch.randn(1, 10))



# 新的测试用例
output = net(input)
# 定义伪标签
target = torch.randn(10)
# 调整大小,使得和 output 一样的 size
target = target.view(1, -1)
criterion = nn.MSELoss()

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

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss

# 如果调用 loss.backward() ,那么整个图都是可微分的,也就是说包括 loss ,图中的所有张量变量,只要其属性 requires_grad=True ,那么其梯度 .grad张量都会随着梯度一直累计。

定义的神经网络:

  • 必须实现forward 函数
  • 而 backward 函数在采用 autograd 时就自动定义好了
  • 在 forward 方法可以采用任何的张量操作
  • net.parameters() 可以返回网络的训练参数
  • 反向传播需要先清空梯度缓存,并反向传播随机梯度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import torch
import numpy as np

x = torch.rand(5, 3)
size = x.size()[1:]
print(x)
print(size)

tensor([[0.2872, 0.8773, 0.9682],
[0.0392, 0.2758, 0.7458],
[0.1696, 0.6978, 0.2294],
[0.8068, 0.5938, 0.4190],
[0.8449, 0.6836, 0.2507]])
torch.Size([3]) # 输出第二维的大小



torch.nn 只支持小批量(mini-batches)数据,也就是输入不能是单个样本,比如对于 nn.Conv2d 接收的输入是一个 4 维张量–nSamples * nChannels * Height * Width 。
所以,如果你输入的是单个样本,需要采用 input.unsqueeze(0) 来扩充一个假的 batch 维度,即从 3 维变为 4 维。
第一个维度是Batch维度

损失函数

损失函数的输入是 (output, target) ,即网络输出和真实标签对的数据,然后返回一个数值表示网络输出和真实标签的差距。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 新的测试用例
output = net(input)
# 定义伪标签
target = torch.randn(10)
# 调整大小,使得和 output 一样的 size
target = target.view(1, -1)
criterion = nn.MSELoss()

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

input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
-> view -> linear -> relu -> linear -> relu -> linear
-> MSELoss
-> loss

# 如果调用 loss.backward() ,那么整个图都是可微分的,也就是说包括 loss ,图中的所有张量变量,只要其属性 requires_grad=True ,那么其梯度 .grad张量都会随着梯度一直累计。

反向传播

反向传播的实现只需要调用 loss.backward() 即可,当然首先需要清空当前梯度缓存,即.zero_grad() 方法,否则之前的梯度会累加到当前的梯度,这样会影响权值参数的更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 清空所有参数的梯度缓存
net.zero_grad()
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.0069, 0.0021, 0.0090, -0.0060, -0.0008, -0.0073])

更新权重

采用随机梯度下降(Stochastic Gradient Descent, SGD)方法的最简单的更新权重规则如下:

  • weight = weight - learning_rate * gradient
1
2
3
4
# 简单实现权重的更新例子
learning_rate = 0.01
for f in net.parameters():
f.data.sub_(f.grad.data * learning_rate)

但是这只是最简单的规则,深度学习有很多的优化算法,不仅仅是 SGD,还有 Nesterov-SGD, Adam, RMSProp 等等.采用 torch.optim 库,使用例子如下所示:

1
2
3
4
5
6
7
8
9
10
11
import torch.optim as optim
# 创建优化器
optimizer = optim.SGD(net.parameters(), lr=0.01)

# 在训练过程中执行下列操作
optimizer.zero_grad() # 清空梯度缓存
output = net(input)
loss = criterion(output, target)
loss.backward()
# 更新权重
optimizer.step()

训练分类器

通常在处理如图片、文本、语音或者视频数据的时候,一般都采用标准的 Python 库将其加载并转成 Numpy 数组,然后再转回为 PyTorch 的张量

PyTorch 对于计算机视觉,特别创建了一个torchvision的库,它包含一个数据加载器(data loader),可以加载比较常见的数据集,比如 Imagenet, CIFAR10, MNIST 等等,然后还有一个用于图像的数据转换器(data transformers),调用的库是 torchvision.datasets 和 torch.utils.data.DataLoader。

训练CIFAR10 数据集:

  • 通过调用 torchvision 加载和归一化 CIFAR10 训练集和测试集;
  • 构建一个卷积神经网络;
  • 定义一个损失函数;
  • 在训练集上训练网络;
  • 在测试集上测试网络性能。
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
import torch
import torchvision
import torchvision.transforms as transforms

# torchvision 的数据集输出的图片都是 PILImage ,即取值范围是 [0, 1] ,这里需要做一个转换,变成取值范围是 [-1, 1] , 代码如下所示:

# 将图片数据从 [0,1] 归一化为 [-1, 1] 的取值范围
transform = transforms.Compose([transforms.ToTensor(),
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)

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, num_workers=2)

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

可视化部分训练图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import matplotlib.pyplot as plt
import numpy as np

# 展示图片的函数
def imshow(img):
img = img / 2 + 0.5 # 非归一化
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()


# 随机获取训练集图片
dataiter = iter(trainloader)
images, labels = dataiter.next()

# 展示图片
imshow(torchvision.utils.make_grid(images))
# 打印图片类别标签
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

构建一个神经网络:

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
28
29
30
import torch.nn as nn
import torch.nn.functional as F


class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5) # 通道变成了3
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 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()

import torch.optim as optim

criterion = nn.CrossEntropyLoss() # 定义损失和优化函数
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

训练网络:指定需要迭代的 epoch,然后输入数据,指定次数打印当前网络的信息,比如 loss 或者准确率等性能评价标准。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import time
start = time.time()
for epoch in range(2): # 训练两个epoch

running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# 获取输入数据
inputs, labels = data
# 清空梯度缓存
optimizer.zero_grad()

outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()

# 打印统计信息
running_loss += loss.item()
if i % 2000 == 1999:
# 每 2000 次迭代打印一次信息
print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))
running_loss = 0.0
print('Finished Training! Total cost time: ', time.time()-start)

测试网络性能:测试集进行测试,检验网络模型的泛化能力。对于图像分类任务来说,一般就是用准确率作为评价标准。

先用一个小的batch做测试:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
dataiter = iter(testloader)
images, labels = dataiter.next()

# 打印图片
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))

# 打印标签
# GroundTruth: cat ship ship plane

# 网络输出
outputs = net(images)

# 预测结果
_, predicted = torch.max(outputs, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

# Predicted: cat ship ship ship

# 全部测试:
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
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:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs, 1)
c = (predicted == labels).squeeze()
for i in range(4):
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上训练

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
28
29
30
31
32
33
34
35
36
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device) # cuda:0

net.to(device)
inputs, labels = inputs.to(device), labels.to(device) # 转移到GPU上训练

import time
# 在 GPU 上训练注意需要将网络和数据放到 GPU 上
net.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

start = time.time()
for epoch in range(2):

running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# 获取输入数据
inputs, labels = data
# 数据放到GPU上进行训练
inputs, labels = inputs.to(device), labels.to(device)
# 清空梯度缓存
optimizer.zero_grad()

outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()

# 打印统计信息
running_loss += loss.item()
if i % 2000 == 1999:
# 每 2000 次迭代打印一次信息
print('[%d, %5d] loss: %.3f' % (epoch + 1, i+1, running_loss / 2000))
running_loss = 0.0
print('Finished Training! Total cost time: ', time.time() - start)

DataParallel会自动分割数据集并发送任务给多个 GPUs 上的多个模型。然后等待每个模型都完成各自的工作后,它又会收集并融合结果,然后返回。


Pytorch基础复习
https://cauccliu.github.io/2024/06/23/Pytorch基础复习/
Author
Liuchang
Posted on
June 23, 2024
Licensed under