Pytorch学习(2)- tensor

Tensor:张量,可以是标量(一个数)、向量(一维数组)、矩阵(二维数组)或者更高维的数组。

它与numpy和ndarrays相似,但是PyTorch的tensor支持GPU加速。

一、tensor分类

  • 从接口的角度分类

        

torch.function如torch.save()
tensor.function如tensor.view()
  • 从存储的角度分类
不会修改自身的数据如a.add(b),加法的结果会返回一个新的tensor
会修改自身的数据如a.add_(b),加法的结果仍然存储在a中,a被修改了

二、创建Tensor

在PyTorch中新建tensor的方法有很多,具体如下:

函数功能
Tensor(*sizes)基础构造函数
ones(*sizes)全1Tensor
zeros(*sizes)全0Tensor
eye(*sizes)对角线为1,其他为0
arange(s,e,step)从s到e,步长为step
linspace(s,e,steps)从s到e,均匀切分成steps份
rand/randn(*sizes)均匀/标准分布
normal(mean,std)/uniform(from,to)正态分布/均匀分布
randperm(m)随机排列

三、常用Tensor操作

       通过tensor.view方法调整tensor的形状,但必须保证调整前后元素总数一致。view不会修改自身的数据,

返回的新tensor与源tensor共享内存,即更改其中一个,另一个也随之改变。

主要用在经常需要添加或者减少某一维度,这时就需要squeeze和unsqueeze这两个函数。

       resize是另一种可以用来调整size的方法,但与view不同,它可以修改tensor的尺寸。如果新尺寸超过了原尺寸,会自动分配新的内存空间,但如果新尺寸小于原尺寸,则之前的数据依旧会被保存。

      Tensor支持numpy.ndarray类似的索引操作,语法也类似。如无特殊说明,索引出来的结果与原tensor共享内存。

from __future__ import print_function
import torch as t

a = t.randn(3, 4)
print(a)
print(a[0])  # 第0行(下标从0开始)
print(a[:, 0])  # 第0列

结果如下:

四、常用的选择函数

函数功能
index_select(input,dim,index)在指定维度dim上选取,例如选取某些行或列
masked_select(input,mask)例a[a>0],使用ByteTensor进行选取
non_zero(input)非0元素的下标
gather(input,dim,index)根据index,在dim维度上选取数据,输出的size与index一样

五、常见的逐元素操作

函数功能
abs//sqrt/div/exp/fmod/log/pow绝对值/平方根/除法/指数/求余/求幂
cos/sin/asin/atan2/cosh三角函数
clamp(input,min,max)超过min和max部分截断
ceil/round/floor/trunc上取整/四舍五入/下取整/只保留整数部分
sigmod/tanh激活函数

     clamp常用在某些需要比较大小的地方,如取一个tensor的每个元素与另一个数的较大值。

a = t.arange(0, 6).view(2, 3)
print(a)
# 不转换为float,则会报错:RuntimeError: cos_vml_cpu not implemented for 'Long'
print(t.cos(a.float()))

      

a = t.arange(0, 6).view(2, 3)
print(a)
print(a % 3)  # 等价于t.fmod(a, 3)
print(a ** 2)  # 等价于t.pow(a, 2)

       

a = t.arange(0, 6).view(2, 3)
print(a)
# a中每个元素都与3相比,取较大的一个
print(t.clamp(a, min=3))

     

 

六、归并操作

       归并操作会是输出形状小于输入形状,并可以沿着某一维度进行指定操作。

常用的归并操作:

函数功能
mean/sum/median/mode均值/和/中位数/众数
norm/dist范数/距离
std/var标准差/方差
cumsum/cumprod累加/累乘

以上大多数函数都有一个参数dim,用来指定这些操作是在哪个维度上执行的。

假设输入的形状是(m, n, k)——m行n列

输入dim输出的形状
0(1, n, k)或者(n, k)——沿着列,变成一行
1(m, 1, k)或者(m, k)——沿着行,变成一列
2(m, n, 1)或者(m, n)

注意: size中是否有“1”,取决于参数keepdim,keepdim=True会保留维度1。默认为false

七、常用的比较函数

函数功能
gt/lt/ge/le/eq/ne大于/小于/大于等于/小于等于/等于/不等
topk最大的k个数
sort排序
max/min比较两个tensor的最大值和最小值

max/min为例:

t.max(tensor)返回tensor中最大的一个数
t.max(tensor,dim)指定维上最大的数,返回tensor和下标
t.max(tensor1,tensor2)比较两个tensor相比较的元素

 

 

 

 

八、常用的线性代数函数

函数功能
trace对角线元素之和(矩阵的迹)
diag对角线元素
triu/tril矩阵的上三角/下三角,可指定偏移量
mm/bmm矩阵乘法/batch的矩阵乘法
addmm/addbmm/addmv矩阵运算
t转置
dot/cross内积/外积
inverse求逆矩阵
svd奇异值分解

注意:矩阵的转置会导致存储空间不连续,需调用它的.contiguous方法将其转为连续

a = t.ones(2, 3)
print(a)
# 求a的转置
b = a.t()
# 查看a的转置矩阵b是否连续
print(b.is_contiguous())
# 将其转为连续
print(b.contiguous())

结果:

             

九、对于Tensor和Numpy之间遇到的问题

需要注意的是:Numpy和Tensor共享内存。PyTorch已经支持了自动广播法则。

当遇到Tensor不支持的操作时,可以先转成Numpy数组,处理后再转为tensor,其转换开销很小。

  • 当输入数组的某个维度的长度为1时,计算时沿此维度复制扩充成一样的形状。
  • unsqueeze或view:为数据某一维的形状补1,实现法则1.
  • expand或expand_as,重复数组,实现法则3;该操作不会复制数组,所以不会占用额外的空间

     9.1、持久化

          tensor的保存:t.save

          tensor的加载:t.load

在load时还可以将GPU tensor映射到CPU或其他GPU上。

if t.cuda.is_available():
    a = a.cuda(1)  # 把a转为GPU1上的tensor
    t.save(a, 'a.path')
    # 加载为b,存储于GPU1上(因为保存时tensor就在GPU1上)
    b = t.load('a.path')
    # 加载为c,存储于CPU
    c = t.load('a.path', map_location=lambda storage, loc: storage)
    # 加载为d,存储于GPU0上
    d = t.load('a.path', map_location={'cuda:1':'cuda: 0'})

    9.2、向量化

           向量化计算是一种特殊的并行计算方式,一般程序在同一时间只执行一个操作的方式,它可以在同一时间执行多个操作,通常是对不同的数据执行同样的一个或一批指令,或者说把指令应用于一个数组/向量上。向量化可极大地提高科学运算的效率。

在科学计算程序中应当极力避免使用Python原生的for循环,尽量使用向量化的数值计算。

           还需要注意:

  • 大多数t.function都有一个参数out,这时产生的结果将保存在out指定的tensor之中
a = t.arange(0, 20000000)
b = t.LongTensor()
t.arange(0, 20000000, out=b)  # 64bit的LongTensor不会溢出
  • t.set_num_threads可以设置PyTorch进行CPU多线程并行计算时所占用的线程数,用来限制PyTorch所占用的CPU数目。
  • t.set_printoptions可以用来设置打印tensor时的数值精度和格式。

十、View的用法

a=torch.Tensor([[[1,2,3],[4,5,6]]])
b=torch.Tensor([1,2,3,4,5,6])

print(a.view(1,6))
print(b.view(1,6))

输出结果:tensor([[1., 2., 3., 4., 5., 6.]]) 
          tensor([[1., 2., 3., 4., 5., 6.]]) 
# -------------------------------------------------------
a=torch.Tensor([[[1,2,3],[4,5,6]]])
print(a.view(3,2))
输出结果:
tensor([[1., 2.],
        [3., 4.],
        [5., 6.]])
相当于就是从1,2,3,4,5,6顺序的拿数组来填充需要的形状
# --------------------------------------------------------
但是如果你想得到:
tensor([[1., 4.],
        [2., 5.],
        [3., 6.]])

就需要用到permute()
# -------------------------------------------------------
另外,参数不可为空。
参数中的-1就代表这个位置由其他位置的数字来推断,只要在不致歧义的情况的下,view参数就可以推断出来,也就是人可以推断出形状的情况下,view函数也可以推断出来。
比如a tensor的数据个数是6个,如果view(1,-1),我们就可以根据tensor的元素个数推断出-1代表6。而如果是view(-1,-1,2),人不知道怎么推断,机器也不知道。
还有一种情况是人可以推断出来,但是机器推断不出来的:view(-1,-1,6),人可以知道-1都代表1,但是机器不允许同时有两个负1。

如果没有-1,那么所有参数的乘积就要和tensor中元素的总个数一致了,否则就会出现错误。

十一、sequeeze和unsqueeze

 简介和用法

squeezeunsqueeze的作用与其翻译基本一致,被作用维度压缩和解压缩.用法相对简单,具体如下:

tensor_unsqueeze = tensor.unsqueeze(dim)

tensor存在n个维度,则dim的取值为[-n+1,n]区间的整数,且dim的取值不能为空.

tensor_squeeze = tensor.squeeze(dim)

tensor存在n个维度,则dim的取值为[-n,n-1]区间的整数,但dim的值可以为空

具体示例:

首先看unsqueeze,其中的参数dim不能为空。

f = torch.arange(0, 6).view(3, 2)
print(f, f.size())
# 参数表示在哪一维的前面增加一个维度
print(f.unsqueeze(0), f.unsqueeze(0).size())  # 1×3×2
print(f.unsqueeze(1), f.unsqueeze(1).size())  # 3×1×2
print(f.unsqueeze(2), f.unsqueeze(2).size())  # 3×2×1
# --------------------------------------------------
tensor([[0, 1],
        [2, 3],
        [4, 5]]) torch.Size([3, 2])

tensor([[[0, 1],
         [2, 3],
         [4, 5]]]) torch.Size([1, 3, 2])

tensor([[[0, 1]],

        [[2, 3]],

        [[4, 5]]]) torch.Size([3, 1, 2])

tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

再看squeeze,它是将被操作目标中维度为1的部分去除。

其中dim表示需要在哪一维去掉一个维度,如果不指定则自动寻找,如果指定则当指定的维度为1时去掉,如果不为1则不改变。

f = torch.arange(0, 6).view(3, 2, 1)
print(f, f.size())  # 3*2*1
print(f.squeeze(0), f.squeeze(0).size())  # 3*2*1,维度为3,不能去掉,所以不变
print(f.squeeze(1), f.squeeze(1).size())  # 3*2*1,维度为2,不能去掉,所有不变
print(f.squeeze(2), f.squeeze(2).size())  # 3*2  ,维度为1,可以去掉,所有改变
print(f.squeeze(), f.squeeze().size())    # 如果无参数,则自动寻找,找到则删除。
# -------------------------------------------------------------------------------
tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

tensor([[[0],
         [1]],

        [[2],
         [3]],

        [[4],
         [5]]]) torch.Size([3, 2, 1])

tensor([[0, 1],
        [2, 3],
        [4, 5]]) torch.Size([3, 2])

tensor([[0, 1],
        [2, 3],
        [4, 5]]) torch.Size([3, 2])

 

十二、cat的用法

cat是用于将两个矩阵进行拼接,0表示按行拼接,1表示按列拼接

a = torch.ones(2, 3)
b = 2 * torch.ones(4, 3)
c = 4 * torch.ones(2, 4)
print(a)
print(b)
print(c)
d = torch.cat((a, b), 0)  # 0表示按行拼接
e = torch.cat((a, c), 1)  # 1表示按列拼接
print(d)
print(e)
# -----------------------------------------------
tensor([[1., 1., 1.],
        [1., 1., 1.]])

tensor([[2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.]])

tensor([[4., 4., 4., 4.],
        [4., 4., 4., 4.]])

tensor([[1., 1., 1.],
        [1., 1., 1.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.],
        [2., 2., 2.]])

tensor([[1., 1., 1., 4., 4., 4., 4.],
        [1., 1., 1., 4., 4., 4., 4.]])

 

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值