功能/模式分析
比较之前的三层神经网络的代码,我们可以看到大量的重复之处,比如前向计算中:
def forward3(X, dict_Param):
...
# layer 1
Z1 = np.dot(W1,X) + B1
A1 = Sigmoid(Z1)
# layer 2
Z2 = np.dot(W2,A1) + B2
A2 = Tanh(Z2)
# layer 3
Z3 = np.dot(W3,A2) + B3
A3 = Softmax(Z3)
...
1,2,3三层的模式完全一样:矩阵运算+激活/分类函数。
再看看反向传播:
def backward3(dict_Param,cache,X,Y):
...
# layer 3
dZ3= A3 - Y
dW3 = np.dot(dZ3, A2.T)
dB3 = np.sum(dZ3, axis=1, keepdims=True)
# layer 2
dZ2 = np.dot(W3.T, dZ3) * (1-A2*A2) # tanh
dW2 = np.dot(dZ2, A1.T)
dB2 = np.sum(dZ2, axis=1, keepdims=True)
# layer 1
dZ1 = np.dot(W2.T, dZ2) * A1 * (1-A1) #sigmoid
dW1 = np.dot(dZ1, X.T)
dB1 = np.sum(dZ1, axis=1, keepdims=True)
...
每一层的模式也非常相近:计算本层的dZ,再根据dZ计算dW和dB。
因为三层网络比两层网络多了一层,所以会在初始化、前向、反向、更新参数等四个环节有所不同,但却是有规律的。再加上前面章节中,为了实现一些辅助功能,我们已经写了很多类。所以,现在可以动手搭建一个深度学习的迷你框架了。
抽象与设计
图14-1是迷你框架的模块化设计,下面对各个模块做功能点上的解释。
NeuralNet
首先需要一个NeuralNet类,来包装基本的神经网络结构和功能:
- Layers - 神经网络各层的容器,按添加顺序维护一个列表
- Parameters - 基本参数,包括普通参数和超参
- Loss Function - 提供计算损失函数值,存储历史记录并最后绘图的功能
- LayerManagement() - 添加神经网络层
- ForwardCalculation() - 调用各层的前向计算方法
- BackPropagation() - 调用各层的反向传播方法
- PreUpdateWeights() - 预更新各层的权重参数
- UpdateWeights() - 更新各层的权重参数
- Train() - 训练
- SaveWeights() - 保存各层的权重参数
- LoadWeights() - 加载各层的权重参数
Layer
是一个抽象类,以及需要增加的实际类,包括:
- Fully Connected Layer
- Classification Layer
- Activator Layer
- Dropout Layer
- Batch Norm Layer
将来还会包括:
- Convolution Layer
- Max Pool Layer
每个Layer都包括以下基本方法:
- ForwardCalculation() - 调用本层的前向计算方法
- BackPropagation() - 调用本层的反向传播方法
- PreUpdateWeights() - 预更新本层的权重参数
- UpdateWeights() - 更新本层的权重参数
- SaveWeights() - 保存本层的权重参数
- LoadWeights() - 加载本层的权重参数
Activator Layer
激活函数和分类函数:
- Identity - 直传函数,即没有激活处理
- Sigmoid
- Tanh
- Relu
Classification Layer
分类函数,包括:
- Sigmoid二分类
- Softmax多分类
Parameters
基本神经网络运行参数:
- 学习率
- 最大epoch
- batch size
- 损失函数定义
- 初始化方法
- 优化器类型
- 停止条件
- 正则类型和条件
LossFunction
损失函数及帮助方法:
- 均方差函数
- 交叉熵函数二分类
- 交叉熵函数多分类
- 记录损失函数
- 显示损失函数历史记录
- 获得最小函数值时的权重参数
Optimizer
优化器:
- SGD
- Momentum
- Nag
- AdaGrad
- AdaDelta
- RMSProp
- Adam
WeightsBias
权重矩阵,仅供全连接层使用:
初始化
- Zero, Normal, MSRA (HE), Xavier
- 保存初始化值
- 加载初始化值
- Pre_Update - 预更新
- Update - 更新
- Save - 保存训练结果值
- Load - 加载训练结果值
DataReader
样本数据读取器:
- ReadData - 从文件中读取数据
- NormalizeX - 归一化样本值
- NormalizeY - 归一化标签值
- GetBatchSamples - 获得批数据
- ToOneHot - 标签值变成OneHot编码用于多分类
- ToZeroOne - 标签值变成0/1编码用于二分类
- Shuffle - 打乱样本顺序
从中派生出两个数据读取器:
- MnistImageDataReader - 读取MNIST数据
- CifarImageReader - 读取Cifar10数据