【深度学习】Numpy实现简单神经网络

    科技2022-08-31  102

    原文地址:点击访问

    许久未更,是因为开学之后学习任务太充实了。每天都有做不完的事情,每件事情都又想把它做好。

    我航中秋国庆假期长达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机上进行实验,

    Processed: 0.018, SQL: 10