在深度学习中,我们经常会看到关于张量作为基础数据结构的讨论。
张量(Tensor)这个词甚至出现在谷歌旗舰机器学习库的名称中:“TensorFlow”。
张量是线性代数中使用的一种数据结构,与向量和矩阵一样,你可以对张量进行算术运算。
在本教程中,你将了解什么是张量,以及如何使用 Python 和 NumPy 来操作它们。
完成本教程后,您将了解:
- 张量是矩阵的推广,并使用n维数组来表示。
- 如何用张量实现逐元素运算。
- 如何执行张量积。
用我的新书《机器学习线性代数》开启你的项目,书中包含所有示例的分步教程和 Python 源代码文件。
让我们开始吧。
- 2019年10月更新:修正了数组索引名称中的拼写错误(感谢 Henry Chan)。

NumPy机器学习张量入门
照片由 Daniel Lombraña González 拍摄,保留部分权利。
教程概述
本教程分为3个部分;它们是
- 什么是张量?
- Python中的张量
- 逐元素的张量运算
- 张量积
在机器学习线性代数方面需要帮助吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
什么是张量?
张量是向量和矩阵的推广,可以很容易地理解为多维数组。
在一般情况下,一个按常规网格排列、具有可变数量轴的数字数组被称为张量。
— 第33页, 《深度学习》, 2016.
向量是一维或一阶张量,矩阵是二维或二阶张量。
张量表示法与矩阵表示法非常相似,用一个大写字母表示一个张量,用带下标整数的小写字母表示张量内的标量值。
1 2 3 |
t111, t121, t131 t112, t122, t132 t113, t123, t133 T = (t211, t221, t231), (t212, t222, t232), (t213, t223, t233) t311, t321, t331 t312, t322, t332 t313, t323, t333 |
许多可以对标量、向量和矩阵执行的运算,都可以重新定义为对张量执行。
作为一个工具,张量和张量代数被广泛应用于物理和工程领域。在机器学习中,它是一个已知的术语和技术集,深度学习模型的训练和操作可以用张量来描述。
Python中的张量
与向量和矩阵一样,张量可以在Python中使用N维数组(ndarray)来表示。
张量可以在 array() 构造函数中以内联方式定义为列表的列表。
下面的示例将一个3x3x3的张量定义为NumPy ndarray。三维更容易理解。在这里,我们首先定义行,然后是将行堆叠成列的列表,最后是将列堆叠成立方体中的层的列表。
1 2 3 4 5 6 7 8 9 |
# 创建张量 from numpy import array T = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) print(T.shape) print(T) |
运行该示例首先打印张量的形状,然后打印张量本身的值。
你可以看到,至少在三维情况下,张量被打印为一系列矩阵,每一层一个。对于这个3D张量,轴0指定层,轴1指定行,轴2指定列。
1 2 3 4 5 6 7 8 9 10 11 12 |
(3, 3, 3) [[[ 1 2 3] [ 4 5 6] [ 7 8 9]] [[11 12 13] [14 15 16] [17 18 19]] [[21 22 23] [24 25 26] [27 28 29]]] |
逐元素的张量运算
与矩阵一样,我们可以在张量之间执行逐元素的算术运算。
在本节中,我们将介绍四种主要的算术运算。
张量加法
两个具有相同维度的张量进行逐元素相加,会得到一个具有相同维度的新张量,其中每个标量值是父张量中标量的逐元素相加结果。
1 2 3 4 5 6 7 8 9 10 11 |
a111, a121, a131 a112, a122, a132 A = (a211, a221, a231), (a112, a122, a132) b111, b121, b131 b112, b122, b132 B = (b211, b221, b231), (b112, b122, b132) C = A + B a111 + b111, a121 + b121, a131 + b131 a112 + b112, a122 + b122, a132 + b132 C = (a211 + b211, a221 + b221, a231 + b231), (a112 + b112, a122 + b122, a132 + b132) |
在 NumPy 中,我们可以直接通过相加数组来添加张量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 张量加法 from numpy import array A = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) B = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) C = A + B print(C) |
运行该示例会打印两个父张量相加的结果。
1 2 3 4 5 6 7 8 9 10 11 |
[[[ 2 4 6] [ 8 10 12] [14 16 18]] [[22 24 26] [28 30 32] [34 36 38]] [[42 44 46] [48 50 52] [54 56 58]]] |
张量减法
从一个张量中逐元素减去另一个具有相同维度的张量,会得到一个具有相同维度的新张量,其中每个标量值是父张量中标量的逐元素相减结果。
1 2 3 4 5 6 7 8 9 10 |
a111, a121, a131 a112, a122, a132 A = (a211, a221, a231), (a112, a122, a132) b111, b121, b131 b112, b122, b132 B = (b211, b221, b231), (b112, b122, b132) C = A - B a111 - b111, a121 - b121, a131 - b131 a112 - b112, a122 - b122, a132 - b132 C = (a211 - b211, a221 - b221, a231 - b231), (a112 - b112, a122 - b122, a132 - b132) |
在 NumPy 中,我们可以直接通过相减数组来减去张量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 张量减法 from numpy import array A = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) B = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) C = A - B print(C) |
运行该示例会打印从第二个张量中减去第一个张量的结果。
1 2 3 4 5 6 7 8 9 10 11 |
[[[0 0 0] [0 0 0] [0 0 0]] [[0 0 0] [0 0 0] [0 0 0]] [[0 0 0] [0 0 0] [0 0 0]]] |
张量哈达玛积
一个张量与另一个具有相同维度的张量进行逐元素相乘,会得到一个具有相同维度的新张量,其中每个标量值是父张量中标量的逐元素相乘结果。
与矩阵一样,该运算被称为哈达玛积(Hadamard Product),以区别于张量乘法。在这里,我们将使用“o”运算符来表示张量之间的哈达玛积运算。
1 2 3 4 5 6 7 8 9 10 |
a111, a121, a131 a112, a122, a132 A = (a211, a221, a231), (a112, a122, a132) b111, b121, b131 b112, b122, b132 B = (b211, b221, b231), (b112, b122, b132) C = A o B a111 * b111, a121 * b121, a131 * b131 a112 * b112, a122 * b122, a132 * b132 C = (a211 * b211, a221 * b221, a231 * b231), (a112 * b112, a122 * b122, a132 * b132) |
在 NumPy 中,我们可以直接通过相乘数组来乘以张量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 张量哈达玛积 from numpy import array A = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) B = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) C = A * B print(C) |
运行该示例会打印张量相乘的结果。
1 2 3 4 5 6 7 8 9 10 11 |
[[[ 1 4 9] [ 16 25 36] [ 49 64 81]] [[121 144 169] [196 225 256] [289 324 361]] [[441 484 529] [576 625 676] [729 784 841]]] |
张量除法
一个张量与另一个具有相同维度的张量进行逐元素相除,会得到一个具有相同维度的新张量,其中每个标量值是父张量中标量的逐元素相除结果。
1 2 3 4 5 6 7 8 9 10 |
a111, a121, a131 a112, a122, a132 A = (a211, a221, a231), (a112, a122, a132) b111, b121, b131 b112, b122, b132 B = (b211, b221, b231), (b112, b122, b132) C = A / B a111 / b111, a121 / b121, a131 / b131 a112 / b112, a122 / b122, a132 / b132 C = (a211 / b211, a221 / b221, a231 / b231), (a112 / b112, a122 / b122, a132 / b132) |
在 NumPy 中,我们可以直接通过相除数组来除以张量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 张量除法 from numpy import array A = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) B = array([ [[1,2,3], [4,5,6], [7,8,9]], [[11,12,13], [14,15,16], [17,18,19]], [[21,22,23], [24,25,26], [27,28,29]], ]) C = A / B print(C) |
运行该示例会打印张量相除的结果。
1 2 3 4 5 6 7 8 9 10 11 |
[[[ 1. 1. 1.] [ 1. 1. 1.] [ 1. 1. 1.]] [[ 1. 1. 1.] [ 1. 1. 1.] [ 1. 1. 1.]] [[ 1. 1. 1.] [ 1. 1. 1.] [ 1. 1. 1.]]] |
张量积
张量积运算符通常用一个中间有一个小x的圆圈来表示。我们在这里用“(x)”来表示它。
给定一个q维张量A和一个r维张量B,这些张量的积将是一个阶为q + r的新张量,或者换句话说,是q + r维的。
张量积不仅限于张量,也可以对矩阵和向量进行运算,这是一个很好的练习起点,以便于培养对更高维度的直觉。
我们来看看向量的张量积。
1 2 3 4 5 6 7 8 |
a = (a1, a2) b = (b1, b2) c = a (x) b a1 * [b1, b2] c = (a2 * [b1, b2]) |
或者,展开来看
1 2 |
a1 * b1, a1 * b2 c = (a2 * b1, a2 * b2) |
我们来看看矩阵的张量积。
1 2 3 4 5 6 7 8 9 10 11 12 |
a11, a12 A = (a21, a22) b11, b12 B = (b21, b22) C = A (x) B b11, b12 b11, b12 a11 * (b21, b22), a12 * (b21, b22) C = [ b11, b12 b11, b12 ] a21 * (b21, b22), a22 * (b21, b22) |
或者,展开来看
1 2 3 4 |
a11 * b11, a11 * b12, a12 * b11, a12 * b12 a11 * b21, a11 * b22, a12 * b21, a12 * b22 C = (a21 * b11, a21 * b12, a22 * b11, a22 * b12) a21 * b21, a21 * b22, a22 * b21, a22 * b22 |
在 NumPy 中,可以使用 tensordot() 函数来实现张量积。
该函数接受两个要相乘的张量以及对乘积求和的轴作为参数,这被称为求和缩并。为了计算张量积,在 NumPy 中也称为张量点积,必须将轴设置为 0。
在下面的示例中,我们定义了两个一阶张量(向量)并计算了张量积。
1 2 3 4 5 6 7 |
# 张量积 from numpy import array from numpy import tensordot A = array([1,2]) B = array([3,4]) C = tensordot(A, B, axes=0) print(C) |
运行该示例会打印张量积的结果。
结果是一个阶为2的张量(矩阵),尺寸为2×2。
1 2 |
[[3 4] [6 8]] |
张量积是您可能遇到的最常见的张量乘法形式,但还存在许多其他类型的张量乘法,例如张量点积和张量缩并。
扩展
本节列出了一些您可能希望探索的扩展本教程的想法。
- 使用您自己的人为构造的小张量数据更新每个示例。
- 使用小的向量或矩阵数据实现本教程未涵盖的其他三种张量乘法。
- 编写您自己的函数来实现每个张量运算。
如果您探索了这些扩展中的任何一个,我很想知道。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
书籍
- 学生向量与张量指南, 2011.
- 第12章,专题,矩阵计算,2012。
- 工程师的张量代数与张量分析, 2015.
API
文章
其他
- 张量链格式下大规模数据分析的基本张量运算, 2016.
- 张量积,直和,量子力学 I, 2006。
- 张量恐惧症与外积, 2016.
- 张量积, 2011
总结
在本教程中,您了解了什么是张量,以及如何使用 Python 和 NumPy 对其进行操作。
具体来说,你学到了:
- 张量是矩阵的推广,并使用n维数组来表示。
- 如何用张量实现逐元素运算。
- 如何执行张量积。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
嗨,Jason!
非常棒、简单且详细地介绍了深度学习的关键数学工具之一。我认为任何张量领域的业余爱好者都可以轻松地从这里开始。
谢谢。
你好,Jason
这是一个非常棒的张量入门介绍。对于像我这样的初学者来说,阅读起来很快。非常有帮助。
很高兴它有帮助。
感谢您的博客,非常有帮助。但我有一个普遍性的问题。为什么我们在深度学习中需要张量?为什么不直接使用Numpy数组呢?
你可以用numpy数组开发自己的库。
张量只是矩阵的一种推广。
“给定一个q维张量A和一个r维张量B,这些张量的积将是一个阶为q + r的新张量,或者换句话说,是q + r维的。”
或许……应该是 q*r?
很好的教程,定义非常清晰。我认为张量点积可能是最棘手的运算符,因为你只提供了低维度的几个例子,但没有提供n阶乘m阶的通用公式。我认为如果能将张量与表示深度学习概念的用途联系起来,也会很有帮助。
谢谢,Victor。
谢谢你,总结得很好!
很高兴它有帮助。
内容不错,但希望你也能讲讲分解和其他内容。谢谢,写得很好。
你说的分解是什么意思?
你指的是矩阵分解吗?
https://machinelearning.org.cn/introduction-to-matrix-decompositions-for-machine-learning/
这与矩阵乘法完全不同。在矩阵中,维度被定义为 A mxn,其中矩阵 A 有 m 行和 n 列。
嗨,Jason!
我有一个关于张量转换的问题。我正在使用注意力机制,我必须在 for 循环中执行我的操作,所以我将结果存储在一个列表中。最后,我无法将列表转换为张量,以便将结果与全连接层连接起来。您能给我一些建议来解决这个问题吗?
列表或numpy数组都可以表示一个张量。
我想你可能指的是某个特定库的张量数据类型?或许可以查看该库的API,了解如何将列表和数组转换为该类型?
非常好的教程。
我不是数学专家,但是向量难道不是张量的一种特殊类型,而不是反过来吗?
谢谢。
不完全是,但也可以这样理解。
解释得很好。而且很容易理解!
谢谢,很高兴对您有帮助。
嗨,Jason,
您说“对于这个3D张量,轴0指定层,轴1指定列,轴2指定行。”
但我认为应该是
对于这个3D张量,轴0指定层,轴1指定行,轴2指定列。
A = array([
[[1,2,3], [4,5,6], [7,8,9]],
[[11,12,13], [14,15,16], [17,18,19]],
[[21,22,23], [24,25,26], [27,28,29]]
])
使用零索引,我们会有
print(A[0,0,0]) –> 1: 层 0, 行 0, 列 0
print(A[0,0,1]) –> 2: 层 0, 行 0, 列 1
print(A[0,1,0]) –> 4: 层 0, 行 1, 列 0
如果我错了请纠正我。
谢谢
谢谢。
也试试这个
打印结果
[1 2 3]
[1 4 7]
在所有的加法、减法、乘法和除法示例中,我看到这个
b111, b121, t131
B = (b211, t221, t231)
“t”应该是“b”吗?我完全是张量的新手,这是我第一次学习它。
看起来是个笔误,谢谢。
已修复。
谢谢。我仍然很困惑,因为其他解释提到张量具有额外的属性,而“它只是矩阵的推广”这个想法没有捕捉到这些属性。
“但是[广义矩阵]这种描述忽略了张量最重要的属性!
张量是一个存在于某个结构中的数学实体,并与其他数学实体相互作用。如果以一种规则的方式变换结构中的其他实体,那么张量必须遵循一个相关的变换规则。”
https://medium.com/@quantumsteinke/whats-the-difference-between-a-matrix-and-a-tensor-4505fbdc576c
对此不太确定…
或许可以和作者谈谈他的想法?
看来计算机科学家们从物理学家/数学家那里借用了这个术语,并将其重新定义为“多维数组”。Jason Brownlee 甚至引用了《深度学习》这本书来指出这一点。但你的困惑是合理的,因为这并不是物理学家使用的定义。
物理学家使用“张量”这个术语来指代一个几何对象,当坐标系改变时,它保持不变(即,它保留像长度、方向等属性)。
了解什么不是张量可能会有帮助。假设我们关注向量中的一个分量。当底层坐标系改变时,这个分量(一个0阶张量)会改变。所以单个分量不能是张量,即使它满足多维数组的定义。
要理解张量,我建议查看eigenchris的视频:https://www.youtube.com/watch?v=8ptMTLzV4-I&t=321s
很棒的注解,谢谢!
先生,如何用 for 循环来做那个求和?请解释一下?
什么求和?什么循环?
谢谢Jason!非常有趣。这篇教程帮助我理解了这些概念。非常直接,代码和图表用得很好。做得好!
谢谢!
有用的文章,但它没有描述张量在机器学习领域代表什么。它们代表训练数据、模型本身、两者,还是其他?
谢谢。
它们可以用来表示数据或模型系数,例如神经网络中的权重。
张量积,用这个 ⊗
谢谢。
在下面的例子中,我们定义了两个order-1张量(向量)并计算了张量积。
您能解释一下这里的“-1”是怎么来的吗?
应读作“order-one”(一阶),而不是负一。例如,一维的。
为什么要用张量?
因为这是我们可以将一组数字放在一起的方式。
非常感谢这篇教程。
最近我在处理一个问题,每个样本都是一个矩阵,例如10*10(所以数据集是一个维度为10*10*1000的张量)。
我想对这个数据集进行分类,但分类不是离散的。
所以这可能是一个回归问题。我不确定,而且我想预测一个矩阵(分类器的输出必须是一个矩阵)。
有什么资源、书籍等可以帮助我解决这个问题吗?
如果您能就此事提供指导,我将不胜感激。
非常感谢。
你好 Roz……虽然我不能直接针对你的应用发表意见,但你可能会对以下内容感兴趣
https://machinelearning.org.cn/softmax-activation-function-with-python/
机器学习中的这些“数据张量”实际上令人困惑,因为数学中的张量有更强的含义。在数学中,张量可以从1个或多个向量参数(理论上也可以是0个参数)以一种特定的方式(每个参数都是线性的)映射到一个向量空间。在实践中,我们可能使用表格通过乘法和加法来计算任何参数下张量的输出,但这并不意味着表格就是张量。张量本身实际上“包含”了所有输入和输出之间的所有映射。
当然,向量也可以是一个ndarray。Numpy中的Ndarrays在数学上是以元组为索引的向量。是矩阵积或张量积将某物变成了非平凡的张量(标量和列向量是平凡的张量)。我看到的ANN公式要么是一组矩阵(每层一个),要么是使用多维数字网格表示的矩阵,而不是像传统矩阵那样。我们也可以称之为线性代数和多维矩阵。(表格维度或Numpy轴的数量在数学张量中称为“阶”,或“模态数”。)超越经典矩阵乘法的情况是,当我们将滤波器由多个较小维度的滤波器组成时,在“数据张量”的多个维度上乘以一个滤波器。张量数学的主要好处是能高效地将多个线性运算一起计算。显然,这就是卷积神经网络所使用的。
Numpy中的tensordot积就像是即时将ndarrays类型转换为数学张量。因为tensordot实际上有第三个参数,它指定了左因子和右因子的哪些轴将被视为参数(在左侧)和参数(在右侧)。张量的函数应用在参数轴和相关参数轴之间使用标量积(逐元素乘积并求和)。矩阵是一种特殊情况,行轴为参数,列轴为参数。