304 Chapter 9. 人工神经网络和神经语言建模 肖桐 朱靖波
9.3 神经网络的张量实现
在神经网络内部,输入经过若干次变换,最终得到输出的结果。这个过程类
于一种逐层的数据“流动”不禁会产生这样的疑问:在神经网络中,数据是以哪种
形式“流动”的?如何去编程实现这种数据“流动”呢?
为了解决上面的问题,本节将介绍人工神经网络更加通用的描述形式
——
张量
计算。随后也会看到,使用基于张量的数学工具,可以方便的搭建神经网络。
9.3.1 张量及其计算
1. 张量
对于神经网络中的某层神经元 y = f(xW+b)其中 W 是权重矩阵,例如
1 2
3 4
!
b 是偏置向量,例如 (1,3)在这里,输入 x 和输出 y可以不是简单的向量或是矩阵
形式,而是深度学习中更加通用的数学量
——
张量Tensor),比如公式(9.31)中的
几种情况都可以看作是深度学习中定义数据的张量:
x =
1 3
x =
1 3
0.2 2
!
x =
1 3
0.2 2
!
1 3
0.2 2
!
(9.31)
简单来说,张量是一种通用的工具,用于描述由多个数据构成的量。比如,输入
的量有三个维度在变化,用矩阵不容易描述,但是用张量却很容易。
从计算机实现的角度来看,现在所有深度学习框架都把张量定义为“多维数组”
张量有一个非常重要的属性
——
Rank可以将多维数组中“维”的属性与张
量的“阶”的属性作类比,这两个属性都表示多维数组(张量)有多少个独立的
向。例如,3 是一个标量,相当于一 0 维数组或 0 张量;(
2 3 0.8 0.2
)
T
是一个向量,相当于一个 1 维数组或 1 阶张量;
1 3 7
0.2 2 9
!
是一个矩阵,相当于一
2 维数组或 2 阶张量;如图9.23所示,这是一个 3 维数组或 3 阶张量,其中,每个
3 ×3 的方形代表一个 2 阶张量,这样的方形有 4 个,最终形成 3 阶张量。
虽然这里所使用的张量是出于编程实现的视角,但是数学中张量有严格的定义。
从数学上看“张量并不是向量和矩阵的简单扩展,多维数组也并不是张量所必须
表达形式”。从某种意义上说,矩阵才是张量的扩展。当然,这个逻辑可能和人们在
深度学习中的认知是不一致的。但是,本书仍然遵循深度学习中常用的概念,把
量理解为多维数组。在保证数学表达的简洁性的同时,使程序实现接口更加统一。
9.3 神经网络的张量实现 305
4
5
6
7
8
9
10
11 12
9.23 3 阶张量示例(4 × 3 × 3
2. 张量的矩阵乘法
对于一个单层神经网络,y = f(xW + b) 中的 xW 表示对输入 x 进行线性变换,
x 是输入张量,W 是权重矩阵。xW 表示的是矩阵乘法,需要注意的是这里是矩阵
乘法而不是张量乘法。
张量乘以矩阵是怎样计呢?可以先回忆一下9.2.1的线性代的知识。假
A m ×p 的矩阵,B p ×n 的矩阵, A B 作矩阵乘积的结果是一个 m ×n
矩阵 C,其中矩阵 C 中第 i 行、第 j 列的元素可以表示为:
(AB)
ij
=
p
X
k=1
a
ik
b
kj
(9.32)
例如 A =
a
11
a
12
a
13
a
21
a
22
a
23
!
B =
b
11
b
12
b
21
b
22
b
31
b
32
,两矩阵做乘法运算的过程如下:
C = AB
=
a
11
b
11
+ a
12
b
21
+ a
13
b
31
a
11
b
12
+ a
12
b
22
+ a
13
b
32
a
21
b
11
+ a
22
b
21
+ a
23
b
31
a
21
b
12
+ a
22
b
22
+ a
23
b
32
!
(9.33)
将矩阵乘法扩展到高阶张量中:一个张量 x 若要与矩阵 W 做矩阵乘法,则 x
最后一维度需要与 W 的行数大小相等,即:若张量 x 的形状为 ·×nW 须为 n ×·
的矩阵。下式是一个例子:
x(1 : 4, 1 : 4,1 : 4) × W(1 : 4,1 : 2) = s(1 : 4,1 : 4, 1 : 2) (9.34)
其中,张量 x 沿第 1 阶所在的方向与矩阵 W 进行矩阵运算(张量 x 1 阶的每个维
度都可以看做一个 4 ×4 的矩阵)9.24演示了这个计算过程。张量 x 中编号为¬
子张量(可看作矩阵)与矩阵 W 进行矩阵乘法,其结果对应张量 s 中编号为¬的子
306 Chapter 9. 人工神经网络和神经语言建模 肖桐 朱靖波
张量。这个过程会循环四次,因为有四个这样的矩阵(子张量)。最终,图9.24给出
了结果张量的形式(4 ×4 ×2
¬
®
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19
x
¯
1
0
1
0
0
1
1
0
W
矩阵乘
¬
®
2 1
2 1
2 1
2 1
¯
xW
=
9.24 张量与矩阵的矩阵乘法
3. 张量的单元操作
对于神经网络中的某层神经 y = f(xW + b)也包含有其他张量单元操作:1
加法:s + b,其中张量 s = xW2)激活函数:f(·)。具体来说:
s + b 中的就是的每都进法。在上 s 形状
(1 : 4,1 : 4,1 : 2) 3 阶张量, b 是含有 4 个元素的向量,在形状不同的情况下
是怎样进行单元加的呢?在这里需要引入广播机制Broadcast Mechanism
果两个数组的后缘维度(即从末尾开始算起的维度)的轴长度相符或其中一方
的长度为 1,则认为它们是广播兼容的。广播会在缺失或长度为 1 的维度上进
行,它是深度学习框架中常用的计算方式。来看一个具体的例子,如图9.25
示,s 是一个 2 ×4 的矩阵而 b 是一个长度为 4 的向量,这两者进行单元加运算
时,广播机制会将 b 沿第一个维度复制后,再与 s 做加法运算。
1 2 3 4
5 6 7 8
s
(a) 张量 s
1 1 1 1
b
(b) 张量 b
1 2 3 4
5 6 7 8
s
1 1 1 1
1 1 1 1
+
b
(c) 张量的单元加运算
2 3 4 5
6 7 8 9
=
s + b
9.25 广播机制
除了单元加之外,张量之间也可以使用减法操作、乘法操作。此外也可以对张
量作激活操作,这里将其称作为函数的向量化Vectorization例如,对向量
9.3 神经网络的张量实现 307
1 阶张量)作 ReLU 激活,ReLU 激活函数表达式如下:
f(x) =
0
x
0
x x > 0
(9.35)
例如 ReLU
2
.3
!!
=
2
0
!
9.3.2 张量的物理存储形式
在深度学习世界中,张量就是多维数组。因此,张量的物理存储方式也与多
数组相同。如下就是一些实例:
张量 t(1 : 3) 表示一个含有三个元素的向量1 阶张量)其物理存储如图9.26(a)
所示。
张量 t(1 : 2,1 : 3) 表示一个 2×3 的矩阵2 阶张量)其物理存储如图9.26(b)
示。
张量 t(1 : 2, 1 : 2, 1 : 3) 表示一个大小 2×2×3 3 阶张量,其物理存储如图9.26(c)
所示。
1 2 3
(a)1
阶张量
1 2 3 4 5 6
(b)2
阶张量
1 2 3 4 5 6 7 8 9 10 11 12
2
×
3
子张量
2
×
3
子张量
(c)3
阶张量
9.26 不同阶的张量的物理存储方式
实际上,高阶张量的物理存储方式也与多维数组在 C++Python 中的物理存
方式相同。
9.3.3 张量的实现手段
实现神经网络的开源系统有很多,比如,使用经典的 Python 工具包 Numpy
可以使用成熟的深度学习框架,比如,Tensorflow Pytorch 就是非常受欢迎的深度
学习工具包,除此之外还有很多其他优秀的框架:CNTKMXNetPaddlePaddle
KerasChainerdl4jNiuTensor 等。开发者可以根据自身的喜好和开发项目的要求
选择所采用的框架。
308 Chapter 9. 人工神经网络和神经语言建模 肖桐 朱靖波
这里以 NiuTensor 为例对张量计算库进行简单介绍。这类库需要提供张量计算接
口,如张量的声明、定义和张量的各种代数运算,各种单元算子,如 +/
Log (取对数)Exp (指数运算)Power(幂方运算)Absolute(绝对值)等,还
SigmoidSoftmax 激活函数。除了上述单元算子外,张量计算库还支持张量
间的高阶运算,其中最常用的是矩阵乘法。表9.2 展示了一些常用的函数。
9.2 NiuTensor 支持的部分函数
函数 描述
a.Reshape(o,s) 把张量 a 变换成阶为 o、形状为 s 的张量
a.Get(pos) 取张量 a 中位置为 pos 的元素
a.Set(v,pos) 把张量 a 中位置为 pos 的元素值设为 v
a.Dump(file) 把张量 a 存到 file 中,file 为文件句柄
a.Read(file) file 中读取张量 afile 为文件句柄
Power(a,p) 计算指数 a
p
Linear(a,s,b) 计算 a s + bs b 都是一个实数
CopyValue(a) 构建张量 a 的一个拷贝
ReduceMax(a,d) 对张量 a 沿着方向 d 进行规约,得到最大值
ReduceSum(a,d) 对张量 a 沿着方向 d 进行规约,得到和
Concatenate(a,b,d) 把两个张量 a b 沿 d 方向级联
Merge(a,d) 对张量 a 沿 d 方向合并
Split(a,d,n) 对张量 a 沿 d 方向分裂成 n
Sigmoid(a) 对张量 a 进行 Sigmoid 变换
Softmax(a) 对张量 a 进行 Softmax 变换,沿最后一个方向
HardTanh(a) 对张量 a 进行 HardTanh 变换(双曲正切的近似)
Rectify(a) 对张量 a 进行 ReLU 变换
9.3.4 前向传播与计算图
有了张量这个工具,可以很容易地实现任意的神经网络。反过来,神经网络
可以被看作是张量的函数。一种经典的神经网络计算模型是:给定输入张量,各
神经网络层逐层进行张量计算之后,最后得到输出张量。这个过程也被称作前向传播
Forward Propagation,它常常被应用在使用神经网络对新的样本进行推断中。
来看一个具体的例子,9.27展示了一个根据天气情况判断穿衣指数(穿衣指数
是人们穿衣薄厚的依据)的过程,将当天的天空状况、低空气温、水平气压作为
入,通过一层神经元在输入数据中提取温度、风速两方面的特征,并根据这两方
9.3 神经网络的张量实现 309
的特征判断穿衣指数。需要注意的是,在实际的神经网络中,并不能准确地知道
经元究竟可以提取到哪方面的特征,以上表述是为了让读者更好地理解神经网络
建模过程和前向传播过程。这里将上述过程建模为如图9.27所示的两层神经网络。
b
[1]
偏置 1
b
11
x
1
天空状况
x
2
w
22
低空气温
x
3
w
32
水平气压
Tanh
P
温度
w
11
b
[2]
偏置 2
b
11
Tanh
P
风速
w
21
Sigmoid
P
穿衣指数
y
b
12
w
11
w
21
9.27 判断穿衣指数问题的神经网络过程
它可以被述为公式(9.36)中隐层的激活数是 Tanh 函数,输出的激
活函数是 Sigmoid 函数,W
[1]
b
[1]
分别表示第一层的权重矩阵和偏置,W
[2]
b
[2]
分别表示第二层的权重矩阵和偏置
4
y = Sigmoid(Tanh(xW
[1]
+ b
[1]
)W
[2]
+ b
[2]
) (9.36)
前向计算实现如图9.28所示,图中对各张量和其他参数的形状做了详细说明。
x = (x
1
,x
2
,x
3
) 1 ×3 量,其个维分别应天状况、空气温、
水平气压三个方面的数据。输入数据经过隐藏层的线性变换 xW
[1]
+b
[1]
Tanh 函数
的激活,得到新的张量 a = (a
1
,a
2
)其中 a
1
a
2
分别对应着从输入数据中提取出的
温度和风速两方面特征;神经网络在获取到天气情况的特征 a 后,继续对其进行线
性变换 aW
[2]
+ b
[2]
Sigmoid 函数的激活操作,得到神经网络的最终输出 y即神经
网络此时预测的穿衣指数。
9.28实际上是神经网络的一种计算图Computation Graph)表示。现在很多深
度学习框架都是把神经网络转化为计算图,这样可以把复杂的运算分解为简单的
算,称为算子Operator通过对计算图中节点的遍历,可以方便地完成神经网络的
计算。比如,可以对图中节点进行拓扑排序(由输入到输出)之后依次访问每个节
点,同时完成相应的计算,这也就实现了一个前向计算的过程。
使用计算图的另一个优点在于,这种方式易于参数梯度的计算。在后面的内
中会看到,计算神经网络中参数的梯度是模型训练的重要步骤。在计算图中,可以使
反向传播Backward Propagation的方式逐层计算不同节点上的梯度信息。9.4.2
4
注意这里 b
[1]
是向量而 b
[2]
是标量,因而前者加粗后者未加粗
310 Chapter 9. 人工神经网络和神经语言建模 肖桐 朱靖波
节会看到使用计算图这种结构可以非常方便、高效地计算反向传播中所需的梯度
息。
y
1 ×1
Sigmoid
1 ×1
ADD
1 ×1
MUL
1 ×2
a
W
[2]
b
[2]
2 ×1
1 ×1
1 ×2
Tanh
1 ×2
ADD
1 ×2
MUL
1 ×3
x
W
[1]
b
[1]
3 ×2
1 ×2
9.28 前向计算示例(计算图)