0 思路
- 使用二层神经网络,输入为8个变量,hidden layer有9个神经元(经实际测试,9个神经元效果较好,太多神经元容易过拟合),输出为维度为4的onehot编码
- 由输入到hidden layer先通过一个线性函数,再用relu函数进行激活
- 由hidden layer到输出使用softmax函数
- 使用梯度下降法迭代一定次数,使得Cost达到最低
1 实现
总的来说,实现步骤可分为:
- 导入数据
- 初始化模型参数
- 前向传播(Linear-Activation)
- 计算损失(Cost)
- 后向传播(Linear-Activation)
- 更新参数
- 循环执行2-5步
1.1 导入数据
1 | dataset = pandas.read_csv('dataset.txt', sep='\s+') |
- 这里使用python中的pandas库进行数据的导入。
- 使用
read_csv
函数导入数据。由于原数据用txt保存,这里需要用正则表达式\s+
对数据进行分割; - 划分训练集与测试集,前400条数据为训练集,后100条数据为测试集;
- 将
y
从训练集、测试集中分离需要注意的是,使用pop方法得到的dataframe经过values方法,得到的是一个没有维度的matrix,因此需要将其reshape; - 将训练集的
y
用转换为one-hot
编码,以便于损失函数和softmax的计算。使用sklearn.preprocessing
中的OneHotEncoder
方法。特别只需要注意维度。
1.2 初始化模型参数
1 | def initialize_parameters(n_x, n_h, n_y): |
- 对于参数W,使用np.random.randn()函数将其随机初始化,此函数将返回一组服从标准正态分布的随机样本值,区间为(0,1),经实验发现将函数返回的值乘以0.01得到的效果更好(也许是最终得到的参数普遍较小,乘以0.01可以使得遍历次数降低)。
- 对于参数b,使用np.zeros()函数将其零初始化。
1.3 前向传播
此步需要定义线性前馈函数(linear_forward)以及非线性前馈函数(activation, relu & softmax)。线性函数以及relu函数较为简单,这里略而不谈。
1.3.1 softmax是什么?
softmax函数是逻辑函数的一种推广,它能够将一个含任意实数的K维向量映射到另一个维度的实向量中,使得每一个元素的范围都落在区间(0,1),并且使所有元素的和为1,以此来表示各分类的概率。结果的值越大,概率也就越大,属于某个分类的可能性就越大。
softmax广泛应用于机器学习和深度学习中的多分类问题。在深度学习中,softmax常用于多分类问题最后一层的激活函数,用于输出某样本属于某个分类的概率值。
1.3.2 softmax实现
-
定义
$$softmax(x)i = \frac{e^{x_i}}{\displaystyle\sum{j=1}^{n}e^{x_j}}$$ -
代码
1 | def softmax(Z): |
注意返回cache以便于后向传播中梯度的计算。
- 为什么这里要减去一个max值呢?
从需求上来说,如果x的值没有限制的情况下,当x线性增长,e指数函数下的x就呈现指数增长,一个较大的x(比如1000)就会导致程序的数值溢出,导致程序error。所以需求上来说,如果能够将所有的x数值控制在0及0以下,则不会出现这样的情况,这也是为什么不用min而采用max的原因。
1.4 计算损失
1 | def compute_cost(AL, Y): |
由于最后一层使用softmax激活,损失函数定义较为简单,只要把不为0的probability相加除以样本个数即可。
1.5 后向传播
对于Softmax求导的推导过程可以参考这篇博文。
简单来说$\frac{\partial C}{\partial z_i} = a_i - y_i$。
这里要特别注意dW、db以及dA_prev的求导,维度一定要对的上。
1.6 更新参数
1 | def update_parameters(parameters, grads, learning_rate): |
这里使用的是最简单的参数更新方式,由于数据集较小,没有使用其他的参数更新策略(如SGD、Adam等等)。
2 结果
经测试发现,当n_h=9, learning_rate=0.05, num_iteration=15000时,得到的准确率较好(两个准确率分别为训练集、测试集上的准确率)。
当增大hidden layer层数、神经元数时,发现不仅训练速度变慢了,准确率也降低了,这可能就是过拟合了,因为这个数据集本身就不大。
3 踩坑总结
一开始在训练模型的时候,反复测试之下,发现无论是训练集还是测试集,Accuracy都非常低,只有24%左右。这可能表示模型已经完全失效了,因为本身四选一猜对的概率就是25%。一开始猜想是不是网络结构的问题,无法做分类任务,但是这一个网络已经够简单了,网络结构出错的可能性不大。然后把其预测出来的结果打出来看了一下,发现有两个原因:
- 传入的y没有用one-hot表示,这点错的十分离谱,直接导致损失极大;
- 数据集中的y范围是(1, 4),而最终得到的y范围是(0, 3),二者不统一。
References
- Deep Learning and Neural Network on Coursera(Andrew Ng)
- Numpy学习—np.random.randn()、np.random.rand()和np.random.randint()
- 为什么softmax函数需要减去一个max值