改变维度
a=torch.arange(0,6)
#[[0, 1, 2], [3, 4, 5]]
a=a.view(2,3)
#a=[[0, 1, 2], [3, 4, 5]]
#在第1维增加维度 下表从0开始
print(a.unsqueeze(0))
#在第2维增加维度
print(a.unsqueeze(1))
#在第3维增加维度
print(a.unsqueeze(2))
c=a.unsqueeze(0)
print(c)
print(c.squeeze(0))
#可以看出维度并没有变化,仍然为(1,2,3),这是因为只有维度为1时才会去掉
print(c.squeeze(1))
print(c.squeeze(2))
作用是创建以参数probs为标准的类别分布,样本是来自 “0 … K-1” 的整数,其中 K 是probs参数的长度。也就是说,按照传入的probs中给定的概率,在相应的位置处进行取样,取样返回的是该位置的整数索引。
m=Categorical(probs)
action=m.sample()
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)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)
三、为什么要区分叶张量和非叶张量?
从以下几个方面来讲:
1.从链式求导法则来讲:
对于一个可导函数,无论其多么复杂,一定可由若干可导函数的四则运算组成,那么在这个环节中任何一个运算都是可导的,最终得到函数的计算是需要这些环节的导数的传递。不知道讲清楚没有,,,例如:对上面的x1求导,那么自上而下要经过t_1,y,t_1和y的requires_grad()为True,否则梯度无法求解。
2.从求导的目的来讲
在深度学习或者机器学子中,求导或求梯度的根本原因是,对梯度进行反向传播,进而来更新相应的参数来达到学习的目的,在这个例子中可以看出y,t_1是前向传播计算得到的中间值,它们虽然需要求导但是不需要更新参数。
3.从实际需要出发
那些需要更新参数的变量,设置为叶张量,在计算梯度的时候,会保留它们的梯度信息,供反向传播更新参数的时候使用;那些不需要更新参数的中间变量,任然会计算与之相关联的梯度,但是程序不会保留该变量对应的梯度信息;这样有利于节约计算机的资源。