为深度学习创建PyTorch张量 - 最佳选项
正如我们所看到的,PyTorch张量是torch.Tensor PyTorch类的实例。张量的抽象概念与PyTorch张量之间的区别在于,PyTorch张量为我们提供了一个可以在代码中操纵的详细实现。
在上一篇文章中,我们看到了如何利用数据(如Python列表、序列和NumPy ndarrays)在PyTorch中创建张量。给定一个numpy.ndarray,我们发现有四种方法可以创建一个torch.Tensor对象。
这里是一个快速回顾:
- > data = np.array([1,2,3])
- > type(data)
- numpy.ndarray
- > o1 = torch.Tensor(data)
- > o2 = torch.tensor(data)
- > o3 = torch.as_tensor(data)
- > o4 = torch.from_numpy(data)
复制代码- > print(o1)
- tensor([1., 2., 3.])
复制代码- > print(o2)
- tensor([1, 2, 3], dtype=torch.int32)
复制代码- > print(o3)
- tensor([1, 2, 3], dtype=torch.int32)
复制代码- > print(o4)
- tensor([1, 2, 3], dtype=torch.int32)
复制代码 我们在这篇文章中的任务是探索这些选项之间的区别,并为我们创建张量的需求提出最佳选项。
差别系统上的Numpy dtype行为
根据你的呆板和操纵系统,你的dtype可能与这里和视频中显示的差别。
Numpy根据它是在32位还是64位系统上运行来设置其默认dtype,并且在Windows系统上的行为也有所差别。
这个链接提供了关于在Windows系统上看到的差别的更多信息。受影响的方法是:tensor、as_tensor和from_numpy。
感谢hivemind的David找出了这一点!
张量创建操纵:有什么区别?
让我们开始并找出这些差别都是关于什么的。
大写/小写:torch.Tensor()与torch.tensor()
留意第一个选项torch.Tensor()有一个大写的T,而第二个选项torch.tensor()有一个小写的t。这个区别是怎么回事?
第一个选项带有大写的T是torch.Tensor类的构造函数,第二个选项是我们所说的_工厂函数_,它构建torch.Tensor对象并返回给调用者。
你可以将torch.tensor()函数视为一个工厂,它根据一些参数输入构建张量。工厂函数是一种创建对象的软件设计模式。如果你想了解更多,可以查看这里。
好的,这就是大写T和小写t之间的区别,但在这两种方式中,哪一种更好?答案是利用任何一个都可以。然而,工厂函数torch.tensor()有更好的文档和更多的设置选项,以是它现在是胜出的选择。
默认dtype与推断的dtype
好吧,在我们从利用列表中删除torch.Tensor()构造函数之前,让我们回顾一下我们在打印的张量输出中观察到的区别。
区别在于每个张量的dtype。让我们看看:
- > print(o1.dtype)
- torch.float32
- > print(o2.dtype)
- torch.int32
- > print(o3.dtype)
- torch.int32
- > print(o4.dtype)
- torch.int32
复制代码 这里的区别在于,torch.Tensor()构造函数在构建张量时利用默认的dtype。我们可以利用torch.get_default_dtype()方法验证默认的dtype:
- > torch.get_default_dtype()
- torch.float32
复制代码 通过代码验证,我们可以如许做:
- > o1.dtype == torch.get_default_dtype()
- True
复制代码 其他调用根据传入的数据选择dtype。这被称为类型推断。dtype是根据传入的数据推断的。请留意,也可以通过将dtype作为参数指定,为这些调用显式设置dtype:
- > torch.tensor(data, dtype=torch.float32)
- > torch.as_tensor(data, dtype=torch.float32)
复制代码 利用torch.Tensor(),我们无法向构造函数传递dtype。这是torch.Tensor()构造函数缺乏设置选项的一个例子。这是选择torch.tensor()工厂函数来创建张量的另一个缘故原由。
让我们看看这些更换创建方法之间的末了一个隐藏区别。
为了性能共享内存:复制与共享
第三个区别隐藏在幕后。为了揭示这个区别,我们需要在用ndarray创建我们的张量后,改变原始输入数据在numpy.ndarray中。
让我们如许做,看看我们得到什么:
- > print('old:', data)old: [1 2 3]> data[0] = 0> print('new:', data)new: [0 2 3]> print(o1)
- tensor([1., 2., 3.])
- > print(o2)
- tensor([1, 2, 3], dtype=torch.int32)
- > print(o3)tensor([0, 2, 3], dtype=torch.int32)> print(o4)tensor([0, 2, 3], dtype=torch.int32)
复制代码 留意,最初我们有data[0]=1,还要留意我们只改变了原始numpy.ndarray中的数据。留意我们没有明确地对我们的张量(o1,o2,o3,o4)举行任何更改。
然而,在设置data[0]=0之后,我们可以看到我们的一些张量发生了变化。前两个o1和o2仍然在索引0处有原始值1,而后两个o3和o4在索引0处有新值0。
这是因为torch.Tensor()和torch.tensor()在输入数据时_复制_它们,而torch.as_tensor()和torch.from_numpy()在内存中与原始输入对象_共享_它们的输入数据。
共享数据复制数据torch.as_tensor()torch.tensor()torch.from_numpy()torch.Tensor() 这种共享只是意味着内存中的实际数据存在于一个地方。因此,对底层数据发生的任何更改都将反映在两个对象中,即torch.Tensor和numpy.ndarray。
共享数据比复制数据更有效,利用的内存更少,因为数据不会写入内存中的两个位置。
如果我们有一个torch.Tensor,我们想将其转换为numpy.ndarray,我们可以如许做:
- > print(o3.numpy())
- [0 2 3]
- > print(o4.numpy())
- [0 2 3]
复制代码 这给出了:
- > print(type(o3.numpy()))
- <class 'numpy.ndarray'>
- > print(type(o4.numpy()))
- <class 'numpy.ndarray'>
复制代码 这确立了torch.as_tensor()和torch.from_numpy()都与它们的输入数据共享内存。然而,我们应该利用哪一个,它们之间有什么区别?
torch.from_numpy()函数只接受numpy.ndarray,而torch.as_tensor()函数接受各种数组式对象,包罗其他PyTorch张量。因此,torch.as_tensor()是在内存共享游戏中的胜出选择。
那为什么要这么多种函数呢?
在PyTorch中创建张量的最佳选项
鉴于全部这些细节,这两个是最佳选项:
- torch.tensor()
- torch.as_tensor()
torch.tensor()调用是主要的选择,而torch.as_tensor()应该在调整我们的代码以进步性能时利用。
关于内存共享(在可能的地方工作)的一些留意事项:
- 由于numpy.ndarray对象分配在CPU上,当利用GPU时,as_tensor()函数必须将数据从CPU复制到GPU。
- as_tensor()的内存共享不适用于内置的Python数据布局,如列表。
- as_tensor()调用需要开发职员了解共享功能。这是须要的,如许我们就不会在不知不觉中对底层数据举行了不想要的更改,而没有意识到更改会影响到多个对象。
- 如果numpy.ndarray对象和张量对象之间有很多往返操纵,as_tensor()的性能提拔将更大。然而,如果只是一个单一的加载操纵,从性能角度来看不应该有太大影响。
总结
此时,我们应该对PyTorch的tensor创建选项有了更好的理解。我们学习了工厂函数,并且看到了内存_共享与复制_如何影响性能和程序行为。下次见!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |