Pytorch 中的张量(tensor)--- Pytorch深度学习实战 Chapter3
整理一下自己在阅读《Pytorch深度学习实战》这本书时的笔记和一些些感悟。对应的代码搜索异步社区,找到本书就可以直接下载啦。
Pytorch
PyTorch的核心是一个提供多维数组(张量)以及由toch模块提供大量操作的库。张量及操作可以在CPU或GPU上使用。在PyTorch中,将运算从CPU转移到GPU不需要额外的函数调用。PyTorch提供的第2个核心功能是张量可以跟踪对其执行的操作的能力,并分析和计算任何输入对应的输出的导数。该功能用于数值优化,是由张量自身提供的,通过PyTorch底层自动求导引擎来调度。
张量
使用张量来处理浮点数,在深度学习中张量可以将向量和矩阵推广到任意维度(多维数组),张量的维度与用来表示张量中标量值的索引数量一致。
PyTorch并不是处理多维数组的唯一库。到目前为止,NumPy是最受欢迎的多维数组库,可以说它已成为数据科学的通用语言。PyTorch具有与NumPy无缝互操作的特性,这使得它能够与Python中的其他科学库(如SciPy、scikit--learn以及pandas等)进行最优的集成。
与NumPy数组相比,PyTorch张量具有一些「超能力」,如在GPU上执行非常快的操作、在多个设备或机器上进行分布式操作以及跟踪创建它们的计算图。
张量:存储了一组数字,这些数字可以用一个索引单独访问,也可以用多个索引访问。可以看做是Pytorch的基本数据结构。
实际操作时看似与Numpy数组等类似,但原理有很大区别。
张量的索引与运算
张量索引与数组类似
张量内的对象必须都是相同类型的数字
使用dtype来制定包含在张量中的数据类型,如tensor(), zeros()和ones()函数。可能取值有
torch.float torch.double torch.half torch.int8 torch.unit8 torch.int16 torch.int32 torch.int64 torch.int64 torch.bool。张量的默认数据类型是32位浮点数。
通过访问相应的属性找到对应的dtype值,还可以使用对应的转换方法进行数据类型转换。
关于张量以及张量之间的绝大多数操作都可以在torch模块中找到,如transpose()函数
还有很多通用API,包括创建操作,索引、切片、连接、转换操作,数学操作,逐点操作,归约操作,比较操作,频谱操作,其他操作,线性代数中的常规操作,随机采样,序列化,并行化......
实际需要时当官方文档查阅即可。
张量的存储
张量中的值被分配到由torch.Storage实例所管理的连续内存块中。存储区是由数字数据组成的一维数组,即包含给定类型的数字的连续内存块。
【相当于用一串数字来包含所有东西,对应逻辑很重要。不能使用二维索引来访问存储区,如果修改存储区的数据,对应张量的值也会发生变化】
【对于带有下划线的方法,表示直接在原地修改并保存。例如 b = a.zeros_(),在该例中a的值也会发生变化】
对应规则
主要通过大小、偏移量和步长三个概念来描述
大小:用一个元组记录每个维度有多少个元素
偏移量:这个tensor的第一个元素在当前存储区上的位置索引(在对切片等操作时需要)
步长:沿着一个维度获取下一个元素在实际存储区所需要跳过的元素数量
因为对同一个张量的操作只是在修改索引的方式,所以在这种情况下如果修改了子tensor,原来的tensor也会发生变化。
为了避免这类情况发生可以使用clone方法,重新创建一个tensor。
在tensor的顺序和存储区顺序一致的就是连续张量,否则就不是。
在PyTorch中,有一些操作只针对连续张量起作用,如果我们对那些不是连续张量的张量实施这些操作就会报错。
要解决这一问题,需要调用contiguous方法来改变存储区存储顺序,使得存储区顺序符合当前tensor连续的要求。
参考链接:PyTorch张量操作:底层存储逻辑 | 从0开始学PyTorch - 机器学习之禅的文章 - 知乎 https://zhuanlan.zhihu.com/p/518174397
将计算移动到GPU
管理张量的设备属性 -- device
device描述的是张量数据在计算机上的位置。在构造张量时可设定参数device = 'cuda'。
也可以使用to()方法将在CPU上创建的张量复制到GPU上。
如果机器有多个GPU,可以通过从0开始传递一个整数来确定存储张量的GPU,在此基础上,对张量执行的任何操作都将在GPU上执行。
需要注意的是,一旦在GPU上开始执行,所有的数据都不会与CPU有关。要想返回需要重新设置。
Numpy互操作性
Pytorch张量可以非常有效地转化为Numpy数组,反之亦然。与Numpy数组实现了零拷贝互操作性是因为存储系统使用了Python缓冲区协议。
commandline
point = torch.ones(2, 3)
point_num = point.numpy()
需要注意的是返回的数组与张量存储共享相同的底层缓冲区。这意味着只要数据位于CPU上的RAM中,就可以有效执行numpy()方法
如果是在GPU上存储的,Pytorch将把张量的内容复制到CPU上。反之亦然。
张量的存储
序列化张量,pytorch 在内部使用 pickle 来序列化张量对象,并为存储添加专用的序列化代码。
使用torch.save(tensor, path)
还可以用
with open(path) as f:
torch.save(tensor, f)
使用torch.load(path)来加载,或放在with里同理。
需要注意的是,这类后缀为 .t 格式的文件使用别的软件是无法读取的。为此可采用h5py序列化到HDF5
HDF5
Python通过h5py库支持HDF5,该库接收和返回Numpy数组格式的数据。
commandline
import h5py
f = h5py.File('a.hdf5', 'w')
dset = f.create_dataset('coords', data = tensor.numpy())
f.close()
这里的 coords是保存到 HDF5 文件的一个键,可以有其他键,甚至可以嵌套键。
HDF5可以在磁盘上索引数据集,并只访问感兴趣的元素。