zip
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表
a = [1,2,3]
b = [4,5,6]
c = [4,5,6,7,8]
zipped = zip(a,b) # 打包为元组的列表
输出 [(1, 4), (2, 5), (3, 6)]
zip(a,c) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
zip(*zipped) # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]
python3以后,要想输出zip之后的具体内容,需要用list,如
from collections import OrderedDict
outputs = ['weight1', 'weight2','weight3']
train_outputs = OrderedDict([('layer1', []), ('layer2', []), ('layer3', [])])
print(list(zip(train_outputs.keys(), outputs)))
>>>[('layer1', 'weight1'), ('layer2', 'weight2'), ('layer3', 'weight3')]
加载别人预训练好的模型
例如加载wide_resnet50:
import torch
wide_resnet50_2 = torch.hub.load('pytorch/vision:v0.9.0', 'wide_resnet50_2', pretrained=True)
注意:加载模型这句话要跟在import torch之后,不然后面如果有import torchvision的话,可能就是从torchvision里面加载的,就找不到这个模型了
另一种trans的方式
trans = T.Compose([T.Resize(resize, Image.ANTIALIAS)])
这里这个Image.ANTIALIAS可以减少图片resize之后的噪声(有些图片resize之后会出现噪声)相当于一个滤镜的操作
查看pytorch的版本
import torch
print(torch.__version__)
hook函数
由于pytorch会自动舍弃计算图的中间梯度,所以用hook函数可以访问中间的特征或者是梯度
钩子函数包括Variable的钩子或者是nn.Module的钩子
钩子函数的使用场景有:
1 torch.autograd.Variable.register_hook
2 torch.nn.Module.register_backward_hook
3 torch.nn.Module.register_forward_hook
第一个是register_hook,是针对Variable对象的,
后面的两个:register_backward_hook和register_forward_hook是针对nn.Module这个对象的
hook的价值:
一个简单的例子:
计算如下的z的最小值:
x
∈
R
2
,
y
=
2
x
+
2
,
z
=
y
2
x\in R^2, y=2x+2,z=y^2
x∈R2,y=2x+2,z=y2
则很简单根据二次函数性质,可以求出当
x
=
−
1
x=-1
x=−1时,
z
z
z取得最小值
代码如下:
import torch
from torch.autograd import Variable
x = Variable(torch.randn(1), requires_grad=True)
optimizer = torch.optim.Adam([x], lr=0.01)
#注意1:params argument given to the optimizer should be an iterable of Tensors or dicts, but got torch.FloatTensor
#平时optimizer的参数给的是model.parameters,
for i in range(1000):
y = 2*x+2
z = torch.pow(y, 2)
optimizer.zero_grad()
z.backward()
optimizer.step()
print(x.data)
执行1000个epoch之后x的输出为-1.
但是没法求中间y的变量,
print(y.grad)
报错:'NoneType' object is not callable
因为pytorch的机制是:对于中间变量,一旦它们完成了自身反传的使命,计算图就会被释放掉。
这个时候就可以用hook来把想求的中间变量的梯度“钩”起来,需要注意的是register_hook函数接收的是一个函数
import torch
from torch.autograd import Variable
x = Variable(torch.randn(1), requires_grad=True)
optimizer = torch.optim.Adam([x], lr=0.01)
grad_list = []
def print_grad(grad):
grad_list.append(grad)
for i in range(1000):
y = 2*x+2
z = torch.pow(y, 2)
y.register_hook(print_grad)
print(x.grad)
optimizer.zero_grad()
z.backward()
optimizer.step()
#x.data -= lr*x.grad.data
print(x.data)
print(grad_list)
展示一下前几个x和y的输出:
z对x的梯度:
tensor([19.6492])
tensor([19.5692])
tensor([19.4892])
tensor([19.4093])
z对y的梯度:
[tensor([9.8246]), tensor([9.7846]), tensor([9.7446]), tensor([9.7046])
可以看出对x的梯度是对y的梯度的2倍,原因也很简单,根据微积分中的链式求导法则:
d
z
/
d
x
=
(
d
z
/
d
y
)
∗
(
d
y
/
d
x
)
,
d
y
/
d
x
=
2
,
所
以
d
z
/
d
x
=
2
∗
(
d
z
/
d
y
)
dz/dx=(dz/dy)*(dy/dx),dy/dx=2,所以dz/dx=2*(dz/dy)
dz/dx=(dz/dy)∗(dy/dx),dy/dx=2,所以dz/dx=2∗(dz/dy)
利用hook还可以修改梯度