针对pytorch 1.7.1
进行一次全方位的解读,所以此博客会持续更新相当的一段时间。随后的博客会跟进torch的版本更新信息,其中能添加的实例代码我都会添加。
这个包含了多维张量的数据结构和一些对于张量的数学操作。另外,提供了对张量和其他数据类型进行有效序列化的方法,还有些其他的方法。
pytorch对于tensor的存储是一分为二的,一个创建好的张量,其头信息区叫作Tensor
,负责存储tensor的形状、步长、数据类型等,其内部数据保存为数组,存储在存储区Srorage
中。
所以,Tensor
占用的内存较小,真正占用内存的地方是Storage
。
is_tensor
def is_tensor(obj):
r"""如果对象为PyTorch的张量,则返回True.
Note that this function is simply doing ``isinstance(obj, Tensor)``.
Using that ``isinstance`` check is better for typechecking with mypy,
and more explicit - so it's recommended to use that instead of
``is_tensor``.
参数:
输入参数为要测试的对象
"""
return isinstance(obj, torch.Tensor)
import torch
import numpy as np
a = np.ones([1, 2])
t = torch.from_numpy(a)
print(torch.is_tensor(a))
print(torch.is_tensor(t))
print(t)
-----------
False
True
tensor([[1., 1.]], dtype=torch.float64)
is_storage
def is_storage(obj):
r"""如果对象是PyTorch storage的话.则返回True
参数:
测试对象
"""
return type(obj) in _storage_classes
import torch
a = torch.rand(3, 5)
print(a)
print(a.storage())
print(type(a.storage()))
print(a.storage()[0])
x = a.storage()
print(torch.is_storage(x))
----------
tensor([[0.8754, 0.7499, 0.3954, 0.3763, 0.8578],
[0.7598, 0.9750, 0.6963, 0.1602, 0.3442],
[0.9445, 0.5585, 0.2020, 0.9230, 0.4736]])
0.8753897547721863
0.7498539090156555
0.3954319953918457
0.3762640357017517
0.857833981513977
0.7598322033882141
0.9749904870986938
0.6962557435035706
0.16019368171691895
0.34423667192459106
0.9444983005523682
0.5584731101989746
0.20202845335006714
0.9230412840843201
0.473596453666687
[torch.FloatStorage of size 15]
<class 'torch.FloatStorage'>
0.8753897547721863
True
is_complex
def is_complex(input: Tensor) -> _bool: ...
r"""
判断输入张量是否为复数类型(torch.complex64或者torch.complex128),是则返回True。
"""
import torch
a = torch.tensor([1, 2], dtype=torch.float32) #创建复数的实部
b = torch.tensor([3, 4], dtype=torch.float32) #创建复数的虚部
z = torch.complex(a, b) #只有1.7以后才有这个方法
print(z)
print(z.dytpe)
print(torch.is_complex(z))
----------
tensor([1.+3.j, 2.+4.j])
torch.complex64
True
is_floating_point
def is_floating_point(input: Tensor) -> _bool: ...
r"""
判断输入张量的数据类型是不是浮点型(float64\float32\float16)
"""
import torch
a = torch.tensor([1, 2], dtype=torch.float16)
print(torch.is_floating_point(a))
----------
True
is_nonzero
只用来判断单元素张量,判断多元素张量会报错。
def is_nonzero(input: Tensor) -> _bool: ...
r"""
判断输入张量的数据类型是不是单元素非零张量(非[0]\[0.]\[False]),是的话返回True。
"""
import torch
print(torch.is_nonzero(torch.tensor([0.])))
print(torch.is_nonzero(torch.tensor([1.])))
print(torch.is_nonzero(torch.tensor([False])))
print(torch.is_nonzero(torch.tensor([True])))
print(torch.is_nonzero(torch.tensor([1,2,3])))
----------
False
True
False
True
Traceback (most recent call last):
File "/home/qiao/PythonProjects/torchapi/TORCH/Tensor/is_nonzero.py", line 8, in <module>
print(torch.is_nonzero(torch.tensor([1,2,3])))
RuntimeError: Boolean value of Tensor with more than one value is ambiguous
set_default_dtype
对torch.tensor()
创建出的张量的数据类型进行初始化自定义,修改之前的torch.tensor()
的默认数据类型。
def set_default_dtype(d):
r"""将数据类型设置为d.
1.用`torch.tensor`推理之后的数据类型.
2. 因为默认的数据类型是torch.float32,所以复数张量的默认数据类型torch.complex64。
3. 如果自定义默认数据类型为torch.float64,那么复数数据类型变成对应的torch.complex128。
"""
_C._set_default_dtype(d)
import torch
print(torch.tensor([1.2, 3]).dtype)
print(torch.tensor([1.2, 3j]).dtype)
torch.set_default_dtype(torch.float64)
print(torch.tensor([1.2, 3]).dtype)
print(torch.tensor([1.2, 3j]).dtype)
---------
torch.float32
torch.complex64
torch.float64
torch.complex128
get_default_dtype
获取当前的默认张量数据类型。
def get_default_dtype() -> _dtype: ...
r"""
获取当前的默认张量数据类型。
"""
import torch
print(torch.get_default_dtype())
torch.set_default_dtype(torch.float64)
print(torch.get_default_dtype())
torch.set_default_tensor_type(torch.FloatTensor)
print(torch.get_default_dtype())
----------
torch.float32
torch.float64
torch.float32
set_default_tensor_type
这个方法与前面的set_default_dtype
有点相似,但还是有不同,下面的实例中我们会测试一下。
def set_default_tensor_type(t):
r"""同样是设置默认的张量数据类型,但是这个输入的t与之前不同,
这里只可以输入torch.FloatTensor这种格式。
"""
if isinstance(t, _string_classes):
t = _import_dotted_name(t)
_C._set_default_tensor_type(t)
import torch
print(torch.tensor([1.2, 3]).dtype) # initial default for floating point is torch.float32
torch.set_default_tensor_type(torch.DoubleTensor)
print(torch.tensor([1.2, 3]).dtype) # a new floating point tensor
torch.set_default_tensor_type(torch.float32)
print(torch.tensor([1.2, 3]).dtype)
--------
torch.float32
torch.float64
Traceback (most recent call last):
File "/home/qiao/PythonProjects/torchapi/TORCH/Tensor/set_default_tensor_type.py", line 8, in <module>
torch.set_default_tensor_type(torch.float32)
File "/home/qiao/anaconda3/lib/python3.7/site-packages/torch/__init__.py", line 295, in set_default_tensor_type
_C._set_default_tensor_type(t)
TypeError: invalid type object
import torch
print(torch.tensor([1.2, 3]).dtype) # initial default for floating point is torch.float32
torch.set_default_tensor_type(torch.DoubleTensor)
print(torch.tensor([1.2, 3]).dtype) # a new floating point tensor
torch.set_default_dtype(torch.float32)
print(torch.tensor([1.2, 3]).dtype)
torch.set_default_dtype(torch.DoubleTensor)
print(torch.tensor([1.2, 3]).dtype)
--------
torch.float32
torch.float64
torch.float32
Traceback (most recent call last):
File "/home/qiao/PythonProjects/torchapi/TORCH/Tensor/set_default_tensor_type.py", line 11, in <module>
torch.set_default_dtype(torch.DoubleTensor)
File "/home/qiao/anaconda3/lib/python3.7/site-packages/torch/__init__.py", line 326, in set_default_dtype
_C._set_default_dtype(d)
TypeError: invalid dtype object
numel
计算张量的所有元素的总个数。
def numel(self: Tensor) -> _int: ...
r"""
返回张量所有元素的总个数
"""
import torch
a = torch.randn(1, 2, 3, 4, 5)
print(torch.numel(a))
a = torch.zeros(4,4)
print(torch.numel(a))
---------
120
16
set_printoptions
这个方法主要是为了设置print展示出来的张量的显示格式等,和numpy对应的该方法一模一样。
def set_printoptions(
precision=None,
threshold=None,
edgeitems=None,
linewidth=None,
profile=None,
sci_mode=None
):
r"""
Args:
precision: 显示出来每个元素的精度数,默认为4;
threshold: 总元素数大于某个值时进行折叠,默认为1000;
edgeitems: 某个维度上的行数只显示前n行和后n行,中间的折叠,默认n为3;
linewidth: 每行的宽度超过这个值会换行,默认为80;
profile: 有 `default`, `short`, `full`三个模式,full显示小数点后四位,short显示小数点后两位);
sci_mode: 是否开启科学计数法。
"""
if profile is not None:
if profile == "default":
PRINT_OPTS.precision = 4
PRINT_OPTS.threshold = 1000
PRINT_OPTS.edgeitems = 3
PRINT_OPTS.linewidth = 80
elif profile == "short":
PRINT_OPTS.precision = 2
PRINT_OPTS.threshold = 1000
PRINT_OPTS.edgeitems = 2
PRINT_OPTS.linewidth = 80
elif profile == "full":
PRINT_OPTS.precision = 4
PRINT_OPTS.threshold = inf
PRINT_OPTS.edgeitems = 3
PRINT_OPTS.linewidth = 80
if precision is not None:
PRINT_OPTS.precision = precision
if threshold is not None:
PRINT_OPTS.threshold = threshold
if edgeitems is not None:
PRINT_OPTS.edgeitems = edgeitems
if linewidth is not None:
PRINT_OPTS.linewidth = linewidth
PRINT_OPTS.sci_mode = sci_mode
set_flush_denormal
为了防止一些特别小的数引起的问题。开启时,当数组过小时,会将这个值归为0。
import torch
torch.set_flush_denormal(True)
print(torch.tensor([1e-323], dtype=torch.float64))
torch.set_flush_denormal(False)
print(torch.tensor([1e-323], dtype=torch.float64))
--------
tensor([0.], dtype=torch.float64)
tensor([9.8813e-324], dtype=torch.float64)
tensor
这个看似很简单的方法其实有很多的细节要注意:
torch.tensor()
在使用的时候总是会对源数据进行一次复制,如果是对Tensor源数据调用这个方法想要避免复制,要使用torch.Tensor.requires_grad_()
或者torch.Tensor.detach()
;如果Numpy源数据使用这个方法且避免复制,要使用torch.as_tensor()
。torch.tensor()
=x.clone().detach()
,torch.tensor(x, requires_grad=True)
=x.clone().detach().requires_grad_(True)
。建议使用后面这种包含clone()
和detach()
的方式。spares_coo_tensor()
创建稀疏张量,所谓的稀疏矩阵是内部有很多0元素的矩阵,稀疏张量也由此而来。按照上面的tensor的存储方法,稀疏张量也一分为二来存储,而元素数据占用最大内存,那么对于一个0很多的张量来说,大部分的内存全被0占用,显然这样非常耗费资源,所以这里用COO这样的格式存储稀疏张量。COO格式可以概括为一个三元组,也就是三行数据,第一行为每个张量中每个元素的行索引、第二行为每个元素的列索引、第三行为每个元素的元素值。这篇博客很好的做了解释。
import torch
indices = torch.tensor([[4, 2, 1], [2, 0, 2]])
values = torch.tensor([3, 4, 5], dtype=torch.float32)
x = torch.sparse_coo_tensor(indices=indices, values=values, size=[5, 5])
print(x)
---------
tensor(indices=tensor([[4, 2, 1],
[2, 0, 2]]),
values=tensor([3., 4., 5.]),
size=(5, 5), nnz=3, layout=torch.sparse_coo)