深度学习初遇——自己动手实现三层神经网络

2023-10-16 22:50

本文主要是介绍深度学习初遇——自己动手实现三层神经网络,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍

深度学习中,神经网络是最基础的数据结构,本文想自己动手实现一个神经网络,并使用它来对mnist数据集做预测。
本文内容参考了大神塔里克拉希德的著作《Python神经网络编程》,有兴趣的读者可以在网上找到这本书,或联系笔者,笔者免费赠送。

神经网络结构

神经网络的结构想必大家都很熟悉了,看张图吧,这里除了输入层外,其他层每个节点都有激活函数,比如sigmoid或relu等。
在这里插入图片描述
这里,权重很重要,在神经网络中,要更新的参数就是权重,而且后面我们会看到,误差的反向传播也要用到当前的权重。每两层之间的权重可以用一个矩阵表示,在理论研究和代码编程时,这很有用。

前馈

前馈的过程是根据输入数据,逐层计算输出值,进而得到输出层的输出值,给定权重(通过优化算法更新前的权重,最开始是按一定规则人为初始化的)和输入值,代入公式即可得到,这个操作很简单,但很重要,后面我们会看到,权重的更新需要用到后一层节点的输出值以及前一层节点的输出值(注意,我们是站在两层之间的地方),从上一小节的图示中,我们很容易有一个形象的感受。

误差的反向传播

我们通过当前权重和输入值计算出了输出值,而且训练数据的目标值是给定的,所以模型的误差也很容易算出来,有了整个模型的误差值,那还要每一层的误差做什么呢?或者为什么要进行误差反向传播呢?误差又是怎么进行反向传播的呢?
后面我们会看到,每一层权重的更新,都要用到下一层的误差值,所以反向传播很有必要,那它怎么传播呢?
如下图所示,一般地,误差会根据当前节点输入连接的权重进行拆分,假如右边节点的输出误差为 e e e,左边第一个节点的误差为 e r r 1 = W 1 , 1 W 1 , 1 + W 2 , 1 ∗ e err_1=\frac{W_{1,1}}{W_{1,1}+ W_{2,1}}*e err1=W1,1+W2,1W1,1e,左边第二个节点的误差为 e r r 2 = W 2 , 1 W 1 , 1 + W 2 , 1 ∗ e err_2=\frac{W_{2,1}}{W_{1,1}+ W_{2,1}}*e err2=W1,1+W2,1W2,1e
在这里插入图片描述
多个节点的误差会拆分后叠加到上一层中每一个节点的误差上去,例如下图所示
在这里插入图片描述
这时, e r r 1 = W 1 , 1 W 1 , 1 + W 2 , 1 ∗ e 1 + W 1 , 2 W 1 , 2 + W 2 , 2 ∗ e 2 err_1=\frac{W_{1,1}}{W_{1,1}+ W_{2,1}}*e_1+\frac{W_{1,2}}{W_{1,2}+ W_{2,2}}*e_2 err1=W1,1+W2,1W1,1e1+W1,2+W2,2W1,2e2,左边第二个节点的误差为 e r r 2 = W 2 , 1 W 1 , 1 + W 2 , 1 ∗ e 1 + W 2 , 2 W 1 , 2 + W 2 , 2 ∗ e 2 err_2=\frac{W_{2,1}}{W_{1,1}+ W_{2,1}}*e_1+\frac{W_{2,2}}{W_{1,2}+ W_{2,2}}*e_2 err2=W1,1+W2,1W2,1e1+W1,2+W2,2W2,2e2
不断重复上述拆分,便可以计算出每一层的输出误差,在实际应用中,通常用权重代替上面公式中的分数部分,即使用 W 1 , 1 W_{1,1} W1,1代替 W 1 , 1 W 1 , 1 + W 2 , 1 \frac{W_{1,1}}{W_{1,1}+ W_{2,1}} W1,1+W2,1W1,1,使用 W 1 , 2 W_{1,2} W1,2代替 W 1 , 2 W 1 , 2 + W 2 , 2 \frac{W_{1,2}}{W_{1,2}+ W_{2,2}} W1,2+W2,2W1,2,以此类推。这样利用权重矩阵和当前层的输出误差,便可以计算出前一层的误差。

权重更新

在机器学习中,对模型的优化一般采用梯度下降法,这就需要知道误差对更新参数的斜率,在神经网络中,我们需要知道输出误差对每一个权重的斜率。
求导的过程《Python神经网络编程》里面讲的很详细了,这里只给出这个神奇的公式,
在这里插入图片描述
这里,每一层的输出误差已经通过误差的反向传播获得,当前的权重是给定的,输出值也可以通过前馈过程获得,所以,误差对权重的斜率也自然可以轻松获得,用矩阵的语言,某两层之间的权重矩阵更新值可以表示为:

在这里插入图片描述
本文代码部分摘自《Python神经网络编程》并对其做了注释。

代码

import numpy
import numpy as np
import scipy.special# 神经网络类
class NeuralNetwork:def __init__(self, inodes, hnodes, onodes, learning_rate=0):# 输入层节点数self.inodes = inodes# 隐藏层节点数self.hnodes = hnodes# 输出层节点数self.onodes = onodes# 学习率self.learning_rate = learning_rate# 输入层到隐藏层的权重矩阵# self.wih = np.random.rand(self.hnodes, self.inodes) - 0.5self.wih = np.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))# 隐藏层到输出层的权重矩阵# self.who = np.random.rand(self.onodes, self.hnodes) - 0.5self.who = np.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))# 激活函数self.activation_function = lambda x: scipy.special.expit(x)# 前馈def forward(self, input_data):# 输入inputs = np.array(input_data, ndmin=2).T# 隐藏层输入数据hidden_inputs = np.dot(self.wih, inputs)# 隐藏层输出数据hidden_outputs = self.activation_function(hidden_inputs)# 输出层输入数据final_inputs = np.dot(self.who, hidden_outputs)# 输出层输出数据final_outputs = self.activation_function(final_inputs)return final_outputs# 模型训练def train(self, input_data, target_data):# 输入inputs = np.array(input_data, ndmin=2).T# 输入数据标签targets = np.array(target_data, ndmin=2).T# 隐藏层输入数据hidden_inputs = np.dot(self.wih, inputs)# 隐藏层输出数据hidden_outputs = self.activation_function(hidden_inputs)# 输出层输入数据final_inputs = np.dot(self.who, hidden_outputs)# 输出层输出数据final_outputs = self.activation_function(final_inputs)# 输出层误差output_errors = targets - final_outputs# 反向传播至隐藏层的误差hidden_errors = np.dot(self.who.T, output_errors)# 更新隐藏层和输出层的权重矩阵delta_who = np.dot((output_errors * final_outputs * (1.0 - final_outputs)), np.transpose(hidden_outputs))self.who += self.learning_rate * delta_who# 更新输入层和隐藏层的权重矩阵delta_wih = np.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), np.transpose(inputs))self.wih += self.learning_rate * delta_wihif __name__ == "__main__":# 神经网络模型inodes = 784hnodes = 100onodes = 10model = NeuralNetwork(inodes, hnodes, onodes, 0.3)# 读取训练数据data_file = open("./mnist_dataset/mnist_train.csv")data_set = data_file.readlines()data_file.close()# 对每一项输入数据进行模型训练for record in data_set:all_values = record.split(",")# 对训练数据进行放缩inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01# 对训练数据标签进行编码targets = np.zeros(onodes) + 0.01targets[int(all_values[0])] = 0.99# 训练模型model.train(inputs, targets)# 加载测试数据test_data_file = open("./mnist_dataset/mnist_test.csv", 'r')test_data_list = test_data_file.readlines()test_data_file.close()# 分数卡scorecard = []# 对每一项测试数据进行预测for record in test_data_list:all_values = record.split(',')# 正确的标签correct_label = int(all_values[0])print(correct_label, "correct label")inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01# 用神经网络模型预测outputs = model.forward(inputs)# 取出最大输出值对应的标签索引label = numpy.argmax(outputs)print(label, "network's answer")# 计分卡计数if label == correct_label:scorecard.append(1)else:scorecard.append(0)print(scorecard)# 计算分数scorecard_array = np.asarray(scorecard)print("performance = ", scorecard_array.sum() / scorecard_array.size)

运行结果

performance =  0.9468

作者这水平有限,有不足之处欢迎留言指正

这篇关于深度学习初遇——自己动手实现三层神经网络的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/221272

相关文章

pytorch自动求梯度autograd的实现

《pytorch自动求梯度autograd的实现》autograd是一个自动微分引擎,它可以自动计算张量的梯度,本文主要介绍了pytorch自动求梯度autograd的实现,具有一定的参考价值,感兴趣... autograd是pytorch构建神经网络的核心。在 PyTorch 中,结合以下代码例子,当你

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

Android实现打开本地pdf文件的两种方式

《Android实现打开本地pdf文件的两种方式》在现代应用中,PDF格式因其跨平台、稳定性好、展示内容一致等特点,在Android平台上,如何高效地打开本地PDF文件,不仅关系到用户体验,也直接影响... 目录一、项目概述二、相关知识2.1 PDF文件基本概述2.2 android 文件访问与存储权限2.

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

SpringBatch数据写入实现

《SpringBatch数据写入实现》SpringBatch通过ItemWriter接口及其丰富的实现,提供了强大的数据写入能力,本文主要介绍了SpringBatch数据写入实现,具有一定的参考价值,... 目录python引言一、ItemWriter核心概念二、数据库写入实现三、文件写入实现四、多目标写入