神经元模型
神经元具有如下三个功能
1. 能够接收 n 个神经元模型传递过来的信号
2. 能够在信号的传递过程中为信号分配权重
3. 能够将得到的信号进行汇总、变换并输出
假设
(
ormalsize x_{1}),...,(
ormalsize x_{n}) 为 n 个神经元的输出信号
(
ormalsize w_{1}),...,(
ormalsize w_{n}) 为这 n 个信号对应的权值
(
ormalsize f) 为变换函数(也叫激活函数)
(
ormalsize y) 为神经元的输出
则有
(
ormalsize y = f(w_{1}x_{1} + ... + w_{n}x_{n} + b) = f(XW + b))
可以看到神经元模型是将输入信号进行加权求和,再进行偏移,再进行变换输出
如果 (
ormalsize f) 为恒同映射,既 (
ormalsize f(x)=x),则有 (
ormalsize y = XW + b)
可以看到此时神经元变成了线性回归方程,退化成了感知机
神经网络(Neural Network, NN)
许多神经元按照一定的层次结构进行连接即构成神经网络
一个非常自然的想法就是构建一个有向无环图(DAG 图)
遗憾的是现在我们对矩阵运算的依赖很大(因为矩阵运算是被高度优化了的)
所以目前主流的神经网络模型基本都是一类及其特殊的 DAG 图
神经网络是非线性模型
如下图
主流神经网络特点
以层(而不是以节点)为基本单位
一个输入层、多个变换层(也叫隐层)、一个输出层,一层接一层串行
每层由若干个并行的神经元模型组成
同一层的神经元使用相同的变换函数 (
ormalsize f),使用不同的权值 (
ormalsize w) 和偏移量 (
ormalsize b)
所以程序的实现是以层为基本单位而不是节点
每个神经元的输入是上一层所有神经元的输出
假设上一层第一个神经元输出 (
ormalsize x_{1}),第 n 个输出 (
ormalsize x_{n})
则下一层第 j 个神经元输出为
(
ormalsize y_{j} = f(x_{1}w_{j1} + … + x_{n}w_{jn} + b_{j}) = f(xw_{j} + b_{j}))
每个神经元的输出会同时作为下一层所有神经元的输入
输入层的神经元个数等于样本数据 X 的维度
且不用加权求和及偏移
只需变换,比如每条输入数据为 (
ormalsize (x_{1}, …, x_{n}))
则输入层需 n 个神经元,第 i 个神经元的输出为 (
ormalsize y_{i} = f(x_{i}))
输入层的变换函数通常取恒等变换 (
ormalsize f(x)=x) 然后和第一个变换层合成一个输入层
输出层的神经元个数可以等于样本数据 Y 的维度,或是分类总数
one-hot representation:每次只有一个神经元输出 1 代表某类别,其余输出 0
可以在输出层后加一个损失层,或合并到输出层,用于反向传播算法的第一步
变换层不一定要有,甚至输出层也不一定要有,可以只有一层同时作为输入和输出
神经网络算法包含如下三个部分
通过将输入进行一层一层的变换来得到输出(前向传导算法)
通过输出与真值的比较得到损失函数的梯度(损失函数)
利用得到的这个梯度来更新模型的各个参数(反向传播算法)
前向传导算法(Forward Propagation,FP)
将输入进行一层一层的变换来得到输出
符号约定
(
ormalsize L_{i}) 第 i 层
(
ormalsize n_{i}) 第 i 层的神经元个数
(
ormalsize f_{i}) 第 i 层的变换函数(激活函数)
(
ormalsize u_{i}) 第 i 层的输入
(
ormalsize v_{i}) 第 i 层的输出
(
ormalsize b_{i}) 第 i 层和第 i+1 层之间的偏移量,为 (
ormalsize (1, n_{i+1})) 维
(
ormalsize w_{i}) 第 i 层和第 i+1 层之间的权值矩阵,为 (
ormalsize (n_{i}, n_{i+1})) 维
比如第 i 层 3 个节点,第 i+1 层 5 个节点
则 (
ormalsize w_{i}) 维度为 (3, 5),(
ormalsize b_{i}) 维度为 (1, 5)
(
ormalsize w_{i}(n, m)) 代表第 i 层第 n 个神经元和第 i+1 层第 m 个神经元之间的权值
(
ormalsize w_{i}(:, m)) 代表第 i+1 层第 m 个神经元使用的权值向量
(
ormalsize b_{i}(1, m)) 代表第 i+1 层第 m 个神经元使用的偏移量
计算输出
假设样本集为 (X,Y)
第 1 层 (输入层)
(
ormalsize u_{1} = X)
(
ormalsize v_{1} = f_{1}(u_{1}))
其中
X 是 (m, n) 矩阵,m 是样本数据量,n 是样本维度
(
ormalsize f_{1}) 通常取恒同映射 (
ormalsize f_{1}(x) = x) 这样可以把输入层和第一个变换层合成一层
第 i 层 (包括输出层)
(large u_{i} = v_{(i-1)} w_{(i-1)} + b_{(i-1)})
(large v_{i} = f_{i}(u_{i}))
常见的激活函数及相应导数
逻辑函数 Sigmoid
(large f(x) = frac{1}{1+e^{-x}})
(large f^{'}(x) = frac{e^{-x}}{(1+e^{-x})^{2}}=f(x)(1-f(x)))
正切函数 Tanh
(large f(x) = tanh(x) = frac{1-e^{-2x}}{1+e^{-2x}})
(large f^{'}(x) = frac{4e^{-2x}}{(1+e^{-2x})^{2}} = 1 - f(x)^{2})
线性整流函数 (Rectified Linear Unit, ReLU)
(large f(x) = max(0,x))
(large f^{'}(x) =left{egin{matrix} 0 & & f(x)=0\1 & & f(x)
eq 0end{matrix}
ight.)
ELU 函数 (Exponential Linear Unit)
(large f(a,x) =left{egin{matrix}a(e^{x}-1) & & x<0\x & & xgeqslant 0end{matrix}
ight.)
(large f^{'}(a,x)=left{egin{matrix}f(a,x)+a& & x<0\1 & & xgeqslant 0end{matrix}
ight.)
Softplus
(large f(x) = ln(1+e^{x}))
(large f^{'}(x) = frac{e^{x}}{1+e^{x}} = 1 - frac{1}{e^{f(x)}})
恒同映射 (Identify)
(large f(x) = x)
(large f^{'}(x) = 1)
Softmax
(Large f(x) = frac{e^{x_{i}}}{sum_{j=1}^{n}e^{x_{j}}})
Softmax 被用于最后的输出层
用于多分类,每个节点的输出代表样本属于该分类的概率
可以看到对于一个样本,输出层所有节点的输出的和等于 1
(Large f^{'}(x) = (e^{x_{i}})^{'}(sum_{j=1}^{n}e^{x_{j}})^{-1} + (e^{x_{i}})((sum_{j=1}^{n}e^{x_{j}})^{-1})^{'} = f(x)(1-f(x)))
激活函数的一个作用是实现去线性化
对应函数图
损失函数(Cost Function/Loss Function)
假设把神经网络看做一个整体有 (
ormalsize y = G(x)) 则有以下几种常见损失函数
距离损失函数
(
ormalsize L(y,G(x)) = || y - G(x) ||^{2})
交叉熵 (Cross Entropy) 损失函数 (要求 G(x) 每一位的取值都在 (0,1) 中)
(
ormalsize L(y,G(x)) = -(y ln(G(x)) + (1-y) ln(1-G(x))))
log-likelihood 损失函数
(
ormalsize L(y,G(x)) = -ln(v_{k}))
要求 G(x) 是一个概率向量,向量的每个值 (
ormalsize v_{k}) 代表 x 属于分类 k 的概率
该损失函数是样本的实际分类在预测结果中出现的概率的负对数
通常和 Softmax 激活函数配合使用
考虑到梯度下降法的应用,我们还期望,损失函数在函数值比较大时,它对应的梯度也比较大(亦即更新参数的幅度也要比较大)
对神经网络而言,梯度下降可谓是训练的全部,至今没能出现能够与之抗衡的算法,最多只是研究出各式各样的梯度下降法的变体而已
反向传播算法 (Backpropagation, BP)
用于训练模型,利用梯度来更新结构中的参数以使得损失函数最小化,先从输出层开始,反向一层层更新
链式法则
设有
(large u = f(y)),(large y = g(x))
则有
(Large frac{partial u}{partial x} = frac{partial u}{partial y} cdot frac{partial y}{partial x})
注意
这里用的是点乘不是叉乘
如果是多元函数
(large u = f( y_{1} , ... , y_{i} , ... , y_{m} ))
(large = f( g_{1}(x_{1} , ... , x_{n}) , ... , g_{i}(x_{1} , ... , x_{n}) , ... , g_{m}(x_{1} , ... , x_{n}) ))
则有
(Large frac{partial u}{partial x_{j}} =sum_{i=1}^{m}frac{partial u}{partial y_{i}} cdot frac{partial y_{i}}{partial x_{j}})
通过梯度调整参数
第 i 层的第 q 个神经元的输入和输出为
(large u_{(i, q)} = sum_{p=1}^{n_{i-1}}v_{(i-1, p)} w_{(i-1, p, q)} + b_{(i-1, q)})
(large v_{(i, q)} = f_{i}(u_{(i, q)}))
定义第 i 层的第 q 个神经元的局部梯度为
(Large delta_{(i, q)}= frac{partial L}{partial u_{(i, q)}})
对最后一层(假设共 m 层)的第 q 个神经元和上一层的第 p 个神经元间的系数求导
(Large frac{partial L}{partial w_{(m-1, p, q)}} =frac{partial L}{partial u_{(m, q)}}cdot frac{partial u_{(m, q)}}{partial w_{(m-1, p, q)}}=delta_{(m, q)}cdot v_{(m-1, p)})
(Large frac{partial L}{partial b_{(m-1, q)}}= frac{partial L}{partial u_{(m, q)}}cdot frac{partial u_{(m, q)}}{partial b_{(m-1, q)}}= delta_{(m, q)})
其中
(Large delta_{(m, q)}=frac{partial L}{partial u_{(m, q)}}=frac{partial L}{partial v_{(m, q)}} cdot frac{partial v_{(m, q)}}{partial u_{(m, q)}}=frac{partial L}{partial v_{(m, q)}} cdot f_{m}^{'}(u_{(m, q)}))
对 i 层的第 q 个神经元和 i-1 层的第 p 个神经元间的系数求导
(Large frac{partial L}{partial w_{(i-1, p, q)}} =frac{partial L}{partial u_{(i, q)}}cdot frac{partial u_{(i, q)}}{partial w_{(i-1, p, q)}}=delta_{(i, q)}cdot v_{(i-1, p)})
(Large frac{partial L}{partial b_{(i-1, q)}} = frac{partial L}{partial u_{(i, q)}}cdot frac{partial u_{(i, q)}}{partial b_{(i-1, q)}}=delta_{(i, q)})
其中
(Large delta_{(i, q)}=frac{partial L}{partial u_{(i, q)}})
(Large =sum_{r=1}^{n_{i+1}}frac{partial L}{partial u_{(i+1, r)}} cdot frac{partial u_{(i+1, r)}}{partial u_{(i, q)}})
(Large =sum_{r=1}^{n_{i+1}}delta_{(i+1, r)}cdot frac{partial (sum_{h=1}^{n_{i}} w_{(i, h, r)}v_{(i, h)} + b_{(i, r)})}{partial u_{(i, q)}})
(Large =sum_{r=1}^{n_{i+1}}delta_{(i+1, r)}cdot frac{partial (sum_{h=1}^{n_{i}} w_{(i, h, r)}f_{i}(u_{(i, h)}) + b_{(i, r)})}{partial u_{(i, q)}})
(Large =sum_{r=1}^{n_{i+1}}delta_{(i+1, r)}cdot w_{(i, q, r)}cdot f_{i}^{'}(u_{(i, q)}))
这里采用多元函数的链式法则,因为 (
ormalsize u_{i}) 和 (
ormalsize u_{i+1}) 之间是一对多的关系
将所有系数合起来用矩阵表达,结合梯度下降法,学习率为 (
ormalsize eta),对于 m 层网络有
(large delta_{(m)} =frac{partial L}{partial v_{(m)}} cdot f_{m}^{'}(u_{(m)}))
(large delta_{(i)} = delta_{(i+1)} imes w_{i}^{T} cdot f_{i}^{'}(u_{i}))
(large w_{i} = w_{i} - etacdotfrac{partial L}{partial w_{i}} = w_{i} - eta cdot v_{i}^{T} imes delta_{(i+1)})
(large b_{i} = b_{i} - etacdotfrac{partial L}{partial b_{i}} = b_{i} - eta cdotdelta_{(i+1)})
其中
(large u_{(i)}) 是 (large (1, n_{i})) 矩阵
(large v_{(i)}) 是 (large (1, n_{i})) 矩阵
(large delta_{(i)}) 是 (large (1, n_{i})) 矩阵
(large b_{(i)}) 是 (large (1, n_{i+1})) 矩阵
(large w_{(i)}) 是 (large (n_{i}, n_{i+1})) 矩阵
以上是针对单个样本的
对于多个样本的同时计算有(这里的 $
ormalsize u,v,delta $ 还是 (
ormalsize(1, n_{i})) 矩阵代表单个样本)
(Large frac{partial L(X)}{partial w_{(i-1, p, q)}}=sum_{x_{1}}^{x_{k}}frac{partial L}{partial u_{(i, q)}}cdot frac{partial u_{(i, q)}}{partial w_{(i-1, p, q)}}=sum_{x_{1}}^{x_{k}}delta_{(i, q)}cdot v_{(i-1, p)})
(Large frac{partial L(X)}{partial b_{(i-1, q)}} = sum_{x_{1}}^{x_{k}}frac{partial L}{partial u_{(i, q)}}cdot frac{partial u_{(i, q)}}{partial b_{(i-1, q)}}=sum_{x_{1}}^{x_{k}}delta_{(i, q)})
可以得到(这里的 $
ormalsize u,v,delta $ 改写为 (
ormalsize(k, n_{i})) 矩阵代表多个样本)
(large delta_{(m)} =frac{partial L}{partial v_{(m)}} cdot f_{m}^{'}(u_{(m)}))
(large delta_{(i)} = delta_{(i+1)} imes w_{i}^{T} cdot f_{i}^{'}(u_{i}))
(large w_{i} = w_{i} - etacdotfrac{partial L}{partial w_{i}} = w_{i} - eta cdot v_{i}^{T} imes delta_{(i+1)})
(large b_{i} = b_{i} - etacdotfrac{partial L}{partial b_{i}} = b_{i} - eta cdot(np.sum(delta_{(i+1)}, axis=0, keepdims=True)))
其中
(large k) 是样本数量
(large u_{(i)}) 是 (
ormalsize (k, n_{i})) 矩阵
(large v_{(i)}) 是 (
ormalsize (k, n_{i})) 矩阵
(large delta_{(i)}) 是 (
ormalsize (k, n_{i})) 矩阵
(large b_{(i)}) 是 (
ormalsize (1, n_{i+1})) 矩阵
(large w_{(i)}) 是 (
ormalsize (n_{i}, n_{i+1})) 矩阵
np.sum
是借用 numpy 的写法,是对矩阵求和,这里求出的结果是 (
ormalsize (1, n_{i+1})) 矩阵
axis=0
代表对第一个下标求和,即求
sum[0] = x[0][0] + x[1][0] + ... + x[m][0]
sum[1] = x[0][1] + x[1][1] + ... + x[m][1]
可以看到就是求列和
keepdims=True
代表保持原来维度,不然求和后会变成一维向量
可以看到,每一次前向传导算法出来结果后,就要从最后一层开始,通过反向传播算法更新系数
然后再进行前向传导算法,然后再反向传播更新系数,这样不断迭代得到最优参数
损失层 (CostLayer)
输出层后面可以再加一个损失层 CostLayer 作为 BP 算法的第一层
并且其 BP 算法和其他层不一样
损失层没有激活函数,但可能有特殊的变换函数 (比如说 Softmax)
需要定义某个损失函数
定义导函数时,需要考虑到自身特殊的变换函数并计算相应的、整合后的梯度
可以把损失层和输出层合并,把损失层同时作为输出层使用
损失函数的选择
对于固定的损失函数,有相对适合它的激活函数,结合激活函数来选择损失函数是一个常见的做法
用得比较多的组合有以下四个
Sigmoid 系以外的激活函数 + 距离损失函数(MSE)
因为 Sigmoid 系激活函数会引起梯度消失的现象,既梯度容易趋向于 0
MSE 这个损失函数无法处理这种梯度消失
(large delta_{(m)} =frac{partial L}{partial v_{(m)}}cdot f_{m}^{'}(u_{(m)})=-2||y-v_{m}||cdot v_{m}(1-v_{m}))
可以看到,由于 (large y) 取 0 和 1,而 (large v_{(m)}) 是趋向于 0 和 1
当这两个值不一致的时候也就是需要调整参数时,梯度会趋向 0,所以这种组合不能用
Sigmoid + Cross Entropy
Cross Entropy 能解决 Sigmoid 的梯度消失问题
(large delta_{(m)} =frac{partial L}{partial v_{(m)}}cdot f_{m}^{'}(u_{(m)})=(-frac{y}{v_{m}} + frac{1-y}{1-v_{m}})cdot v_{m}(1-v_{m}) =v_{m}-y)
可以看到当 (large y) 和 (large v_{(m)}) 不一致时梯度趋向 1 或 -1
Softmax + Cross Entropy / log-likelihood
log-likelihood 会导致训练无法收敛,需要改进,改进后和 Cross Entropy 本质上是一样的
特殊的层结构(SubLayer)
有一类特殊的 Layer 它们不会独立存在,而是附在某个 Layer 后以实现某种特定功能,称为 SubLayer
SubLayer 是为了对 Layer 的输出进行变换,目的是为了优化输出
SubLayer 可以有多个相连,最前面的 Layer 又称为 Root Layer,最后一个 SubLayer 又称为 Leaf Layer
SubLayer 的行为大体上可以概括如下:
在前向传导中,它会根据自身的属性和算法来优化从父层处得到的更新
在反向传播中,它会有如下三种行为:
SubLayer 之间的关联不会被更新
SubLayer 本身可能会有参数,可能会被 BP 算法更新,但影响域仅在该 SubLayer 的内部
Layer 之间关联的更新通过 Leaf Layer 完成,i 层的 Leaf 用 i 层的激活函数完成局部梯度的计算
典型的 SubLayer 有 Dropout 和 Normalize
Dropout
核心思想在于提高模型的泛化能力
它在每次迭代中依概率去掉 Layer 的某些神经元,从而每次迭代训练的都是一个小的神经网络
Normalize
核心思想在于把父层的输出进行归一化
从而期望能够解决由于网络结构过深而引起的梯度消失等问题
优化器(Optimizer)
在众多深度学习框架中,参数更新过程常被单独抽象成若干个模型,这些模型称为优化器
优化器主要对梯度的计算进行优化
优化的算法和梯度下降法类似,区别可以概括如下两点:
更新方向不是简单地取为梯度
学习速率不是简单地取为常值
优化器的框架应该包括如下三个方法:
接收欲更新的参数并进行相应处理的方法
利用梯度和自身属性来更新参数的方法
在完成参数更新后更新自身属性的方法
这里要讲的优化器属于最朴素的优化器:根据算法与梯度来更新相应参数
比较优秀的算法在每一步迭代中计算梯度时都不是独立的,而会利用上以前的计算结果
以 (small Delta W) 代表原始梯度,以 (small Delta^{*}W) 代表优化后的梯度
Vanilla Update
Vanilla 是朴实平凡的意思,既和最普通的梯度下降一样
(large Delta^{*}W=Delta W)
在实际实现中,Vanilla Update 通常以小批量梯度下降法(MBGD)的形式出现
Momentum Update
设想:
将损失函数的图像想象成一个山谷,我们的目的是达到谷底
将损失函数某一点的梯度想象成该点对应的坡度
将学习速率想象成沿坡度行走的速度
Vanilla Update 会出现前一秒还在以很快的速度往左走,下一秒突然以很快的速度往右走
这种行进模式之所以违背直观,是因为没有考虑到惯性
Momentum Update 通过尝试模拟物体运动时的惯性以期望增加算法收敛的速度和稳定性
其优化公式为:
(large Delta^{*}W_{t}=-frac{
ho}{eta}V_{t-1} + Delta W_{t})
其中
(
ormalsize Delta W_{t}) 为动力
(
ormalsize V_{t-1}) 为第 t-1 步的速度
(
ormalsize
ho) 为惯性,(
ormalsize
ho) 初始化为 0.5 并逐步加大至 0.99,相当于越接近谷底越要减少动力
Nesterov Momentum Update
在凸优化问题下的收敛性会比传统的 Momentum Update 要更好
核心思想在于想让算法具有前瞻性
它会利用下一步的梯度而不是这一步的梯度来合成出最终的更新步伐
(large W^{'}_{t-1} = W_{t-1} +
ho V_{t-1})
(large V_{t} =
ho V_{t-1} - eta Delta W^{'}_{t})
(large Delta^{*}W_{t}=-frac{
ho}{eta}V_{t} +Delta W^{'}_{t})
RMSProp
Momentum 系算法通过搜索更优的更新方向来进行优化
RMSProp 则是通过实时调整学习速率来进行优化
(large igtriangledown^{2}=
hoigtriangledown^{2}+(1-
ho)Delta W_{t})
(large Delta^{*}W_{t}=frac{Delta W_{t}}{igtriangledown + epsilon})
计算公式比较复杂
(large igtriangledown^{2}) 是从算法开始到当前步骤的所有梯度的某种“累积”
(large
ho) 是衰减系数,越早的梯度对当前梯度的影响越小
Adam
Adam 算法是应用最广泛的,一般而言效果最好,它高效、稳定、适用于绝大多数应用场景
一般来说如果不知道该选哪种优化算法的话,使用 Adam 常常会是个不错的选择
计算公式比较复杂,很像是 Momentum 系算法和 RMSProp 算法的结合
(large Delta = eta_{1}Delta + (1-eta_{1})Delta W_{t})
(large igtriangledown^{2} = eta_{2}igtriangledown^{2} + (1-eta_{2})Delta^{2} W_{t})
(large Delta^{*}W_{t} = frac{Delta}{igtriangledown + epsilon})
代码思路
主要的函数有
# 添加新的层
def add(self, layer)
# 训练,使用反向传播算法(bp),指定学习率,迭代次数,优化器
def fit(self, x, y, lr=None, epoch=None, optimizer=None)
# 预测,使用前向传导算法
def predict(self, x)
使用
# 初始化神经网络
nn = NN()
# 添加输入层,需要指定输入维度和输出维度,输入维度就是 x 的维度
nn.add(ReLU((x.shape[1], 24)))
# 添加变换层,只需要指定输出维度,输入维度就是上一层的输出维度
nn.add(ReLU((24, )))
# 添加损失层,同时作为输出层,输出维度就是 y 的维度,指定损失函数和变换函数
nn.add(CostLayer((y.shape[1],), "CrossEntropy", "Softmax"))
# 训练,步长 0.01,迭代 1000 次,选用 Adam 优化器
nn.fit(x, y, lr=0.01, epoch=1000, optimizer="Adam")
# 预测新数据的值
nn.predict(x_new)
分批思想
数据量大时容易引发内存不足,可以考虑分批处理,这里的分批不是指并行分布式,而是一次取一部分数据处理
计算过程会产生中间数据,比如 100 条数据可能产生 10000 条中间数据,数据量大了内存可能不够,如果每次只处理 10 条数据,只产生 1000 条数据,对内存的要求就小了,处理下一批时内存又释放了出来
训练过程
for counter in range(epoch):
for _ in range(train_repeat): # 每次迭代都将输入数据 x 分多批次完成
# 训练部分数据
预测过程
while count < len(x): # 每次预测一批 x 而不是一次性全预测
count += single_batch
if count >= len(x):
rs.append(self._get_activations(x[count - single_batch:]).pop())
else:
rs.append(self._get_activations(x[count - single_batch:count]).pop())
梯度消失
随着网络层数增加,可能会出现梯度消失现象
BP 反向传播梯度时,每传递一层,梯度都会衰减,那么层数一多,梯度就会消失,将无法有效训练参数
解决方法包括使用 ReLU,ELU 等激活函数,使用 Normalize SubLayer 进行归一化等等
神经网络小结
基本单位是层 (Layer),它是一个非常强大的多分类模型
每一层都会有一个激活函数,它是模型的非线性扭曲力
通过权值 w 和偏置量 b 连接相邻两层,其中 w 将结果线性映射到新的维度空间,b 则能打破对称性
通过前向传导算法获取各层的激活值
通过输出层的激活值和损失函数来计算损失,以及输出层的局部梯度
通过反向传播算法算出各层的局部梯度并用各种优化器更新参数 w 和 b
合理利用一些特殊的层结构能使模型表现提升
当任务规模较大时、就需要考虑内存等诸多和算法无关的问题了
各种神经网络
前反馈神经网络 (Feedforward Neural Network, FNN)
信息由输入层到输出层向前单向流动,误差由输出层到输入层后向传递,这就是 FNN
有时也叫 BP 神经网络(Back Propagation Neural Network)
CNN 也是 FNN 的一种
RNN 则不是
全连接神经网络 (Fully Connected Neural Network)
每个节点的输出会被下一层的所有节点当作输入
每个节点的输入会使用上一层的所有节点的输出
既前后两层的所有节点都连接起来
前面介绍的神经网络就是全连接神经网络,CNN、RNN 则不是
卷积神经网络 (Convolutional Neural Network, CNN)
全连接网络容易导致参数太多,尤其用于处理图像时
卷积神经网络在全连接网络的基础上增加了卷积层,卷积层的计算函数称为卷积核
卷积神经网络接受多维数据
比如一副 5x4 的图片,假设 RGB 占 3 位,全连接神经网络必须将其转为 (1,60)
而卷积层则直接接受多维数据 (3,4,5),通常认为这是 3 个频道,每个频道是一个 (4,5) 二维数据
卷积核输出维度为 (m,n) 的数据,每个数值只使用上一层的所有频道的部分数据进行计算
使用 k 个卷积核最终输出维度为 (k,m,n) 的数据,k 个卷积核被认为提取了 k 个特征
这里说的卷积和数学上的卷积不是一个意思
最后还是要连接普通的全连接网络,因为卷积层只用于提取特征,实际上后面用其他算法也可以
训练过程与全连接神经网络基本一致
循环神经网络 (Recurrent Neural Network, RNN)
全连接网络还存在另一个问题:无法对时间序列上的变化进行建模
然而样本出现的时间顺序对于自然语言处理、语音识别、手写体识别等应用非常重要
在 RNN 中,神经元的输出可以在下一个时间戳直接作用到自身
即第 i 层在 m 时刻的输入,除了 i-1 层在该时刻的输出外,还包括其自身在 m-1 时刻的输出
长短期记忆网络 (Long Short-Term Memory, LSTM)
RNN 可看成一个在时间上传递的神经网络,它的深度是时间长度,会在时间轴上出现梯度消失现象
对于 t 时刻来说,它产生的梯度在时间轴上传播几层之后就消失了,这种影响只能维持若干个时间戳
为了解决时间上的梯度消失,LSTM 通过门的开关实现时间上记忆功能,并防止梯度消失
深层神经网络 (Deep Neural Network, DNN)
广义上来说,神经网络,多层神经网络,深层神经网络指的是同一个东西
狭义上来说,DNN 有时特指全连接神经网络,不包括 CNN,RNN
一般都理解为广义上的意思
深度学习 (Deep Learning, DL)
维基百科:通过多层非线性变换对高复杂性数据建模算法的合集
一般通过激活函数实现去线性化
由于深层神经网络是多层非线性变换的一种常用方法,很多时候深度学习就是指深层神经网络
这里的深度并没有固定的定义
在语音识别中 4 层网络就能够被认为是较深的,而在图像识别中 20 层以上的网络屡见不鲜
深层神经网络比浅层神经网络的优势
打个比方,给一幅图片,上面有一只猫和一张椅子,要求进行识别
浅层神经网络(假设只有一层)
相当于直接把所有信息抽象成猫和椅子
深层神经网络
相当于有多次的提取特征、多次的进行抽象,比如
第一层,从图像中识别出线条
第二层,从线条中识别出图形
第三层,从简单的图形中识别出两个更复杂的图形
第四层,识别出这两个图形分别是猫和椅子