疑问
- 官方说pytorch的高级功能:GPU加速的张量计算;自动求导系统(反向求导技术)。其实是相对于普通CPU网络说的,对于深度网络来说,这些东西可以忽略。
- pytorch是动态图,可以任意改变网络的行为,而且速度快。动态图和静态图有什么区别还是不清楚。
补充:1. 在预测的阶段,把output = output[:, -1, :].squeeze(dim=1)
改为了output = output[:, -1, :].squeeze()
,结果完全一致。 - 在autograd一节中,介绍了标量函数的求导方式,但是对于向量形式的求导,目前还不清楚如何设置求导参数如何设置。
记录
1. 什么是PyTorch
- torch是和Numpy类似的科学计算包,但是因为是小众语言Lua写的,所以不太流行。Pytorch是在torch基础上做的工作,然后最上层使用python封装了,所以叫pytroch。因此,pytorch可以作为numpy的替代品,而且支持GPU加速。同时,它也支持深度学习。当然,我们更重视后者。
- pytorch最核心的是autograd包,它为张量的所有操作提供了自动求导机制。
- Module里面定义的是各种layers,都包含可学习的参数;forword()函数定义的是整个网络完整的结构。
2. features相关
- 0.4版本之前Tensor是包装在Variable里面进行,
pytroch api
torch
- 创建tensor
- tensor的dtype
torch.randn(shape) 产生一个shape形状的tensor,其中的值是正太分布。
pytorch 60min入门
1. pytorch入门
创建tensor
import torch
torch.empty(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False, pin_memory=False)
torch.rand(5, 3)
x = torch.zeros(5, 3, dtype=torch.long)
x = torch.randn(*size) # randn指的是随机产生正态分布的数据,均值为0,方差为1
x = torch.tensor([5.5, 3]) # 会根据入参自动推断,如果是[1,2]则,dtype是torch.int64;正常dtype是torch.float32
x = x.new_ones(5, 3, dtype=torch.double)
x = torch.randn_like(x, dtype=torch.float)
里面的requires_grad
参数默认都是False,在网络中,只有parameters是需要grad的。
tensor.tensor(input)会根据input的数据类型,来判断输出的类型;tensor.Tensor()其实是tensor.FloatTensor(),底层调用的是tensor.tensor()
tensor自带方法
x = torch.tensor([1,2])
x.size() # 返回torch.Size([2])
x.numpy() # 获取numpy,底层numpy和tensor共享数据
## 可以自带一些操作
x.squeeze()
x.view()
x.mm(y) # 矩阵的乘法
operations
同一个操作有很多种方式。
- torch.add(x, y)
- x.add_(y) # 把y加到x上面
- x.view() # 相当于tf的reshape,不过第一个参数还是*args 可变参数
pytorch接口
可以看出torch和numpy的接口基本一致,而且两者共享底部数据
import numpy as np
a = np.ones(5)
b = torch.from_numpy(a)
np.add(a, 1, out=a)
print(a)
print(b)
- torch.max(input, dim, keepdim=False, out=None) -> (Tensor, LongTensor) # 获取最大值
- torch.argmax()
- torch.clamp(input, min, max, out=None) 将input向量夹紧到[min, max]中
>>> x = torch.zeros(2, 1, 2, 1, 2)
>>> x.size()
torch.Size([2, 1, 2, 1, 2])
>>> y = torch.squeeze(x)
>>> y.size()
torch.Size([2, 2, 2])
>>> y = torch.squeeze(x, 0)
>>> y.size()
torch.Size([2, 1, 2, 1, 2])
>>> y = torch.squeeze(x, 1)
>>> y.size()
torch.Size([2, 2, 1, 2])
cuda tensor
不知道不同device上的数据相加,是如何处理的
if torch.cuda.is_available():
device = torch.device("cuda") # a CUDA device object,不进行编译,有没有cuda也可以执行,但是tensor.to(device)会失败
y = torch.ones_like(x, device=device) # directly create a tensor on GPU
x = x.to(device) # or just use strings ``.to("cuda")``
z = x + y
print(z)
print(z.to("cpu", torch.double))
输出如下:
tensor([0.5480], device='cuda:0')
tensor([0.5480], dtype=torch.float64)
2. AUTOGRAD
构建可求导tensor
torch.tensor(requires_grad=True)
创建了tensor,之后所有的operation产生的tensor,都会自带一个Function。
对tensor求grad,只需要调用out.backword(grad_variables)
就可以了,但是grad_variables参数非常古怪,现在也不知道设置多少才合适?
detach求grad
两种方案:
- with torch.no_grad():
- x.detach()
- requires_grad_(False)
3. NEURAL NETWORKS
如何训练一个神经网络,下面的流程可以说是很清晰了:
- Define the neural network that has some learnable parameters (or weights)
第一种方式就是定义一个类,继承nn.Module;另一种就是直接使用nn.Sequential()。直观感受,第一种方式定制化能力更强一些。
第一种方式:
class Net(nn.Module):
def __init__(self):
# define layers
def forword(input):
# define network
第二种方式:
model = nn.Sequential(
nn.Linear(D_in, H),
nn.ReLU(),
nn.Linear(H, D_out),
)
- Iterate over a dataset of inputs
- Process input through the network
net = Net()
output = net(input)
- Compute the loss (how far is the output from being correct)
所有的loss也都存放在了torch.nn包里面,接收一个(output, target)pair,产生一个loss tensor
criterion = nn.MSELoss()
loss = criterion(output, target)
- Propagate gradients back into the network’s parameters
loss.backward()
- Update the weights of the network, typically using a simple update rule: weight = weight - learning_rate * gradient
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.zero_grad() # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step() # Does the update
tips
- nn.Module. 神经网络模型,直接作为定义神经网络的父类。
- torch.optim 这个包包含了所有的optim函数
- net.parameters() 返回的是Parameter对象,如果想获取值,需要使用list(Parameters)
4. TRAINING A CLASSIFIER
前面定义网络,定义loss和optim的阶段省略了,只记录下面计算loss和更新参数的部分:
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
其中loss和optim的定义如下:
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
可以看出,loss不依赖参数;optim是参数以来的,它的目的是更新所有的parameter。
save model & load model
torch.save(net.state_dict(), PATH)
state_dict 是一个python的字典格式,以字典的格式存储,然后以字典的格式被加载,而且只加载key匹配的项
net = Net()
net.load_state_dict(torch.load(PATH))
我们在加载的时候,可以只加载我们需要的层,不需要的层不加载。
https://www.jianshu.com/p/6287a2c85e57
predict
在进行predict的时候,需要把predict的代码放到with torch.no_grad():
里面
training on GPU
不知道为什么,默认不是GPU,需要把两类数据送到目标device中:
- Net的parameters
- 数据集的data
优化器的基类
class torch.optim.Optimizer(params, defaults)
包含的方法:
1、load_state_dict(state_dict)
optimizer的状态。是一个调用state_dict()所返回的对象。和state_dict()配合使用,先保存吗, 再加载。
2、state_dict()
以dict返回optimizer的状态。和model的state_dict相似,一般在保存模型参数的时候可以把优化器的参数一起保存。
3、step(closure)
单步优化
4、zero_grad()
清空所有被优化过的Variable的梯度. 在写的时候也可以用model.zero_grad()
极好的例子
https://www.jianshu.com/p/d8926a2b9e76
optimizer.zero_grad() # 来清空model参数的grad
loss.backward() # 进行反向传播
optimizer.step() # 进行梯度更新
torch.nn与torch.nn.functional之间的区别和联系
所有需要参数的实现都是nn.Module(),torch.nn.Module的底层实现也是nn.functioncal。
有些nn的实现需要参数,比如 nn.functioncal的入参需要传入这些模型参数,让用户去定义会比较麻烦,所以构建了torch.nn.Module,在init里面构建了这些参数,就不用用户自己定义了。
同时有保留了nn.functional的接口,保留这种灵活性。
但是不需要参数的layer就可以直接使用nn.functional()
【但是也有例外,比如nn.Softmax() 这个明明没有参数,但是还是构建了Module】
1. Numpy
https://blog.csdn.net/u012300744/article/details/80423135
点乘:
- m * n
- np.multiply(m, n)
矩阵乘法:
- np.matmul(b, a)
- np.dot(a,a)
- a.dot(a)
pytorch和tensorflow的区别
个人感觉,pytorch比tensorflow好用多了,优势如下:
- 包的定义非常清晰
- 动态图的方式,非常适合调试
- nn.Module 的定义非常好,相当于一个小的规范,模型定义更清晰
- 动态图编辑