TORCH01-02:Tensor的基本属性

本主题主要说明Tensor的属性及其使用;这些属性的设置,影响着数据的使用;Tensor最大的好处就是提供了计算跟踪,这个跟踪用来提供动态图的构建,这个与Tensorflow的静态图是不同滴。同时还提供了导数的逆向计算,这是目前神经网络中最成功的网络思想:前馈神经网络的实现基础(梯度下降算法);


回顾

  • 因为Torch的核心是Tensor,Tensor的数据由Storage管理,所以这两个类的关系搞清楚,就可以使用Tensor了。

Tensor的Python构造器定义如下

    Tensor.__init__(torch.device device)
    Tensor.__init__(torch.Storage storage)
    Tensor.__init__(Tensor other)
    Tensor.__init__(tuple of ints size, torch.device device)
    Tensor.__init__(object data, torch.device device)

Storage的Python构造器定义如下

    FloatStorage.__init__() no arguments
    FloatStorage.__init__(int size)
    FloatStorage.__init__(Sequence data)
    FloatStorage.__init__(torch.FloatStorage view_source)
    FloatStorage.__init__(torch.FloatStorage view_source, int offset)
    FloatStorage.__init__(torch.FloatStorage view_source, int offset, int size)

关于Tensor

Tensor与Numpy

  • 实际上按照Python一贯的思路,会提供很多函数来替代构造器的使用,这样做有两个原因:

    • 个性化,方便,简单;
    • 使用工厂模式来创建对象,符合软件的常见设计模式,Python大量采用;
      • 今后不要动不动就说面向对象最好,最方便。最直观,最方便的还是函数,拿来就用,不需要构建对象才能使用。
  • Torch号称是GPU版本的Numpy,Numpy有的Tensor都有,所以按照Numpy的思路,在构建好对象后,有三大块功能是需要数理下的,掌握这三大基础功能,后面的内容就容易理解:

    1. 基本属性
      • 了解对象的内存与数据结构
    2. 基本操作
      • 数据进出
    3. 数学运算
      • 构建数据对象的最终目的就是计算;
        • 计算的类别很多,基本数学运算,随机采样,线性代数的矩阵运算,统计计算,......
        • 这里先明白基本的数学运算。

Tensor的官方文档结构

torch
        Tensors
                Creation Ops
                Indexing, Slicing, Joining, Mutating Ops
                Generators
        Random sampling
                In-place random sampling
                Quasi-random sampling
                Serialization
                Parallelism
                Locally disabling gradient computation
        Math operations
                Pointwise Ops
                Reduction Ops
                Comparison Ops
                Spectral Ops
                Other Operations
                BLAS and LAPACK Operations
        Utilities
  • 这里先搞定Tensor本身的基本属性与操作
    • 基本属性(从C/C++文档对应)
    • 基本操作
      • Indexing(索引访问操作)
      • Slicing (切片访问操作【是索引的批量级升级版本】)
      • Joining(数据组合与合并)
      • Mutating Ops(数据访问:索引与切片的函数版本)
    • 数学运算:
      • Pointwise Ops(元素运算)
      • Reduction Ops(降维运算)
      • Comparison Ops(比较运算)
      • Spectral Ops(谱运算)
      • Other Operations(其他运算)
      • BLAS and LAPACK Operations(线性代数运算)
        1. BLAS
          • Basic Linear Algebra Subprograms(Fortran语言编写,Fortran史上经典古老的数学计算语言);
        2. LAPACK
          • Linear Algebra Package,底层使用的也是BLAS;
        3. ATLAS
          • Automatically Tuned Linear Algebra Software;
        4. OpenBLAS:
          • 在编译时根据目标硬件进行优化,生成运行效率很高的程序或者库。OpenBLAS的优化是在编译时进行的,所以其运行效率一般比ATLAS要高。因此OpenBLAS对硬件的依赖比较高,换一个硬件平台可能会重新进行编译。
        5. cuBLAS与ACML:
          • Intel的MKL和AMD的ACML都是在BLAS的基础上,针对自己特定的CPU平台进行针对性的优化加速。以及NVIDIA针对GPU开发的cuBLAS。

Tensor的基本属性与属性函数

  • 先构建一个张量(Tensor)使用;
import torch

t_vector = torch.LongTensor(
    data= [1, 2, 3, 4, 5]
)
print(t_vector)
t_matrix = torch.LongTensor(
    data= [
        [1, 2, 3, 4],
        [5, 6, 7, 8]
    ]
)
print(t_matrix)
tensor([1, 2, 3, 4, 5])
tensor([[1, 2, 3, 4],
        [5, 6, 7, 8]])

属性

属性-T

  • 返回Tensor的转置;
print(t_vector.T)    # 向量转置还是本身,不产生转置效果
print(t_matrix.T)
tensor([1, 2, 3, 4, 5])
tensor([[1, 5],
        [2, 6],
        [3, 7],
        [4, 8]])

属性-data

  • 返回张量的数据, 返回的也是张量,就是张量本身;
    • 返回不同的id;
    • 共享同一个Stroage;
    • 但是data返回的数据状态改变:require s_grad = False,就是不能求导。
# 地址不同
print(t_vector.data)
print(type(t_vector.data))
print(id(t_vector), id(t_vector.data))
tensor([1, 2, 3, 4, 5])

4481379352 4510253344
# 数据相互影响
d = t_vector.data
t_vector[2] =88
print(d)

tensor([ 1,  2, 88,  4,  5])
# data与原张量的差异

属性-dtype

  • Tensoor元素类型
print(t_vector.dtype)
torch.int64

属性-grad,grad_fn,requires_grad

  • 导数:
    • 默认是None
    • 调用backward计算导数,导数是累加的。如果每次单独计算,需要清空;
    • 导数的计算需要导数函数grad_fn(没有指定函数的张量无法计算导数)。
    • grad_fn函数自动跟踪,需要设置requires_grad=True
  1. grad属性
print(t_vector.grad)
None
t_vector.backward()
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

 in ()
----> 1 t_vector.backward()


/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
    116                 products. Defaults to ``False``.
    117         """
--> 118         torch.autograd.backward(self, gradient, retain_graph, create_graph)
    119 
    120     def register_hook(self, hook):


/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     91     Variable._execution_engine.run_backward(
     92         tensors, grad_tensors, retain_graph, create_graph,
---> 93         allow_unreachable=True)  # allow_unreachable flag
     94 
     95 


RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
  1. 属性-grad_fn
    • 张量所在的导数函数
t1 = torch.Tensor([1.0])
t2 = torch.Tensor([1.0])

t3 = t1 + t2
print(t3)
print(t3.grad_fn)
tensor([2.])
None
  1. requires_grad属性
t1.requires_grad=True
t2.requires_grad=True
t4 = t1 + t2
print(t4)
print(t4.grad_fn)
print(type(t4.grad_fn))
print(t4.requires_grad)
print(t1.grad_fn)
tensor([5.], grad_fn=)


True
None
print(t4.grad)
t4.backward()
print(t4.grad)    # 没有导数
print(t1.grad)     # t1与t2导数(偏导数)
print(t2.grad)
print(t1.grad_fn)
None
None
tensor([2.])
tensor([2.])
None

属性-is_cuda,device

  • 判断是否是cuda计算(GPU计算)
  • device使用专门的类构造;
t1 = torch.Tensor([2.5])
print(t1.is_cuda)
False
t2 = torch.Tensor([2.5], device=torch.device('cpu:0'))
t2 = torch.Tensor([2.5], device=torch.device('cpu'))
print(t2.is_cuda)

False
t3 = torch.Tensor([2.5], device=torch.device('cuda'))
print(t3.is_cuda)   # 苹果电脑不支持,请在Nvidia的显卡上运算,其他支持GPU运算的电脑上运行
# 在window上还需要安装厂商驱动
---------------------------------------------------------------------------

RuntimeError                              Traceback (most recent call last)

 in ()
----> 1 t3 = torch.Tensor([2.5], device=torch.device('cuda'))
      2 print(t3.is_cuda)   # 苹果电脑不支持,请在Nvidia的显卡上运算,其他支持GPU运算的电脑上运行


RuntimeError: legacy constructor for device type: cpu was passed device type: cuda, but device type must be: cpu
# 判定电脑是否之处GPU运算
print(torch.cuda.is_available())
False

属性-is_leaf,grad与retain_grad函数

  • 这个属性用来判定张量Tensor是否是Leaf Tensor,下面两种情况都应该是Leaf Tensor:

    • 属性requires_grad为False的。
    • 属性requires_grad=True,但是用户构建的Tensor,表示该张量不是计算结果,而是用户构建的初始张量。
  • 运行backward后,仅仅只有Leaf Tensor在才会有grad属性。如果非Leaf Tensor需要具有grad属性,需要使用retain_grad函数开启grad属性。

# 演示叶子Tensor与grad,backward的关系
import torch

t1 = torch.Tensor([1.0])     # 用户构建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1 + t2
t3.backward()

print(t1.is_leaf, t2.is_leaf, t3.is_leaf)
print(t1.grad)     # Leaf Tensor的grad属性由backward函数产生。
True True False
tensor([1.])
# 演示Non-Leaf Tensor 与 retain_grad的关系

import torch

t1 = torch.Tensor([1.0])     # 用户构建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1 + t2
t3.retain_grad()    # 调用该函数后,t3才有grad属性,可以注释这个语句体验
t3.backward()

print(t1.is_leaf, t2.is_leaf, t3.is_leaf)
print(t3.grad) 
True True False
tensor([1.])

属性-ndim与dim函数

  • Tensor的维度
import torch
t1 = torch.Tensor([1.0, 20])     # 用户构建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [2.0, 1.0],
        [1.0, 2.0]
    ]
)
print(t1.ndim)   # 1 维

print(t2.ndim)  # 2 维
print(t2.dim())
1
2
2

属性-shape与size函数

  • Tensor的形状,与size函数一样
import torch
t1 = torch.Tensor([1.0, 20])     # 用户构建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [2.0, 1.0],
        [1.0, 2.0]
    ]
)
print(t2.shape) # 属性shape

print(t2.size())  # 函数size()
torch.Size([2, 2])
torch.Size([2, 2])

属性-is_sparse

  • 是否稀疏张量:

    • 在矩阵中,若数值为0的元素数目远远多于非0元素的数目,并且非0元素分布没有规律时,则称该矩阵为稀疏矩阵;与之相反,若非0元素数目占大多数时,则称该矩阵为稠密矩阵。定义非零元素的总数比上矩阵所有元素的总数为矩阵的稠密度。
  • is_sparse该属性是只读,不可写的

    • 稀疏张量提供专门的API产生。
  • 稀疏张量有自己的构造规则:
    • 稀疏张量被表示为一对致密张量:一维张量和二维张量的索引。可以通过提供这两个张量来构造稀疏张量,以及稀疏张量的大小。
# 默认的张量都是稠密张量
import torch
t1 = torch.Tensor([0, 0])     # 用户构建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [1, 0],
        [0, 0]
    ]
)
print(t1.is_sparse)  # 属性shape

print(t2.is_sparse)  # 函数size()

t3 = torch.Tensor(1000,1000)
t3.fill_(0)
t3[0,0]=1
print(t3.is_sparse)  
print(t3)
t3.is_sparse=True   # 不能修改该属性,该属性是只读,不可写的。
False
False
False
tensor([[1., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        ...,
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]])



---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

 in ()
     17 print(t3.is_sparse)
     18 print(t3)
---> 19 t3.is_sparse=True
     20 print()


AttributeError: attribute 'is_sparse' of 'torch._C._TensorBase' objects is not writable
# 稀疏矩阵
import torch
ts = torch.sparse.FloatTensor(2, 3)
print(ts.is_sparse)  
print(ts)
print(ts.to_dense())
True
tensor(indices=tensor([], size=(2, 0)),
       values=tensor([], size=(0,)),
       size=(2, 3), nnz=0, layout=torch.sparse_coo)
tensor([[0., 0., 0.],
        [0., 0., 0.]])

属性-layout

  • 张量Tensor使用Storage表示都是一维的,其构成张量只要采用布局计算。这个布局使用layout属性设置

    • 一般都是采用strided
    • 稀疏矩阵的布局使用的是:torch.sparse_coo
  • 目前常用的就是这两种布局layout。

import torch
t1 = torch.Tensor([0, 0])     # 用户构建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [1, 0],
        [0, 0]
    ]
)
print(t1.layout, t2.layout)
torch.strided torch.strided

属性-output_nr

  • 在反向传播中存放输出。
    • 具体用途先存疑。
import torch
t1 = torch.Tensor([0, 0])     # 用户构建的都是Leaf Tensor
t2 = torch.Tensor(
    [
        [1, 0],
        [0, 0]
    ]
)
print(t2.output_nr)
0
# 演示Non-Leaf Tensor 与 retain_grad的关系

import torch

t1 = torch.Tensor([2.0])     # 用户构建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1.sin()
print(t1.output_nr, t2.output_nr, t2.output_nr)
t3.retain_grad()    # 调用该函数后,t3才有grad属性,可以注释这个语句体验
t3.backward()
print(t3)
print(t1.is_leaf, t2.is_leaf, t3.is_leaf)
print(t3.grad) 
print(t1.output_nr, t2.output_nr, t2.output_nr)
0 0 0
tensor([0.9093], grad_fn=)
True True False
tensor([1.])
0 0 0

属性-其他

  • is_mkldnn:intel提供的加速CPU运算的方法,判定是否CPU加速
  • is_quantized:是否被量化(量化指将信号的连续取值近似为有限多个离散值)
  • name:张量名
  • volatile:新版本已经停用;
# 演示Non-Leaf Tensor 与 retain_grad的关系

import torch

t1 = torch.Tensor([2.0])     # 用户构建的都是Leaf Tensor
t1.requires_grad=True

t2 = torch.Tensor([2.0])
t2.requires_grad=True

t3 = t1 + t2
print(t1.is_mkldnn)
print(t2.name)
print(t2.is_quantized)
False
None
False

附录:mkldnn的使用

  1. 下载地址

    • https://github.com/intel/mkl-dnn
  2. 安装

    • cmake安装,直接套路
  3. 如果torch不支持mkldnn,就需要使用源代码重新安装!


你可能感兴趣的:(TORCH01-02:Tensor的基本属性)