标量的运算
实数的四则运算加减乘除, 整除, 取余, 幂运算
TensorFlow 实现
加减乘除: tf.math.add(a,b)
$+$, tf.math.subtract(a,b)
$-$, tf.math.multiply(a,b)
$\times$, tf.math.divide(a,b)
$\div$
整除: $//$
取余: tf.math.mod(a,b)
$%$
幂运算: tf.math.pow(x, a)
$**$ $x^a$ 平方: tf.square(x)
开方: tf.math.pow(x, 1/a)
$**$ $\sqrt[a]x$ 平方根: tf.sqrt(x)
指数运算: tf.math.pow(a, x)
$**$ $a^x$ 自然指数 $e^x$ tf.exp(x)
对数运算: 自然对数: $log_e(x)$ tf.math.log(x)
其他对数: $log_a(x)=\frac{log_e(x)}{log_e(a)}$
正负数符号: tf.math.sign(a)
绝对值: tf.math.abs(a)
倒数: tf.math.inv(a)
向量的运算
向量与标量乘法
除法相当于乘以倒数, 向量方向不变, 扩大/缩小距离.
$$
k\begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix}=
\begin{bmatrix}kx_1\\kx_2\\kx_3\end{bmatrix}
$$
向量与向量的点乘
结果是标量, 用于描述两个向量的相似度.
$$
\begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix}
\cdot
\begin{bmatrix}y_1\\y_2\\y_3\end{bmatrix}
= x_1y_1+x_2y_2+x_3y_3
$$
向量与向量的叉乘
$$
\begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix}
\times
\begin{bmatrix}y_1\\y_2\\y_3\end{bmatrix}
=
\begin{bmatrix}x_2y_3-x_3y_2\\x_3y_1-x_1y_3\\x_1y_2-x_2y_1\end{bmatrix}
$$
参考: 向量运算
矩阵的运算
矩阵与标量乘法
$$
kM
=
k\begin{bmatrix}
m_{11} & m_{12} & m_{13} \\
m_{21} & m_{22} & m_{23} \\
m_{31} & m_{32} & m_{33}
\end{bmatrix}
=
\begin{bmatrix}
km_{11} & km_{12} & km_{13} \\
km_{21} & km_{22} & km_{23} \\
km_{31} & km_{32} & km_{33}
\end{bmatrix}
$$
矩阵与矩阵乘法
rxn
矩阵 A 与一个 nxc
矩阵 B 相乘,则得到一个 rxc
矩阵 C.
$$
AB =
\begin{bmatrix}
a_{11} & a_{12} \\
a_{21} & a_{22} \\
a_{31} & a_{32}
\end{bmatrix}
\begin{bmatrix}
b_{11} & b_{12} & b_{13} & b_{14} \\
b_{21} & b_{22} & b_{23} & b_{24}
\end{bmatrix}
\\ =
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21} & a_{11}b_{12} + a_{12}b_{22} & a_{11}b_{13} + a_{12}b_{23} & a_{11}b_{14} + a_{12}b_{24} \\
a_{21}b_{11} + a_{22}b_{21} & a_{21}b_{12} + a_{22}b_{22} & a_{21}b_{13} + a_{22}b_{23} & a_{21}b_{14} + a_{22}b_{24} \\
a_{31}b_{11} + a_{32}b_{21} & a_{31}b_{12} + a_{32}b_{22} & a_{31}b_{13} + a_{32}b_{23} & a_{31}b_{14} + a_{32}b_{24}
\end{bmatrix}
\\ =
\begin{bmatrix}
c_{11} & c_{12} & c_{13} & c_{14} \\
c_{21} & c_{22} & c_{23} & c_{24} \\
c_{31} & c_{32} & c_{33} & c_{34}
\end{bmatrix}
= C
$$
每个元素的值算法
$$c_{ij}=\sum_{k=1}^{n}a_{ik}b_{kj}$$
矩阵与向量乘法
向量是特殊的矩阵, 乘法符合矩阵与矩阵的乘法.
为了保持 $A_{r,n} \times B_{n,c}$ 相乘的关系, 行向量需要左乘矩阵, 列向量需要右乘矩阵.
行向量 * 矩阵
$$
行向量 \times 矩阵
=
\begin{bmatrix}
a_{11} & a_{12}
\end{bmatrix}
\begin{bmatrix}
b_{11} & b_{12} & b_{13} \\
b_{21} & b_{22} & b_{23}
\end{bmatrix}
=
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21} & a_{11}b_{12} + a_{12}b_{22} & a_{11}b_{13} + a_{12}b_{23}
\end{bmatrix}
$$
矩阵 * 行向量
$$
矩阵 \times 行向量
=
\begin{bmatrix}
a_{11} & a_{12} \\
a_{21} & a_{22} \\
a_{31} & a_{32}
\end{bmatrix}
\begin{bmatrix}
b_{11} \\
b_{21}
\end{bmatrix}
=
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21} \\
a_{21}b_{11} + a_{22}b_{21} \\
a_{31}b_{11} + a_{32}b_{21}
\end{bmatrix}
$$
横向量与列向量乘法
横向量与列向量均为特殊的矩阵, 横向量与列向量乘法可以看做是矩阵乘法.
行向量 * 列向量
$$
行向量 \times 矩阵
=
\begin{bmatrix}
a_{11} & a_{12}
\end{bmatrix}
\begin{bmatrix}
b_{11} \\
b_{21}
\end{bmatrix}
=
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21}
\end{bmatrix}
$$
参考: 矩阵运算
使用 Numpy 和 TensorFlow 对矩阵进行乘法运算
点乘(“*“) — 各个矩阵对应元素做乘法
$w$ 为 $m \times 1$ 矩阵, $X$ 为 $m \times n$ 矩阵
$$
Y = wX =
\begin{bmatrix}
w_11 \\
w_21
\end{bmatrix}
\begin{bmatrix}
x_11 & x_12 & x_13 \\
x_21 & x_22 & x_23
\end{bmatrix}
=
\begin{bmatrix}
w_11x_11 & w_11x_12 & w_11x_13 \\
w_21x_21 & w_21x_22 & w_21x_23
\end{bmatrix}
$$
$w$ 为 $m \times n$ 矩阵, $X$ 为 $m \times n$ 矩阵
$$
Y = wX =
\begin{bmatrix}
w_11 & w_12 & w_13\\
w_21 & w_22 & w_23
\end{bmatrix}
\begin{bmatrix}
x_11 & x_12 & x_13 \\
x_21 & x_22 & x_23
\end{bmatrix}
=
\begin{bmatrix}
w_11x_11 & w_12x_12 & w_13x_13 \\
w_21x_21 & w_22x_22 & w_23x_23
\end{bmatrix}
$$
$w$ 的列数只能为 1 或 与 x 的列数相等(即 n), $w$ 的行数与 x 的行数相等, 才能进行乘法运算.
矩阵乘 — 按照矩阵乘法规则做运算
$$
Y = wX =
\begin{bmatrix}
w_{11} & w_{12} \\
w_{21} & w_{22} \\
w_{31} & w_{32}
\end{bmatrix}
\begin{bmatrix}
x_{11} & x_{12} & x_{13} & x_{14} \\
x_{21} & x_{22} & x_{23} & x_{24}
\end{bmatrix}
\\ =
\begin{bmatrix}
w_{11}x_{11} + w_{12}x_{21} & w_{11}x_{12} + w_{12}x_{22} & w_{11}x_{13} + w_{12}x_{23} & w_{11}x_{14} + w_{12}x_{24} \\
w_{21}x_{11} + w_{22}x_{21} & w_{21}x_{12} + w_{22}x_{22} & w_{21}x_{13} + w_{22}x_{23} & w_{21}x_{14} + w_{22}x_{24} \\
w_{31}x_{11} + w_{32}x_{21} & w_{31}x_{12} + w_{32}x_{22} & w_{31}x_{13} + w_{32}x_{23} & w_{31}x_{14} + w_{32}x_{24}
\end{bmatrix}
$$
TensorFlow 高阶矩阵相乘
也就是张量 𝑨
和 𝑩
的维度数大于 2 时, 会选择 𝑨
和 𝑩
的最后两个维度进行矩阵相乘, 前面的所有维度视作 Batch 维度.
Batch 维度必须相同, 𝑨 的倒数第一个维度长度(列)和 𝑩 的倒数第二个维度长度(行)必须相等.
1 | # 前几位相同, a 倒数第一位 与 b 倒数第二位相同 |
Numpy 的写法
点乘
1 | import numpy as np |
矩阵乘
1 | import numpy as np |
TensorFlow 的写法
点乘法
1 | import tensorflow as tf |
矩阵乘法
1 | import tensorflow as tf |
参考: Python 之 numpy 和 tensorflow 中的各种乘法(点乘和矩阵乘)
维度变换
tf 基本的维度变换操作函数包含了 reshape 改变视图 , expand_dims 插入新维度 , squeeze 删除维度, transpose 交换维度, tile 复制数据, broadcast_to 形状扩张等, 其中 broadcast_to 往往可以自动进行.
$𝒀=𝑿@𝑾+𝒃$ 在计算过程中, $𝑿@𝑾$ 是 $m \times n$ 维张量, $𝒃$ 是 $n$ 维向量, 无法直接进行 +
运算.
将 shape = [1,n]
的 bias 偏置 $𝒃 = \begin{bmatrix} b_1 & b_2 & b_3 \end{bmatrix}$ 的样本数复制扩展到 shape = [m,n]
$𝒃 = \begin{bmatrix} b_1 & b_2 & b_3 \ b_1 & b_2 & b_3 \end{bmatrix}$
$$
𝒀=𝑿@𝑾+𝒃 \\
=
𝑿@𝑾
+
\begin{bmatrix} b_1 & b_2 & b_3 \end{bmatrix} \\
=
𝑿@𝑾
+
\begin{bmatrix} b_1 & b_2 & b_3 \ b_1 & b_2 & b_3 \end{bmatrix} \\
=
\begin{bmatrix} x_{11} & x_{12} & x_{13} \ x_{21} & x_{22} & x_{23} \ \end{bmatrix}
+
\begin{bmatrix} b_1 & b_2 & b_3 \ b_1 & b_2 & b_3 \end{bmatrix} \\
=
\begin{bmatrix} x_{11}+b_1 & x_{12}+b_2 & x_{13}+b_3 \ x_{21}+b_1 & x_{22}+b_2 & x_{23}+b_3 \ \end{bmatrix}
$$
通过 维度变换
满足了数学上矩阵相加需要 shape 一致的条件,又达到了给每个输入样本的输出节点共享偏置向量的逻辑.
视图 与 reshape 改变视图
在介绍改变视图 reshape 操作之前,我们先来认识一下张量的存储(Storage)和视图 (View)的概念。张量的视图就是我们理解张量的方式,比如 shape 为[2,4,4,3]的张量 𝑨,我 们从逻辑上可以理解为 2 张图片,每张图片 4 行 4 列,每个位置有 RGB 3 个通道的数据; 张量的存储体现在张量在内存上保存为一段连续的内存区域,对于同样的存储,我们可以 有不同的理解方式,比如上述张量 𝑨,我们可以在不改变张量的存储下,将张量 𝑨 理解为 2 个样本,每个样本的特征为长度 48 的向量。同一个存储,从不同的角度观察数据,可以产 生不同的视图,这就是存储与视图的关系。视图的产生是非常灵活的,但需要保证是合理。
在存储数据时,内存并不支持这个维度层级概念,只能以平铺方式按序写入内存,因此这 种层级关系需要人为管理. 为了方便表达,我们把张量 shape 列表中相对靠左侧的维度叫作大维度,shape 列表中相对靠右侧的维度叫作小维度.
1 | # 模拟生成张量, 将存储数据以 shape [2,4,4,3] 视图展示 |
数据的顺序不变, [b, h, w, c]
可以转化成 [b, hw, c]
, [b, hwc]
都可以说得通. 特殊的是, -1
表示前面确定了之后, 根据张量元素不变法则自动推导.
expend_dims 增加维度与 squeeze 删除维度
[h, w]
在最后增加一个维度 [h, w, 1]
, 存储不变, 表示某个通道, 视图显示变了.[h, w]
在最前增加一个维度 [1, h, w]
, 存储不变, 表示某张图片, 视图显示变了.
tf.expand_dims(x, axis)
, 增加维度, 其中 axis >=0 表示在指定的 axis 轴前增加维度, axis < 0 表示从右往左数第几个位置.
与增加维度一样,删除维度只能删除长度为 1 的维 度,也不会改变张量的存储.
tf.squeeze(x, axis)
删除 axis 位置的维度.
循环产出的时候,尽量从右向左判断删除,防止从左到右删除的时候,右面的维度索引变化
transpose 交换维度
改变视图、增删维度都不会影响张量的存储.
交换维度会影响数据的存储. 例如 [b, h, w, c]
到 [b, c, h, w]
的维度交换, 只提供 reshape 得到的数据是不合法的.
tf.transpose(x, new_order)
对原有维度进行交换. new_order 是原有顺序 0,1,2… 的重排 tf.transpose(x, [0,3,1,2])
tile 复制数据
使用 tf.tile(x,multiples=[times,...])
在某一个维度上进行数据的复制, times 表示结果是当前的几倍, 1 表示不复制. 例如 $shape [2,4] \times multiples [2,3] = shape [4,12]$ 第一维度是 2 倍, 第二位的是 3 倍.
tf.tile 会创建一个新的张量来保存复制后的张量,由于复制操作涉及大 量数据的读写 IO 运算,计算代价相对较高.
broadcasting 自动扩展机制
神经网络中不同 shape 之间的张量运算操作十分频繁, 使用 broadcasting 可以减少 tile 对数据的复制.
tf.broadcast_to(x, shape)
在一定的已知情况, 可以替代 tile 进行自动的数据复制. 复制机制为张量靠右对齐, 空维度以维度 1 补齐. 从右往左依次判断是否两个向量是否具有普适性, 维度为 1 或者维度相同表示具有普适性.
没有普适性无法使用 broadcasting 机制.