本文以pytorch1.10进行解读:torch — PyTorch 1.10 documentation
文本的操作在github上都有Shirley-Xie/pytorch_exercise · GitHub,且有运行结果。
1. 张量的介绍
张量其实是一个多维数组,它是标量、向量、矩阵的高维拓展。基于平时常用的张量进行整理,有些操作请区分张量和numpy数组,本文的操作主要针对张量的操作。因为二者看着一样,有的方法放在numpy上会报错。
1.1 张量的属性
数据本身相关
data: 被包装的Tensor dtype: 张量的数据类型
shape: 张量的形状 device:张量所在的设备
梯度求导相关
grad: data的梯度。
grad_fn: fn表示function的意思,记录我创建张量时用到的方法,比如说加法,乘法,这个操作在求导过程需要用到,Tensor的Function, 是自动求导的关键。
requires_grad: 指示是否需要梯度, 有的不需要梯度。
is_leaf: 指示是否是叶子节点(张量)
t = torch.randint(0, 9, size=(3, 3))
print(t.data, t.device, t.dtype, t.shape,)
print(t.grad, t.requires_grad, t.grad_fn,t.is_leaf)
结果:
tensor([[0, 0, 5],
[6, 1, 0],
[7, 5, 0]]) cpu torch.int64 torch.Size([3, 3])
None False None True
1.2 张量的数据类型
张量的数据类型和numpy.array基本一一对应,但是不支持str类型。
torch.float64(torch.double), torch.float32(torch.float), torch.float16(torch.half)
torch.int64(torch.long), torch.int32(torch.int), torch.int16(torch.short), torch.int8(带符号8位整数), torch.uint8(无符号8位整数)
torch.bool
一般神经网络建模使用的都是torch.float32类型。
print('自动推断数据类型,整数64,浮点32')
i = torch.tensor(1);print(i,i.dtype)
x = torch.tensor(2.0);print(x,x.dtype)
b = torch.tensor(True);print(b,b.dtype)
print('使用特定类型构造函数,都是32')
i = torch.IntTensor(1);print(i,i.dtype)
x = torch.Tensor(np.array(2.0));print(x,x.dtype) #等价于torch.FloatTensor
b = torch.BoolTensor(np.array([1,0,2,0])); print(b,b.dtype)
print('不同类型进行转换')
i = torch.tensor(1); print(i,i.dtype)
x = i.float(); print(x,x.dtype) #调用 float方法转换成浮点类型
y = i.type(torch.float); print(y,y.dtype) #使用type函数转换成浮点类型
z = i.type_as(x);print(z,z.dtype) #使用type_as方法转换成某个Tensor相同类型
结果:
自动推断数据类型,整数64,浮点32
tensor(1) torch.int64
tensor(2.) torch.float32
tensor(True) torch.bool
使用特定类型构造函数,都是32
tensor([9], dtype=torch.int32) torch.int32
tensor(2.) torch.float32
tensor([ True, False, True, False]) torch.bool
不同类型进行转换
tensor(1) torch.int64
tensor(1.) torch.float32
tensor(1.) torch.float32
tensor(1.) torch.float32
2. 张量的创建
2.1 使用torch.tensor()的创建
data直接用张量或者python的list
1.torch.
tensor
(data, *, dtype=None, device=None, requires_grad=False, pin_memory=False)
torch.tensor([[1., -1.], [1., -1.]])
torch.tensor(np.array([[1, 2, 3], [4, 5, 6]]))
# 参数的增加
cuda0 = torch.device('cuda:0')
torch.ones([2, 4], dtype=torch.float64, device=cuda0)
可以创建requires_grad=True的张量,以便torch.argrad记录对它们的操作以进行自动微分。
x = torch.tensor([[1., -1.], [1., 1.]], requires_grad=True)
out = x.pow(2).sum()
out.backward()
x.grad
tensor和numpy更改另一个不变。
2.2 使用torch.from_numpy()的创建
通过numpy数组来创建,用numpy方法从torch.from_numpy从numpy数组得到Tensor,也可以从Tensor得到numpy数组。这两种方法关联的Tensor和numpy数组是共享数据内存的。如果改变其中一个,另外一个的值也会发生改变。
如果有需要,可以用张量的clone方法拷贝张量,中断这种关联。此外,还可以使用item方法从标量张量得到对应的Python数值。使用tolist方法从张量得到对应的Python数值列表。
print('torch.from_numpy函数从numpy数组得到Tensor')
arr = np.array([[1,2,3],[4,5,6]])
tensor = torch.from_numpy(arr)
print(arr,'\n', tensor)
print('\n 给 arr增加20,tensor也随之改变')
np.add(arr,20, out = arr)
print(arr, '\n', tensor)
print('\n tensor.numpy()从tensor到数组')
arr = tensor.numpy()
print(arr,'\n', tensor)
print('\n 给tensor增加10,arr也随之改变 ')
tensor.add_(10)
#或: torch.add(tensor,1,out = tensor)
print(arr,'\n', tensor)
print('可以用clone() 方法拷贝张量,中断这种关联')
arr = tensor.clone().numpy() # 也可以使用tensor.data.numpy()
tensor.add_(50) #给 tensor增加50,arr不再随之改变
print(arr,'\n', tensor)
# item方法和tolist方法可以将张量转换成Python数值和数值列表
scalar = torch.tensor(1.0)
s = scalar.item()
print(scalar, s, type(s))
tensor = torch.rand(2,2)
t = tensor.tolist()
print(type(t), t)
结果:
torch.from_numpy函数从numpy数组得到Tensor
[[1 2 3]
[4 5 6]]
tensor([[1, 2, 3],
[4, 5, 6]])
给 arr增加20,tensor也随之改变
[[21 22 23]
[24 25 26]]
tensor([[21, 22, 23],
[24, 25, 26]])
tensor.numpy()从tensor到数组
[[21 22 23]
[24 25 26]]
tensor([[21, 22, 23],
[24, 25, 26]])
给tensor增加10,arr也随之改变
[[31 32 33]
[34 35 36]]
tensor([[31, 32, 33],
[34, 35, 36]])
可以用clone() 方法拷贝张量,中断这种关联
[[31 32 33]
[34 35 36]]
tensor([[81, 82, 83],
[84, 85, 86]])
2.3 特殊数值创建
2.3.1 全0 、全1、全一样
全零向量torch.zeros
(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
layout这个是内存中的布局形式, 一般采用默认就可以。 这个out,表示输出张量,就是再把这个张量赋值给别的一个张量,但是这两个张量是一样的,指的同一个内存地址。看代码:
out_t = torch.tensor([1])
t = torch.zeros((3, 3), out=out_t)
print(out_t, '\n', t)
print(id(t), id(out_t), id(t) == id(out_t)) # 这个看内存地址
## 结果:
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
2575719258696 2575719258696 True
torch.zeros_like(input, dtype=None, layout=None, device=None, requires_grad=False) : 创建与input同形状的全0张量
t = torch.zeros_like(out_t) # 这里的input要是个张量
print(t)
tensor([[0, 0, 0],
[0, 0, 0],
[0, 0, 0]])
torch.ones(), torch.ones_like() 同上。
torch.
full
(size, fill_value, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
t = torch.full((3,3), 10)
结果:
tensor([[10., 10., 10.],
[10., 10., 10.],
[10., 10., 10.]])
同理:torch.full_like()
2.3.2 均分操作
torch.
arange
(start=0, end, step=1, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
默认等差为1维张量,数值区间[start, end), 注意这是右边开,取不到最后的那个数。
t = torch.arange(2, 10, 6) # tensor([2, 8])
torch.linspace():均分的1维张量, 数值区间[start, end] 注意这里都是闭区间,steps是个数,和上面的区分。
t = torch.linspace(2, 10, 5) # tensor([2, 4, 6, 8, 10])
# 那么如果不是那么正好呢? 步长应该是多少?
t = torch.linspace(2, 10, 6) # tensor([2, 3.6, 5.2, 6.8, 8.4, 10])
# 这个步长是怎么算的? (end-start) / (steps-1)
torch.
logspace
(start, end, steps, base=10.0, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
创建对数均分数列,这里的base表示以什么为底。
torch.logspace(start=-10, end=10, steps=5)
tensor([ 1.0000e-10, 1.0000e-05, 1.0000e+00, 1.0000e+05, 1.0000e+10])
2.3.3 创建单位对角矩阵
torch.
eye
(n, m=None, *, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False)
n, m分别是矩阵的行数和列数。
torch.eye(3)
tensor([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
2.4 依概率分布创建张量
2.4.1 正态分布(高斯分布)
torch.
normal
(mean, std, *, generator=None, out=None), 这个使用的比较多
- mean为标量, std为标量,只有这个是同分布
- mean为标量, std为张量
- mean为张量, std为标量
- mean为张量,std为张量,对应的值
# 第一种模式 - 均值是标量, 方差是标量 - 此时产生的是一个分布, 从这一个分部种抽样相应的个数,所以这个必须指定size,也就是抽取多少个数
t_normal = torch.normal(0, 1, size=(4,))
# 第二种模式 - 均值是标量, 方差是张量 - 此时会根据方差的形状大小,产生同样多个分布,每一个分布的均值都是那个标量
std = torch.arange(1, 5, dtype=torch.float)
t_normal2 = torch.normal(1, std)
# 也产生来四个数,但是这四个数分别来自四个不同的正态分布,这些分布均值相等
# 第三种模式 - 均值是张量,方差是标量 - 此时也会根据均值的形状大小,产生同样多个方差相同的分布,从这几个分布中分别取一个值作为结果
mean = torch.arange(1, 5, dtype=torch.float)
t_normal3 = torch.normal(mean, 1)
print(t_normal3) # 来自不同的分布,但分布里面方差相等
# 第四种模式 - 均值是张量, 方差是张量 - 此时需要均值的个数和方差的个数一样多,分别产生这么多个正太分布,从这里面抽取一个值
mean = torch.arange(1, 5, dtype=torch.float)
std = torch.arange(1, 5, dtype=torch.float)
t_normal4 = torch.normal(mean, std)
# 来自不同的分布,各自有自己的均值和方差
结果:
tensor([-0.2064, 0.6686, 1.9040, 4.9825])
tensor([0.4730, 0.8979, 2.5438, 4.4194])
标准正态分布 torch.randn(), torch.randn_like()
t= torch.randn(2,3)
print(t, ' \n ',torch.randn_like(t))
结果:
tensor([[-0.0701, -0.4255, -0.2008],
[-0.5426, -0.0658, 0.0465]])
tensor([[-2.2730, 1.3279, 0.4503],
[ 1.0447, 0.4552, 0.7559]])
2.4.2 生成均匀分布
torch.rand(), rand_like() 在[0,1)生成均匀分布
torch.randint(), torch.randint_like(): 区间[low,hight)生成整数均匀分布
torch.rand(1,5),torch.randint(0,10,(1,5))
2.4.3 伯努利分布
torch.bernoulli(input): 以input为概率,生成伯努利分布(0-1分布,两点分布), input: 概率值
torch.bernoulli(torch.arange(1,10),0.8)
# tensor([1, 1, 0, 0, 0, 1, 0, 1, 1])
2.4.4 乱序索引
torch.randperm(n): 生成从0 - n-1的随机排列, n是张量的长度, 经常用来生成一个乱序索引。
torch.randperm(6)
# tensor([5, 1, 4, 3, 2, 0])
参考:
torch — PyTorch 1.10 documentation
系统学习Pytorch笔记一:Pytorch的数据载体张量与线性回归_翻滚的小@强的博客-CSDN博客
GitHub - lyhue1991/eat_pytorch_in_20_days: Pytorch🍊🍉 is delicious, just eat it! 😋😋