原文地址:点击访问
许久未更,是因为开学之后学习任务太充实了。每天都有做不完的事情,每件事情都又想把它做好。
我航中秋国庆假期长达8天,真应了那句话:该放的假一天不少,该补的课一次没有。期间,有多门作业要完成。今天,为大家推送简单神经网络的实现,是我的《人工智能加速器》的作业。
实验内容
搭建基本的多层神经网络,并在给定测试集上进行精度测试。
-
注1:不使用深度学习框架完成网络搭建。
-
注2:不限制编程语言,推荐使用python进行神经网络搭建,允许使用numpy等工具包。
-
注3:使用给定的训练集和测试集,可使用提供的代码模板(bp_template.py)并在其基础上进行修改,也可以重新进行编写。
实验要求
- 网络输入:784 个输入节点(每个节点对应图片的一个像素)
- 网络输出:10 个输出节点(分别代表0~9 这10 个数字)
- 网络深度建议为3 至5 层即可,如果太深则需要太长运行时间。
- 使用给定训练集(mnist_train.csv)进行权重训练,使用测试集(mnist_test.csv)测试并给出测试精度。(不对精度做特别的要求,只需在合理范围内即可)
网络架构
本文参考tutorial学习了后向传播的原理, 参考tutorial学习了后向传播的设计, 从而设计出了两个隐含层的简单神经网络. 具体网络架构见图1所示.
主要代码实现
完整代码点击阅读原文跳转到我的Github,后向与前向传播代码如下:
# neural network class definition
class neuralNetwork:
param = {}
# initialise the neural network
def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
'''
The network consists of three types of layers: input layer(784 nodes), hidden layers and output layer(10 nodes).
You can define the number of hidden nodes and layers you want.
'''
self.hiddennodes_1 = hiddennodes[0]
self.hiddennodes_2 = hiddennodes[1]
self.param['W1'] = np.random.randn(hiddennodes[0], inputnodes) * np.sqrt(1 / hiddennodes[0])
self.param['b1'] = np.random.randn(hiddennodes[0], 1) * np.sqrt(1 / hiddennodes[0])
self.param['W2'] = np.random.randn(hiddennodes[1], hiddennodes[0]) * np.sqrt(1 / outputnodes)
self.param['b2'] = np.random.randn(hiddennodes[1], 1) * np.sqrt(1 / hiddennodes[1])
self.param['W3'] = np.random.randn(outputnodes, hiddennodes[1]) * np.sqrt(1 / outputnodes)
self.param['b3'] = np.random.randn(outputnodes, 1) * np.sqrt(1 / outputnodes)
self.learningrate = learningrate
self.inputnodes = inputnodes
self.hiddennodes = hiddennodes
self.outputnodes = outputnodes
def forward(self, inputs_list):
'''
forward the neural network
'''
inputs_list = inputs_list.reshape(-1, 1)
self.inputs_list = inputs_list
z1 = np.dot(self.param['W1'], inputs_list) + self.param['b1']
h1 = sigmoid(z1)
z2 = np.dot(self.param['W2'], h1) + self.param['b2']
h2 = sigmoid(z2)
z3 = np.dot(self.param['W3'], h2) + self.param['b3']
h3 = sigmoid(z3)
self.final_outputs = h3
self.z1 = z1
self.h1 = h1
self.z2 = z2
self.h2 = h2
self.z3 = z3
self.h3 = h3
def Backpropagation(self, targets_list):
'''
propagate backword
'''
change = {}
targets_list = targets_list.reshape(-1, 1)
loss_val = mse_loss(targets_list, self.final_outputs)
# calculate W3 update
error = -2 * (targets_list - self.final_outputs)
error = np.multiply(error, sigmoid(self.z3, derivative=True))
change['W3'] = np.dot(error, self.h2.T)
change['b3'] = error
# calculate W2 update
error = np.multiply(np.dot(self.param['W3'].T, error), sigmoid(self.z2, derivative=True))
change['W2'] = np.dot(error, self.h1.T)
change['b2'] = error
# calculate W1 update
error = np.multiply(np.dot(self.param['W2'].T, error), sigmoid(self.z1, derivative=True))
change['W1'] = np.dot(error, self.inputs_list.T)
change['b1'] = error
self.param['W1'] -= self.learningrate * change['W1']
self.param['b1'] -= self.learningrate * change['b1']
self.param['W2'] -= self.learningrate * change['W2']
self.param['b2'] -= self.learningrate * change['b2']
self.param['W3'] -= self.learningrate * change['W3']
self.param['b3'] -= self.learningrate * change['b3']
return loss_val
精度与损失
本实验中, 训练了20代, 共耗时3590.8710s. 在训练集上的损失和验证精度如下图, 可以看到, 随着训练代数增多, l o s s loss loss值逐渐减低, 精度逐渐升高, 最高可以达到100%.
最终, 在测试集上的精度达到了98%. 图3展示了测试集中前10个测试样本的预测结果, 期预测结果与其真实标签基本吻合. 但是, 对于图3(i)这样人为都难以辨别出来的测试样本, 神经网络就更加难以预测准确. 现实中, 这种脏数据往往是无意义的.
训练时间
整个实验运行时间如下表所示, 其中训练时间最长, 平均每一代的训练时间为179.5436s, 相当耗时.
图4显示了各个时间的占比, 平均每代训练时间占比高达93.6%.
实验环境
本文使用Python 3.6, 在配置为Intel® Xeon® Gold 5120T CPU @2.20GHz 2.19 GHz (2 processors)的PC机上进行实验,