PyTorch使用说明

参考资料:
https://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html

第一部分 tensor + operator

第二部分 autograd
torch.Tnesor是包中的核心类,
.requires_grad = True,那么会自动跟踪所有运算,
.backward() 当你结束运算调用这个函数,就会自动计算梯度。
.grad 梯度会计算放到这里

.detach() 可以停止跟踪
with torch.no_grad(): 停止跟踪
上面的在评估模型的时候非常有用

Function类也是一个很重要的类别。
.grad_fn 是一个tensor被一个函数建立

随机数初始化:
在神经网络中,参数默认是进行随机初始化的,不同的初始化参数往往会导致不同的结果,当得到比较好的结果的时候,我们希望结果可以复现,在torch中,通过设置随机数种子可以达到这个目的:

1
2
3
4
5
6
7
8
9
10
11
def set_seed(seed):
torch.manual_seed(seed)
# cpu 为CPU设置种子用于生成随机数,以使得结果是确定的
torch.cuda.manual_seed(seed)
# gpu 为当前GPU设置随机种子
torch.backends.cudnn.deterministic = True
# cudnn 每次返回的卷积算法都是确定的,即默认算法
np.random.seed(seed)
# numpy
random.seed(seed)
# random and transforms

在程序的入口处设置随机数种子

1
set_seed(1)

1.当我们训练了一个模型之后,需要将训练得到的模型进行保存。

1
2
PATH = './cifar_net.pth'
torch.save(net.state_dict(),PATH)

2.测试网络

1
2
3
# 重新加载保存的模型
net = Net()
net.load_state_dict(torch.load(PATH))

保存模型的方式不同。会导致模型有可能不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 保存模型
torch.save(net,'./model.pth')
torch.save(net.state_dict(),'./model-dict.pth')

# 加载模型
net=torch.load('./model.pth')
net.load_state_dict(torch.load('./model-dict.pth'))

# 为了加载之后相同,需要指定eval模式
#保存
net=net.eval()
torch.save(net,'./model.pth')
torch.save(net.state_dict(),'./model-dict.pth')

#加载
net_load1=torch.load('./model.pth')
net_load1=net_load1.eval()

#或者
net_load2.load_state_dict(torch.load('./model-dict.pth'))
net_load2=net_load2.eval()

model.state_dict()是浅拷贝,返回的参数依然会随着网络的训练而变化,需要deepcopy或者拷贝到硬盘中。

在state_dict中有下面四个内容:
1._paramters
nn.parameter.Paramter,也就是组成Module的参数。例如一个nn.Linear通常由weight和bias参数组成。它的特点是默认requires_grad=True,也就是说训练过程中需要反向传播的
2._buffers
不需要参与反向传播的参数
3._modules
torch.nn.Module类,你定义的所有网络结构都必须继承这个类。
4._state_dict_hooks
最后一种就是在读取state_dict时希望执行的操作,一般为空,所以不做考虑。

关于NLLLoss的代码说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import torch
import torch.nn as nn
import torch.nn.functional as F

torch.manual_seed(2019)

output = torch.randn(1, 3) # 网络输出
target = torch.ones(1, dtype=torch.long).random_(3) # 真实标签
print(output)
print(target)

# 直接调用
loss = F.nll_loss(output, target)
print(loss)

# 实例化类
criterion = nn.NLLLoss()
loss = criterion(output, target)
print(loss)

计算公式:loss(input, class) = -input[class]
公式理解:input = [-0.1187, 0.2110, 0.7463],target = [1],那么 loss = -0.2110
个人理解:感觉像是把 target 转换成 one-hot 编码,然后与 input 点乘得到的结果

如果 input 维度为 M x N,那么 loss 默认取 M 个 loss 的平均值,reduction=’none’ 表示显示全部 loss

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

torch.manual_seed(2019)

output = torch.randn(2, 3) # 网路输出
target = torch.ones(2, dtype=torch.long).random_(3) # 真实标签
print(output)
print(target)

# 直接调用
loss = F.nll_loss(output, target)
print(loss)

# 实例化类
criterion = nn.NLLLoss(reduction='none')
loss = criterion(output, target)
print(loss)

"""
tensor([[-0.1187, 0.2110, 0.7463],
[-0.6136, -0.1186, 1.5565]])
tensor([2, 0])
tensor(-0.0664)
tensor([-0.7463, 0.6136])
"""

那么CrossEntropyLoss和NLLLoss区别在于
CrossEntropyLoss = Softmax+Log+NLLLoss

还有
ignore_index 就是计算的时候忽略的标签的数值

梯度计算以及backward方法

tensor在torch中是一个n维数组,我们通过指定参数requires_grad = True来建立一个反向传播图,从而可以计算梯度。被称之为动态计算图Dynamic Computation Graph。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import torch
import numpy as np

# solution 1
x = torch.randn(2,2,requires_grad=True)

# solution 2
x = torch.autograd.Variable(torch.Tensor([2,3]),requires_grad=True)

# solution 3
x = torch.tensor([2,3],requires_grad=True,dtype=torch.float64)

# solution 4
x = np.array([1,2,3],dtype=np.float64)
x = torch.from_numpy(x)
x.requires_grad = True
# or x.requires_grad(Ture)

attention:
1.只有浮点型数据才有梯度,

tensor是PyTorch中的组建,Variable是对tensor的封装,操作和tensor一样,但是每个variable都有三个属性,包含了

1
2
3
.data 数据
.grad 梯度
.grad_fn 变量的得到方式