如何创建一个 Tensor#
备注
在 MegEngine 中创建 Tensor 与 NumPy 创建数组 的途径类似;
由于 ndarray 是 Python 数据科学社区中较为通用支持的格式 (例如 SciPy、Pandas、OpenCV 等库都对 ndarray 提供了良好的支持), 如果存在着 NumPy 已经实现但 MegEngine 尚未支持的创建途径,可以先创建 NumPy ndarray, 再将其转换成 MegEngine Tensor. 也是下面提到的最后一种方法。
创建 Tensor 的常见途径如下:
将 Python 序列转换为 Tensor (例如
list
,tuple
);使用内置函数创建 Tensor (例如
arange
,ones
,zeros
等);使用 random 子包随机生成 (可从
normal
,uniform
等分布中采样);基于现有的 Tensor 进行操作 (例如
split
,stack
等);
警告
任何通过已有数据创建 Tensor 的方式都是通过拷贝创建的,和原始数据不会共享内存。
将 Python 序列转换为 Tensor#
可以使用 Python 序列(例如列表和元组)定义 MegEngine Tensor.
列表 list
和元组 tuple
分别使用 [...]
和 (...)
定义,可以用来定义 Tensor 如何创建:
由数字组成的列表将创建 1 维 Tensor;
由列表组成的列表将创建 2 维 Tensor;
同理,更进一步的列表嵌套将创建更加高维的 Tensor.
>>> a1D = megengine.Tensor([1, 2, 3, 4])
>>> a2D = megengine.Tensor([[1, 2], [3, 4]])
>>> a3D = megengine.Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
警告
这种写法其实调用了
Tensor
类的构造函数,传入了data
参数;megengine.tensor
是megengine.Tensor
的别名,二者本质上没有任何区别。
参见
将 Tensor 转化为 Python 内置数据类型可以使用 item
或 tolist
.
默认的数据类型#
参见
当你使用 megengine.Tensor
来定义新的 Tensor 时,需要考虑到其中每个元素的 数据类型 。
默认行为是以 32 位有符号整数 int32
或浮点数 float32
来创建 Tensor.
>>> megengine.Tensor([1, 2, 3, 4]).dtype
numpy.int32
>>> megengine.Tensor([1., 2., 3., 4.]).dtype
numpy.float32
如果你希望得到的 Tensor 是某种数据类型,则需要指定在创建 Tensor 时显式指定 dtype.
创建时指定数据类型#
数据类型是可以被显式指定的,但显式指定 dtype
有可能产生非预期的溢出,例如:
>>> a = megengine.Tensor([127, 128, 129], dtype="int8")
>>> a
Tensor([ 127 -128 -127], dtype=int8, device=xpux:0)
一个 8 位有符号整数表示从 -128 到 127 的整数。将 int8 Tensor 赋值给此范围之外的整数会导致溢出。
如果使用不匹配的数据类型执行计算,可能会得到非预期的结果,例如:
>>> a = megengine.Tensor([2, 3, 4], dtype="uint8")
>>> b = megengine.Tensor([5, 6, 7], dtype="uint8")
>>> a - b
Tensor([253 253 253], dtype=uint8, device=xpux:0)
你可能希望得到的结果是 [-3, -3, -3]
, 但在 uint8
数据类型下,这些值将表示为 253
.
不同数据类型之间的计算#
注意上面两个 Tensor 即 a
和 b
有着相同的 dtype: uint8
, 因此得到的 Tensor 的数据类型也会相同。
如果你在两个不同 dtype
的 Tensor 之间进行计算,MegEngine 将进行类型提升来满足计算要求:
>>> a - b.astype("int8")
Tensor([-3 -3 -3], dtype=int16, device=xpux:0)
注意到数据类型为 uint8
的 a
与数据类型为 int8
的 b
进行计算,
最终得到了一个数据类型为 int16
的 Tensor.
使用内置函数创建 Tensor#
备注
MegEngine 的
functional
子包内置了多个创建 Tensor 的函数(位于 creation );使用这些函数创建的 Tensor 默认数据类型为
float32
.
根据它们所创建的 Tensor 的维数,这些函数大致上可以分为三类:
创建 1 维 Tensor#
创建 1 维 Tensor 的函数如 arange
和 linspace
通常需要至少两个输入,即 start
和 stop
.
arange
将创建具有规律递增值的 Tensor, 下面显示了一些用法:
>>> megengine.functional.arange(10)
Tensor([0. 1. 2. 3. 4. 5. 6. 7. 8. 9.], device=xpux:0)
>>> megengine.functional.arange(2, 10, dtype="float")
Tensor([2. 3. 4. 5. 6. 7. 8. 9.], device=xpux:0)
>>> megengine.functional.arange(2, 3, 0.1)
Tensor([2. 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9], device=xpux:0)
使用该函数得到的 Tensor 中的值不包括终点 stop
, 即范围为 [start, stop)
.
linspace
将创建具有指定数量元素的 Tensor, 并在指定的开始值和结束值之间等距间隔。例如:
>>> megengine.functional.linspace(1., 4., 6)
Tensor([1. 1.6 2.2 2.8 3.4 4. ], device=xpux:0)
使用这个函数的好处是可以保证 Tensor 中元素的数量、值的起点和终点。
备注
在 NumPy 中使用 arange
的最佳实践是使用整型的 start
, stop
和 step
值。
这是由于机器表示浮点数时存在着舍入误差,向 arange
传入非整数值时有可能得到非预期结果:
>>> np.arange(7.8, 8.4, 0.05)
array([7.8 , 7.85, 7.9 , 7.95, 8. , 8.05, 8.1 , 8.15, 8.2 , 8.25, 8.3 ,
8.35, 8.4 ])
在 NumPy 中由于浮点误差的累积,最终的结果中将会看到 8.4
这个值。
而在 MegEngine 中,arange
内部调用了 linspace
进行实现,此时得到的结果与 NumPy 不同:
>>> megengine.functional.arange(7.8, 8.4, 0.05)
Tensor([7.8 7.85 7.9 7.95 8. 8.05 8.1 8.15 8.2 8.25 8.3 8.35], device=xpux:0)
创建 2 维 Tensor#
创建 2 维 Tensor 的函数通常以表示为二维数组的特殊矩阵的属性来定义。
例如 eye
定义了一个 2 维单位矩阵,行索引和列索引相等的元素为 1, 其余为 0, 如下所示:
>>> megengine.functional.eye(3)
Tensor([[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]], device=xpux:0)
>>> megengine.functional.eye(3, 5)
Tensor([[1. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0.]], device=xpux:0)
创建 n 维 Tensor#
此类函数如 ones
, zeros
通常可以根据给定的形状创建 Tensor.
>>> megengine.functional.zeros((2, 3))
Tensor([[0. 0. 0.]
[0. 0. 0.]], device=xpux:0)
>>> megengine.functional.zeros((2, 3, 2))
Tensor([[[0. 0.]
[0. 0.]
[0. 0.]]
[[0. 0.]
[0. 0.]
[0. 0.]]], device=xpux:0)
参见
本质上它们都是通过调用
full
来实现创建满足给定形状和值的 Tensor;使用
zeros_like
,ones_like
,full_like
根据输入 Tensor 形状进行创建。
使用 random 子包随机生成#
例如使用 normal
可以从服从正态分布的随机变量中采样:
>>> a = megengine.random.normal(100, 1, (5,))
Tensor([ 99.8308 101.949 100.2816 101.8977 99.9773], device=xpux:0)
使用 uniform
可以从服从均匀分布的随机变量中采样:
>>> megengine.random.uniform(10, 20, (5,))
Tensor([12.557 17.8996 10.0152 18.2324 11.2644], device=xpux:0)
参见
Python 的
random
标准库文档 – Generate pseudo-random numbersNumPy 的随机采样官方文档 —— Random sampling
MegEngine 所有随机数生成相关 API 都列举在
random
页面。
基于现有的 Tensor 进行操作#
备注
使用 copy
函数可以拷贝一个 Tensor.
参见
更多具体内容请参考 如何对 Tensor 进行操作 页面。
将 NumPy ndarray 转化为 MegEngine Tensor#
我们也能够通过 Tensor
, 将 ndarray 作为输入数据传入,得到对应的 Tensor.
>>> a = np.array([1, 2, 3])
>>> a.dtype
dtype('int64')
>>> b = megengine.Tensor(a)
>>> Tensor([1 2 3], dtype=int32, device=xpux:0)
Tensor([1 2 3], dtype=int32, device=xpux:0)
通过 Tensor 的 numpy
方法,我们可以得到 Tensor 转为 ndarray 后的结果:
>>> b.numpy()
array([1, 2, 3], dtype=int32)
参见
相关注意事项如数据类型等,与 将 Python 序列转换为 Tensor 一致。