pytorch系列1——张量数据结构

本文以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=Nonedevice=Nonerequires_grad=Falsepin_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(*sizeout=Nonedtype=Nonelayout=torch.strideddevice=Nonerequires_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(sizefill_value*out=Nonedtype=Nonelayout=torch.strideddevice=Nonerequires_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=0endstep=1*out=Nonedtype=Nonelayout=torch.strideddevice=Nonerequires_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(startendstepsbase=10.0*out=Nonedtype=Nonelayout=torch.strideddevice=Nonerequires_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(nm=None*out=Nonedtype=Nonelayout=torch.strideddevice=Nonerequires_grad=False)

n, m分别是矩阵的行数和列数。

torch.eye(3)
tensor([[ 1.,  0.,  0.],
        [ 0.,  1.,  0.],
        [ 0.,  0.,  1.]])

2.4 依概率分布创建张量

2.4.1 正态分布(高斯分布)

torch.normal(meanstd*generator=Noneout=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! 😋😋

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值