pytorch

view

改变维度

a=torch.arange(0,6)
#[[0, 1, 2], [3, 4, 5]]
a=a.view(2,3)

unsqueeze

#a=[[0, 1, 2], [3, 4, 5]]
#在第1维增加维度 下表从0开始
print(a.unsqueeze(0))
#在第2维增加维度
print(a.unsqueeze(1))
#在第3维增加维度
print(a.unsqueeze(2))

pytorch_第1张图片

squeeze

c=a.unsqueeze(0)
print(c)
print(c.squeeze(0))
#可以看出维度并没有变化,仍然为(1,2,3),这是因为只有维度为1时才会去掉
print(c.squeeze(1))
print(c.squeeze(2))

pytorch_第2张图片

Categorical

作用是创建以参数probs为标准的类别分布,样本是来自 “0 … K-1” 的整数,其中 K 是probs参数的长度。也就是说,按照传入的probs中给定的概率,在相应的位置处进行取样,取样返回的是该位置的整数索引。

m=Categorical(probs)
action=m.sample()

requires_grad

import torch
x = torch.tensor(3.) # 数字
w = torch.tensor(4., requires_grad=True) # 数字
b = torch.tensor(5., requires_grad=True) # 数字
y = w * x + b
y.backward()
#相当于函数变为 y = 3 * w + b
 
#求梯度:
# Display gradients
print('dy/dx:', x.grad) #dy/dx: None
print('dy/dw:', w.grad)#dy/dw: tensor(3.)
print('dy/db:', b.grad)#dy/db: tensor(1.)

解释:对于y = x * w + b,因为x为常数3, 对y = 3 * w + b,y对x求偏导数dy/dx=0, y对w求偏导数dy/dw = 3, y对b求偏导dy/db=1.

import torch
x=torch.tensor([1,2],dtype=torch.float32,requires_grad=True)
a=torch.tensor([3,4],dtype=torch.float32,requires_grad=True)
y=x*2+a
y.requires_grad_(True)
z=torch.mean(y)

z.backward()

print(x.grad, x.requires_grad)
print(a.grad, a.requires_grad)
print(y.grad, y.requires_grad)
print(z.grad, z.requires_grad)

这段会报一个警告:

UserWarning: The .grad attribute of a Tensor that is not a leaf Tensor is being accessed. Its .grad attribute won’t be populated during autograd.backward(). If you indeed want the .grad field to be populated for a non-leaf Tensor, use .retain_grad() on the non-leaf Tensor. If you access the non-leaf Tensor by mistake, make sure you access the leaf Tensor instead. See github.com/pytorch/pytorch/pull/30531 for more informations.(Triggered internally at C:\cb\pytorch_1000000000000\work\build\aten\src\ATen/core/TensorBody.h:485.) print(y.grad, y.requires_grad)

这个报错的大致翻译如下:
< input > : 1:UserWarning:正在访问非叶张量的张量的.grad属性。在autograd.backward()期间不会填充其.grad属性。如果确实需要非叶张量的梯度,请在非叶张量上使用.retain_grad()。如果您错误地访问了非叶张量,请确保您访问了叶张量。
一句话总结是:
并不是 requires_grad()为True就可以输出对应的梯度,还要看is_leaf属性,当is_leaf=false时,也即该变量是非叶张量,则会爆出上面的错误

  1. requires_grad=True 的作用是让 backward 可以追踪这个参数并且计算它的梯度。最开始定义你的输入是requires_grad=True ,那么后续对应的输出也自动具有 requires_grad=True ,如代码中的 y 和 z ,而与 z 对 x 求导无关联的 a ,其 requires_grad 仍等于 False。
  2. 如果在 z 对 x 求导的过程中需要用到 z 对 y 求导,而如果设置 y.requires_grad=False,则会报错。就是因为只有 requires_grad=True的参数才会参与求导,而在求导路径的中间设置相关参数不可求导,那么它就会报错。
  3. 那么如何取得参数的 grad :①如果你想取的参数是由 torch.tensor(requires_grad=True)定义的,可以直接取它的 grad ;②如果你的参数是如 y 和 z 这样计算出来的,那么根据编译器警告,需要定义 y.retain_grad() 就可以取得 y 的 grad;③还有一个方法是使用钩子可以保存计算的中间梯度,在上面文章中可见。由此可知梯度的计算会在计算完成后遗弃,并且requires_grad=False 的参数不计算它的梯度,如此可以减少内存使用和降低计算量。
  4. 当你在使用 Pytorch 的 nn.Module 建立网络时,其内部的参数都自动的设置为了 requires_grad=True ,故可以直接取梯度。而我们使用反向传播时,其实根据全连接层的偏导数计算公式,可知链式求导和 w , b的梯度无关,而与其中一个连接层的输出梯度有关,这也是为什么冻结了网络的参数,还是可以输出对输入求导。

detach()

(1)detach()与detach_()

在x->y->z传播中,如果我们对y进行detach(),梯度还是能正常传播的;

但如果我们对y进行detach_(),就把x->y->z切成两部分:x和y->z,x则无法接受到后面传过来的梯度。

(2)detach()和data

1)共同点:

x.data和x.detach()返回和x的相同数据 tensor,这个新的tensor和原来的tensor(即x)是共用数据的,一者改变,另一者也会跟着改变,但是x.data和x.detach() 的 require s_grad = False,即是不可求导的。

2)不同点:

①x.data 不能被 autograd 追踪求微分,即使被改了也能错误求导;而x.detach()也不能被 autograd 追踪求微分,被改了会直接报错,避免错误的产生。

②.data 是一个属性,detach()是一个方法;

③.data 是不安全的, .detach()是安全的。

具体看这 很详细

叶张量和非叶张量

首先根据张量的属性判断,当张量的is_leaf为true时,该变量为叶张量

那么is_leaf是如何产生的:

由用户初始创建的变量,而不是程序中间产生的结果变量,那么该变量为叶变量。

 x1 = torch.ones(2, 2) * 2
 x1.requires_grad=True
 print('x1是否是叶张量:', x1.is_leaf)
 x2 = torch.ones(2, 2) * 3
 x2.requires_grad = True
 print('x2是否是叶张量:', x2.is_leaf)

 x3 = torch.ones(2, 2) * 4
 x3.requires_grad = True
 y = x1 * x3 + x2
 t_1 = y.sum()
 print('y是否是叶张量:', y.is_leaf)
 print('t_1是否是叶张量:', t_1.is_leaf)

pytorch_第3张图片

三、为什么要区分叶张量和非叶张量?
从以下几个方面来讲:

1.从链式求导法则来讲:

对于一个可导函数,无论其多么复杂,一定可由若干可导函数的四则运算组成,那么在这个环节中任何一个运算都是可导的,最终得到函数的计算是需要这些环节的导数的传递。不知道讲清楚没有,,,例如:对上面的x1求导,那么自上而下要经过t_1,y,t_1和y的requires_grad()为True,否则梯度无法求解。

2.从求导的目的来讲

在深度学习或者机器学子中,求导或求梯度的根本原因是,对梯度进行反向传播,进而来更新相应的参数来达到学习的目的,在这个例子中可以看出y,t_1是前向传播计算得到的中间值,它们虽然需要求导但是不需要更新参数。

3.从实际需要出发

那些需要更新参数的变量,设置为叶张量,在计算梯度的时候,会保留它们的梯度信息,供反向传播更新参数的时候使用;那些不需要更新参数的中间变量,任然会计算与之相关联的梯度,但是程序不会保留该变量对应的梯度信息;这样有利于节约计算机的资源。

你可能感兴趣的:(AI学习,python,神经网络,pytorch)