tensor是pyTorch的基本数据结构,可以表示任意维度的多维数组;
pyTorch tensor可以和Numpy array无缝的互操作,pyTorch tensor相对Numpy array的优点是:
python list或tuple中存储的是单独分配在内存中的python对象的集合,而numpy array和pytorch tensor中存储的是连续内存块的视图,该内存块中存储的是未封装的C语言数值类型;
points[None]
等价于对 points 添加一个新的维度,等价于 points.unsqueeze(0)
;
tensor的维度常用来进行索引,如表示像素位置或颜色channel。这意味着如果我们要对某个tensor进行索引,就需要记清各个维度的顺序,但如果某个tensor进行了很复杂的处理过程,往往很容易因为记混tensor的各个维度的含义而造成错误。
pytorch 1.3版本开始引入了named tensor,即给tensor的各个维度进行命名,如:
refine_names 函数用于对一个未命名的tensor添加name,如下所示:
align_as返回一个tensor,自动补充缺失的维度,并且按名字将维度调整为正确的顺序:
tensor的那些按照维度进行操作的函数,如sum,可以按照named维度进行操作,如:
如果想将名字不同的维度进行结合,会报错,如:
**rename(None)**可以去掉一个Named tensor的名字,如:
named tensor有助于消除维度对齐的错误。
为什么不用python原生的数据类型进行大规模的矩阵运算 ?
答案: python原生的数据类型都是封装过的数据,添加了引用计数这些信息,大规模计算时效率低。numpy array和pytorch tensor提供的api都是在底层封装的是C语言实现的数据计算,效率更高。
pytorch tensor中存储的是同类型的数据,可以在构造函数中通过dtype指定创建的tensor的数据类型。
pytorch中常用的数据类型有:
默认的数据类型是 32位单精度浮点数。
CPU不支持半精度浮点数运算,但GPU支持,将单精度浮点数改为半精度浮点数,可以减少显存占用且对模型的准确率影响很小,这也是混合精度训练能够成功的原因。
下面的操作会创建一个bool类型的tensor:
设定tensor的数据类型:
tensor是连续内存块的视图,通过offset和每一维的stride索引到实际的内存。
storage函数用于查看一个tensor的实际存储,如:
实际存储一定是连续的一维的内存序列。
改变storage中的数据之后,tensor的内容也会跟着改变:
tensor的带下划线的函数,如zero_都是对tensor进行in-place操作,直接修改了tensor本身。
tensor的size()函数和shape属性查看tensor的各个维度的大小;storage_offset函数查看tensor相比对实际存储的起始位置的距离;stride函数查看在tensor的每个维度上前移一位对应到实际存储上需要移动的位数。
2D tensor中第(i,j)个元素在实际存储中的位置为 storage_offset + i * stride[0] + j * stride[1].
tensor只是实际内存的视图,因此很多操作,如transpose和subtensor的效率很高,因为并未进行实际存储的改变,只是改变了tensor的属性(size,storage_offset和stride)。
clone函数是深拷贝tensor,进行了新的内存分配:
contiguous函数是将一个tensor的存储变为连续队列,如:
z是y的转置,其存储对z来说是不连续的,执行contiguous函数后,存储对z来说变成连续的了。
构造函数中,通过device参数设置tensor存储在内存还是显存中,如:
也可以通过to函数强制改变tensor的存储位置,如:
还可以通过cuda、cpu函数改变存储位置:
cuda(1)表示传输到第二块显卡上,默认参数为0,表示传输到第一块显卡上。
numpy函数将tensor转换为ndarray;from_numpy将numpy转换为tensor。
numpy函数返回的ndarray与tensor共享内存,因此如果tensor本身就放在内存上,那么这个转换基本上是没有开销的。但如果tensor本身放在显存上,则需要先将数据拷贝到内存上,并基于该内存块构建一个tensor。
pytorch底层使用pickle来保存数据,使用torch.save保存tensor,torch.load加载保存结果。
保存成HDF5格式: