pytorch初学者的函数收集手册。(二)

这些内容某些部分直接复制了其他博主的代码,一般我会留下转载的链接,初心只是为了自己能够方便的查找项目过程中的感悟。如果侵权了请直接联系我,会及时删除。


1.torch的register_hook()register_forward_hook()register_backawrd_hook()

参考链接:@Foneone

  • 首先hook分为3种:
  1. register_hook(hook):为Tensor注册一个backward hook,用来获取变量的梯度;hook必须遵循如下的格式:hook(grad) -> Tensor or None
  2. register_forward_hook(hook):对应于前向传播的梯度获取
  3. register_backward_hook(hook):对应与反向传播。

先看register_hook():

import torch
from torch.autograd import Variable

def print_grad(grad):
    print('grad is \n', grad)

x = Variable(torch.randn(2, 1), requires_grad = True)
## x = torch.rand(2, 1, requires_grad = True)#等效
print('x value is \n', x)
y = x + 3
print('y value is '\n'', y)
z = torch.mean(torch.pow(y, 1 / 2))
lr = 1e-3

y.register_hook(print_grad)
z.backward()
x.data -= lr * x.grad.data
print('new x is \n', x)
output:
x value is 
 tensor([[ 2.5474],
        [-1.1597]], requires_grad=True)
y value is 
 tensor([[5.5474],
        [1.8403]], grad_fn=<AddBackward0>)
grad is 
 tensor([[0.1061],
        [0.1843]])
new x is
 tensor([[ 2.5473],
        [-1.1599]], requires_grad=True)

 

解释:对于z来说,求梯度最终求解的是对x的梯度(导数,偏导),因此y是一个中间变量。因此可以用register_hook()来获取其作为中间值的导数,否则z对于y的偏导是获取不到的。

因此尝试不使用register_hook()获取梯度:

#y.register_hook(print_grad) 
 
z.backward() # 梯度求解
print('y\'s grad is ',y.grad)
print('x\'s grad is \n',x.grad)
x.data -= lr*x.grad.data
print('new x is\n',x)
 
output:
y's grad is  None
x's grad is 
 tensor([[0.1544],
        [0.1099]])
new x is
 tensor([[-0.3801],
        [ 2.1755]], requires_grad=True)

 然后看register_forward_hook():

条件:执行过模型内置的forward.

格式:如下

hook(module, input, output) -> None or modified output

hook可以修改input和output,但是不会影响forward的结果。最常用的场景是需要提取模型的某一层(不是最后一层)的输出特征,但又不希望修改其原有的模型定义文件,这时就可以利用forward_hook函数。

import torch
import torch.nn as nn
import torch.nn.functional as F
 
class LeNet(nn.Module):
    def __init__(self):
        super(LeNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        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):
        out = F.relu(self.conv1(x))     #1 
        out = F.max_pool2d(out, 2)      #2
        out = F.relu(self.conv2(out))   #3
        out = F.max_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = F.relu(self.fc1(out))
        out = F.relu(self.fc2(out))
        out = self.fc3(out)
        return out
 
features = []
def hook(module, input, output): 
    # module: model.conv2 
    # input :in forward function  [#2]
    # output:is  [#3 self.conv2(out)]
    features.append(output.clone().detach())
    # output is saved  in a list 
 
 
net = LeNet() ## 模型实例化 
x = torch.randn(2, 3, 32, 32) ## input 
handle = net.conv2.register_forward_hook(hook) ## 获取整个Lenet模型 conv2的中间结果
y = net(x)  ## 获取的是 关于 input x 的 conv2 结果 
 
print(features[0].size()) # 即 [#3 self.conv2(out)]
handle.remove() ## hook删除 

注意:使用完成后,最好用handle.remove()

再看register_backward_hook(hook)

使用情况是在反响传播之后。


2.torch.utils.data.Dataset

  •  首先请看官网的解释:

  • 细节讲解

链接:dataset 


3.torch的tensor与numpy的转换

  • tensor to numpy
a = torch.ones(1,2)
print(a.numpy())

#输出
#[1 , 1]
  • numpy to tensor 
import numpy as np
a = np.ones(1,2)
p = torch.from_numpy(a)

#输出
#tensor

 


4. 关于提取cnn冻结层的特征时tensor和array转换的理解

源代码如下(《oytorch与深度学习》p90)

def preconvfeat(dataset,model):#计算预卷积
	conv_features = []
	labels_list = []
	for data in dataset:#一批一批的计算
		inputs,labels = data
		if is_cuda:
			inputs , labels = inputs.cuda(),labels.cuda()
		inputs , labels = Variable(inputs),Variable(labels)
		output = model(inputs)
		conv_features.extend(output.detach().cpu().numpy())#将conv_features转换成numpy
		labels_list.extend(labels.data.cpu().numpy())
	conv_features = np.concatenate([[feat] for feat in conv_features])#numpy的list整合命令
	return (conv_features,labels_list)
  • 首先介绍list的extend函数:

链接:link

在列表追加另一个序列的所有元素。(注意是逐个添加)

注意:extend只适用于一维数组,如果有一个二维的array它会把每一行当成一个元素extend进list。

>>> x1
array([[1, 2],
       [2, 2]])
>>> x2
array([[1, 2],
       [2, 2]])
>>> t = []
>>> t.extend(x1)
>>> t
[array([1, 2]), array([2, 2])]
  • 然后来介绍numpy的concatenate()函数

链接:官网 

在理解上面的代码中

conv_features = np.concatenate([[feat] for feat in conv_features])

这句话的时候,我完全不明白为什么要给每一个[feat]组成的序列之外再添加一个“[ ]”?

最后我看官方的书写格式: numpy.concatenate((a, b)),我发现这是将最外层的[]当作了(a,b)中的(),测试了后发现将()换成[]是不报错的。

>>> a
array([[[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]]])
>>> b
array([[[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]]])
>>> numpy.concatenate([a,b])
array([[[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]],

       [[1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.],
        [1., 1., 1., 1.]]])

所以代码中的那句话是把所有的图像顺序存储在array中,将list转换array的numpy格式,这样就懂了


5.pytorch中tensor,list相互转换

参考链接:Python中 list, numpy.array, torch.Tensor 格式相互转化 


6.pytorch中的momentum动量的讲解

链接:momentum的讲解 


7.辨析:requre_grad,detach(),torch.nograd()

 link

     8.怎么更改vgg中的输出层的数目

#微调模型输出
num_input = vgg.classifier[6].in_features
feature_model = list(vgg.classifier.children())
feature_model.pop()
feature_model.append(nn.Linear(num_input, 10))
vgg.classifier = nn.Sequential(*feature_model)

要去除最后一层,然后append一个新的一层就好了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值