TORCH01-04:Tensor的访问操作函数

Tensor本身是数据View,与Storage结合形成MVC模式。本主题主要罗列Tensor数据访问有关的函数。


数据访问

item函数

  • 直接把标量Tensor转换为Python类型
import torch

# t = torch.Tensor([
#     [1, 2, 3],
#     [4, 5, 6],
#     [7, 8, 9]
# ])
t = torch.Tensor([1])
print(t.item())
1.0

data属性与detach函数

  • data与原Tensor共享Storage,但是属性会改变:requires_grad会变为False。

    • 可以通过data修改原数据,修改后,在运行时不会检测,然后可能会产生错误
  • detach()函数返回的是从计算图中剥离出来的Tensor,requires_grad=False。

    • 通过detach()函数返回的张量修改数据,这种修改在运行的时候,会先检测是否修改,从而在运行前触发错误。
  • 注意:

    • 关于Tensor的检测实际与图跟踪有关,这个在Torch中提供了上下文管理来处理,个人喜欢使用上下文管理器,用来管理作用在Tensor上的各种运算操作跟踪。
# data的不安全说明
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
t.requires_grad=True
print(t.data)
print(t.data.requires_grad)
t.data[0,0] =88                    # 这种修改在运行时可能导致致命错误
print(t)

tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]])
False
tensor([[88.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.]], requires_grad=True)
### detach的安全说明(修改的时候直接检测,就是不准修改了,这样安全)
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
t.requires_grad=True
print(t.detach())
print(t.detach().requires_grad)
t.detach()[0,0] =88                    # 这种修改在运行时可能导致致命错误
print(t)
t.detach().resize_(3,3)
tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]])
False
tensor([[88.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.]], requires_grad=True)





tensor([[88.,  2.,  3.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.]])
# data的不安全说明
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
t.requires_grad=True
y = t.sigmoid()
y_ = y.sum() 
r = y_.backward(retain_graph=True)   # backward本身不会返回值 r = Nones
print(t.grad)

# 修改数据
y.data[0,0]=88    # 不检测错误,但可能已经有错误(不允许在计算中途修改)
y_.backward()   # backward本身不会返回值 r = Nones
print(t.grad)
print(t.data[0,0])
tensor([[1.9661e-01, 1.0499e-01, 4.5177e-02],
        [1.7663e-02, 6.6480e-03, 2.4665e-03],
        [9.1017e-04, 3.3522e-04, 1.2337e-04]])
tensor([[-7.6558e+03,  2.0999e-01,  9.0353e-02],
        [ 3.5325e-02,  1.3296e-02,  4.9329e-03],
        [ 1.8203e-03,  6.7045e-04,  2.4673e-04]])
tensor(1.)
# data的不安全说明
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
t.requires_grad=True
y = t.sigmoid()
y_ = y.sum() 
r = y_.backward(retain_graph=True)   # backward本身不会返回值 r = Nones
print(t.grad)

# 修改数据
y.detach()[0,0]=88    # 检测错误,修改数据就会报错,这样最终结果安全。
y_.backward()   # backward本身不会返回值 r = Nones
print(t.grad)
print(t.data[0,0])
tensor([[1.9661e-01, 1.0499e-01, 4.5177e-02],
        [1.7663e-02, 6.6480e-03, 2.4665e-03],
        [9.1017e-04, 3.3522e-04, 1.2337e-04]])



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

RuntimeError                              Traceback (most recent call last)

 in ()
     15 # 修改数据
     16 y.detach()[0,0]=88    # 检测错误,修改数据就会报错,这样最终结果安全。
---> 17 y_.backward()   # backward本身不会返回值 r = Nones
     18 print(t.grad)
     19 print(t.data[0,0])


/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: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [3, 3]], which is output 0 of SigmoidBackward, is at version 1; expected version 0 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True).

numpy函数

  • 把Tensor转换为Numpy的ndarray格式。
  • 这种转换大部分没有意义
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(t.numpy())
[[1. 2. 3.]
 [4. 5. 6.]
 [7. 8. 9.]]

storage/storage_offset/storage_type函数

  • 可以直接返回Tensor的数据存储对象
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(t.storage())
print(t.storage_offset())
print(t[1,1].storage_offset())
print(t.storage_type())
 1.0
 2.0
 3.0
 4.0
 5.0
 6.0
 7.0
 8.0
 9.0
[torch.FloatStorage of size 9]
0
4

stride函数

  • 返货Tensor的对Storage的行列的间隔步长,按照维数指定,维度由0,1,2,...指定
    • 0行
    • 1列
  • 注意:
    • 使用负数指定逆序的维数,-1表示最后一个维度,-2就是倒数第二个维度,
    • 步长的单位是Storage的元素长度。
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(t.stride())   # 返回所有维度
print(t.stride(1))   # 返回第二维读步长
print(t.stride(0))   
print(t.stride(-1))   
print(t.stride(-2))   
(3, 1)
1
3
1
3

as_strided函数

  • 按照指定的步长返回新的Tensor
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

s = t.as_strided((2, 2), (3, 1), storage_offset=2)   # 返回的张量与原来的Storage共享存储空间
print(s)
s[0,0]=88   
print(t)
tensor([[3., 4.],
        [6., 7.]])
tensor([[ 1.,  2., 88.],
        [ 4.,  5.,  6.],
        [ 7.,  8.,  9.]])

view与view_as函数

  • as_strided函数特例版本,不需要offset,不需要stride
  • 需要view前后的size一样。
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

s = t.view((1,9))
print(s)
tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

v = torch.Tensor(1, 9)

s = t.view_as(v)
print(s)
tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])

to与to_**函数

  • to系列函数有:
    • to
      • dtype 与 device转换
    • to_dense/ to_sparse
      • 稀疏矩阵与稠密矩阵之间转换(转换的是layout格式)
    • to_mkldnn
      • cpu加速
    • to_list
      • 转换为python类型
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(t.to(dtype=torch.int32, device=torch.device("cpu:0")))    # 还可以使用device,根据cpu个数来,只有一个就只能是0
print(t.to_sparse())     # 稠密矩阵调用这个
# print(t.to_dense())  # 稀疏Tensor就调用这个
print(t.to_mkldnn())
print(t.tolist())   
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]], dtype=torch.int32)
tensor(indices=tensor([[0, 0, 0, 1, 1, 1, 2, 2, 2],
                       [0, 1, 2, 0, 1, 2, 0, 1, 2]]),
       values=tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.]),
       size=(3, 3), nnz=9, layout=torch.sparse_coo)
tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]], layout=torch._mkldnn)
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]

type与type_as函数

  • type与type_as主要是类型转换。
    • type_as是使用参数的Tensor类型
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(t.type(torch.float32))  

t.type_as(t.type(torch.float32))
tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]])





tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]])

类型转换系列函数

import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
print(t.int())
print(t.long())
print(t.byte())
print(t.char())
print(t.short())
print(t.half())
print(t.float())
print(t.double())
print(t.bool())
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]], dtype=torch.int32)
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]])
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]], dtype=torch.uint8)
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]], dtype=torch.int8)
tensor([[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]], dtype=torch.int16)
tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]], dtype=torch.float16)
tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]])
tensor([[1., 2., 3.],
        [4., 5., 6.],
        [7., 8., 9.]], dtype=torch.float64)
tensor([[True, True, True],
        [True, True, True],
        [True, True, True]])

reshape与resize函数

  • 这个系列函数有:
    • reshape:不改变Tensor的元素个数
    • reshape_as:使用已知Tensor作为参照
    • resize:改变元素个数
    • resize_as_:使用已知Tensor作为参照
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(t.reshape(1, 9))
print(t.resize_(2, 2))   # 按照顺序来
tensor([[1., 2., 3., 4., 5., 6., 7., 8., 9.]])
tensor([[1., 2.],
        [3., 4.]])

data_ptr函数

  • 返回第一个元素的地址,一般没有什么意义。
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
print(t.data_ptr())
140604559708032

dense_dim与sparse_dim函数

  • 返回稀疏与稠密矩阵维度
  • 这两个函数都是稀疏矩阵使用的。
import torch

t = torch.Tensor([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])
print(t.to_sparse().sparse_dim())
print(t.to_sparse().dense_dim()) 
2
0

element_size函数

  • 元素大小
import torch
t1 = torch.LongTensor(2, 3)
t2 = torch.DoubleTensor(3, 2)
print(t1.element_size(),  t2.element_size())
8 8

get_device函数

  • 获取设备
    • 对CPU来说,应该抛出异常
import torch
t1 = torch.LongTensor(2, 3)
print(t1.cpu().get_device())    # 返回-1,其实应该是抛出异常。
print(t1.get_device())    # 返回-1,其实应该是抛出异常。
-1

nelement函数

  • 返回所有元素个数
import torch
t1 = torch.LongTensor(2, 3)
print(t1.nelement())   
6

flatten函数

  • 与numpy的flat函数一样,把Tensor的layout从多维变成一维。
import torch
t1 = torch.LongTensor(2, 3)
print(t1.flatten())
tensor([0, 0, 0, 0, 0, 0])

dequantize函数

  • Tensor去量化
    • 量化是一种离散化的技术,可以用于数据压缩等。
import torch
t1 = torch.FloatTensor([0.0, 10.50,  11.50, 11.45])    # 被离散化
print(t1.is_quantized)

False
# 线性量化函数,这个函数在卷积运算中使用。
q_t1= torch.quantize_linear(t1,  0.2,  0, torch.qint8)
print(q_t1.is_quantized)
print(q_t1.data)

print(q_t1.dequantize())
print(q_t1.dequantize().is_quantized)
True
tensor([ 0.0000, 10.4000, 11.6000, 11.4000], size=(4,), dtype=torch.qint8,
       scale=0.2, zero_point=0)
tensor([ 0.0000, 10.4000, 11.6000, 11.4000])
False

values函数

  • 返回稀疏Tensor的数据;
    • 矩阵类型必须是coalesced 稀疏矩阵(聚接后的稀疏矩阵的值)
import torch
i = torch.tensor(
    [[0, 1, 1],
     [2, 0, 2]])
v = torch.tensor([3, 4, 5], dtype=torch.float32)
sp = torch.sparse_coo_tensor(i, v)  

print(sp.coalesce().values())
tensor([3., 4., 5.])

indices函数

  • 这个函数只争对torch.sparse_coo布局的稀疏矩阵。
  • 返回值得索引,见values函数
import torch
i = torch.tensor(
    [[0, 1, 1],
     [2, 0, 2]])
v = torch.tensor([3, 4, 5], dtype=torch.float32)
sp = torch.sparse_coo_tensor(i, v)  

print(sp.coalesce().indices())
tensor([[0, 1, 1],
        [2, 0, 2]])

squeeze_/squeeze与unsqueeze/unsqueeze_函数

  • 矩阵降维(减少维数)
    • 前提是只有一个元素的向量,可以直接转化为标量,从而实现降维。
    • 带后缀下划线的函数,影响被操作的Tensor,同时返回操作后的Tensor。
import torch
t1 = torch.Tensor([
    [2],[3],[4]
])
print(t1.squeeze())
print(t1.squeeze().unsqueeze(0))   # 指定扩大哪一维
print(t1.squeeze().unsqueeze(1))    # 不能取大于等于2的维度。
tensor([2., 3., 4.])
tensor([[2., 3., 4.]])
tensor([[2.],
        [3.],
        [4.]])
import torch
t1 = torch.Tensor([
    [2],[3],[4]
])
print(t1.squeeze_())
print(t1)
tensor([2., 3., 4.])
tensor([2., 3., 4.])

你可能感兴趣的:(TORCH01-04:Tensor的访问操作函数)