神经网络的数学基础:张量运算

回顾上一篇 神经网络的数学基础 :张量和梯度
通过上一篇的内容,我们知道了张量表示神经网络中的数据,那么数据在网络中流动必然要经过各种运算或者叫做处理,这一系列的处理就是达到最终结果的过程。可以形象把中间的变换称为神经网络的“齿轮”,或者叫做张量运算。就像二进制运算有逻辑与(AND),或(OR),异或(NOR)一样,张量运算有以下几种:

  1. 逐元素运算
  2. 张量点积
  3. 广播
  4. 张量变形
1. 逐元素运算

relu运算和加法(减法)都是逐元素(element-wise)的运算,即该运算独立地应用于张量中的每个元素。如果你想对逐元素运算编写简单的Python 实现,那么可以用for循环,但是一般都使用Numpy封装好的函数,这也是Numpy功能强大的一个原因。示例:

>>> import numpy as np
>>> x = np.array([[1,2,3],[4,5,6]])
>>> x.shape
(2, 3)
>>> y = np.array([[1,1,1],[2,2,2]])
>>> y.shape
(2, 3)
>>> z = x + y
>>> z
array([[2, 3, 4],
       [6, 7, 8]])
>>> z.shape
(2, 3)
>>> z = x - y
>>> z
array([[0, 1, 2],
       [2, 3, 4]])
>>> z.shape
(2, 3)
>>> z = y - x
>>> z
array([[ 0, -1, -2],
       [-2, -3, -4]])
>>> z.shape
(2, 3)
2. 张量点积

点积运算,也叫张量积(tensor product,不要与逐元素的乘积弄混),是最常见也最有用的张量运算。与逐元素的运算不同,它将输入张量的元素合并在一起。
在Numpy、Keras、Theano 和TensorFlow 中,都是用* 实现逐元素乘积。TensorFlow 中的点积使用了不同的语法,但在Numpy 和Keras 中,都是用标准的dot 运算符来实现点积。

import numpy as np
z = np.dot(x, y)

数学符号中的点(.)表示点积运算。
z=x.y

示例如下:

>>> import numpy as np
>>> x = np.array([[1,2,3],[4,5,6]])
>>> x.shape
(2, 3)
>>> y = np.array([[1,1,1],[2,2,2],[3,3,3]])
>>> y.shape
(3, 3)
>>> z = np.dot(x,y)
>>> z
array([[14, 14, 14],
       [32, 32, 32]])
>>> z.shape
(2, 3)
3. 广播

上一节所说的加减法仅支持两个形状相同的张量相加。如果将两个形状不同的张量相加,会发生什么?如果没有歧义的话,较小的张量会被广播(broadcast),以匹配较大张量的形状。广播包含以下两步。
(1) 向较小的张量添加轴(叫作广播轴),使其ndim 与较大的张量相同。
(2) 将较小的张量沿着新轴重复,使其形状与较大的张量相同。

举例,下图可以形象说明广播是怎么进行的。
图3-1

>>> x = np.array([[1, 2], [3, 4]])
>>> y = np.array([10])
>>> x * y
array([[10,20],
     [30,40]])

再举一例:
图3-2

>>> x = np.array([[1, 2], [3, 4]])
>>> y = np.array([10,20])
>>> x * y
array([[10,40],
     [30,80]])
4. 张量变形

第四个重要的张量运算是张量变形(tensor reshaping)。张量变形是指改变张量的行和列,以得到想要的形状。变形后的张量的元素总个数与初始
张量相同。简单的例子可以帮助我们理解张量变形。

>>> x = np.array([[0., 1.],
                [2., 3.],
                [4., 5.]])
>>> print(x.shape)
(3, 2)
>>> x = x.reshape((6, 1))
>>> x
array([[ 0.],
    [ 1.],
    [ 2.],
    [ 3.],
    [ 4.],
    [ 5.]])
>>> x = x.reshape((2, 3))
>>> x
    array([[ 0., 1., 2.],
    [ 3., 4., 5.]])

经常遇到的一种特殊的张量变形是转置(transposition)。对矩阵做转置是指将行和列互换,比如:使x[i, :] 变为x[:, i]。

>>> x = np.zeros((300, 20))
>>> x = np.transpose(x)
>>> print(x.shape)
(20, 300)

小结一下,张量运算:

运算 Numpy对应操作
逐元素运算 +,-,np.maximum
张量点积 np.dot
广播 操作自带支持
张量变形 reshape, np.transpose

介绍上面的张量基本运算是为了使学习神经网络容易一些,至此,介绍完了基本运算。

5、神经网络的内积

简单来说,输入与权重的点积就是神经网络的内积,没有考虑激活函数。
先看一个小例子,我们来计算一下,在神经网络学习中可以看到如下图所示的表达:
图5-1

x代表输入用一个1维数组表示,y代表输出,也是一个1维数组,直线上的数字代表权重W,用2乘以3的矩阵来表示,这是一个最简单的神经网络,可以用下述代码来表示表示内积

>>> X = np.array([1, 2])
>>> X.shape
(2,)
>>> W = np.array([[1, 3, 5], [2, 4, 6]])
>>> print(W)
[[1 3 5]
[2 4 6]]
>>> W.shape
(2, 3)
>>> Y = np.dot(X, W)
>>> print(Y)
[ 5 11 17]

我们把上面的例子引伸一下,并做一些符号上的约定,,以便公式推导。
图5-2

这是一个3层神经网络结构,输入X为第0层,有两个隐藏层,最后输出算一层,共3层。
权重和隐藏层的神经元的右上角有一个“(1)”,它表示权重和神经元的层号(即第1层的权重、第1层的神经元)。此外,权重的右下角有两个数字,它们是后一层的神经元和前一层的神经元的索引号。比如,表示前一层的第2个神经元x2 到后一层的第1个神经元的权重。权重右下角按照“后一层的索引号、前一层的索引号”的顺序排列,即后前顺序,如下图所示:
图5-3

上面的神经网络还增加了表示偏置的神经元“1”。请注意,偏置的右下角的索引号只有一个。这是因为前一层的偏置神经元(神经元“1”)只有一个。为了确认前面的内容,现在用数学式表示。通过加权信号和偏置的和按如下方式进行计算。

a 1 ( 1 ) = w 1 1 1 x 1 + w 1 2 1 x 2 + b 1 1 a_1^{(1)} = w{_1}{_1}{^1}x_1 + w{_1}{_2}{^1}x_2 + b_1^{1}

此外,如果使用矩阵的乘法运算,则可以将第1 层的加权和表示成下面的式。

A 1 = X W 1 + B 1 A^{1} = XW^{1} + B^{1}
其中,A(1)、X、B(1)、W(1)如下所示。

A 1 = ( a 1 ( 1 )    a 2 ( 1 )    a 3 ( 1 ) ) ,     X = ( x 1 ,    x 2 ) ,     B ( 1 ) = ( b 1 ( 1 )    b 2 ( 1 )    b 3 ( 1 ) ) A^{1} = (a_1^{(1)} ~~ a_2^{(1)} ~~ a_3^{(1)}), ~~~ X=(x1,~~ x2), ~~~ B^{(1)} = (b_1^{(1)} ~~ b_2^{(1)} ~~ b_3^{(1)})

W ( 1 ) = ( w 11 ( 1 ) w 21 ( 1 ) w 31 ( 1 ) w 12 ( 1 ) w 22 ( 1 ) w 32 ( 1 ) ) W^{(1)} = \begin{pmatrix}{w_{11}^{(1)}}&w_{21}^{(1)}&{w_{31}^{(1)}}\\ {w_{12}^{(1)}}&w_{22}^{(1)}&{w_{32}^{(1)}}\\ \end{pmatrix}
下面我们用NumPy多维数组来实现,这里将输入信号、权重、偏置设置成任意值。

X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])
print(W1.shape) # (2, 3)
print(X.shape) # (2,)
print(B1.shape) # (3,)
A1 = np.dot(X, W1) + B1

这个运算和上一节进行的运算是一样的。W1是2 × 3 的数组,X是元素个
数为2 的一维数组。这里,W1和X的对应维度的元素个数也保持了一致。

至此,我们已经把神经网络的一层的计算公式作了简单推导,大家看到还少了激活函数,下一篇继续在讲解 激活函数 后,继续完善上面的推导。

继续下一篇对阅读 激活函数的理解和实现-最新整理

发布了36 篇原创文章 · 获赞 42 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_28710515/article/details/89283154
今日推荐