前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【神经网络】:手写数字识别,一文带你掌握!

【神经网络】:手写数字识别,一文带你掌握!

作者头像
WEBJ2EE
发布2023-09-02 10:09:35
5120
发布2023-09-02 10:09:35
举报
文章被收录于专栏:WebJ2EEWebJ2EE

提要

本文带大家从原理到实践,手动构建一个能识别手写数字的神经网络

一、要做什么

我们的要做的是,训练出一个人工神经网络(ANN),使它能够识别手写数字(如下图所示)。

二、背景

2.1. 人工神经网络是什么

人工神经网络(Artificial Neural Network,简称ANN),也被称为神经网络(NN),是受生物神经网络(Biological Neural Networks)启发的计算系统

神经网络是一种重要的人工智能技术,其在图像识别、自然语言处理、医疗和金融等领域得到了广泛应用。

2.2. 手写数字从哪来

这些手写数字,来自大名鼎鼎的 MNIST 手写数字图像集。

MNIST 是机器学习领域最有名的数据集之一,也称作计算机视觉领域的 hello world 数据集。

三、基础

由于人工神经网络(Artificial Neural Network)的灵感来源是生物神经网络(Biological Neural Networks),那么接下来,我将按照以下思路讲解:

  1. 生物神经网络 的基本结构和特性。
  2. 人工神经网络 如何对其进行模拟。

3.1. 生物神经网络

生物神经网络一般指,生物的大脑神经元、细胞、触突等结构组成的一个大型网络结构,用来帮助生物进行思考和行动。

【神经元】

神经元即神经元细胞,是神经系统最基本的结构和功能单位

神经元包括胞体突起两大部分,突起又分为轴突树突

下面从功能角度,对生物神经元进行进行介绍:

  • 神经信号的输入:
    • 神经元的树突,负责接收其他神经元传来的神经信号,并传给胞体
    • 一个神经元通常有多个树突,即一个神经元可以接收来自多个神经元的输入
  • 神经元的激活:
    • 积累不同时间通过同一突触传入的神经信号。
    • 积累同一时间通过不同突触传人的神经信号。
    • 胞体是神经元新陈代谢的中心,负责接收整合从树突传来的神经信号。
    • 胞体接收到神经信号输入之后,不会立即做出反应,而是要等输入积累到超过一个阈值,才会被激活
  • 神经信号的输出:
    • 胞体被激活后,它会沿轴突向其它神经元发出神经信号。
    • 轴突比树突长而细,也叫神经纤维,末端处有很多细的分支称为神经末梢,每一条神经末梢可以向四面八方传出信号,神经末梢和和另一个神经元进行通信的结构叫突触,用于输出神经元的神经信号。
    • 需要注意的是,相同的同神经信号可能对接受它的不同神经元有不同的效果。这一效果主要由突触决定:突触的“联结强度”越大,接受的信号就越强,反之,就越弱。

【神经网络】

生物神经系统由大量神经元构成,每个神经元都可能连接到数千个其他神经元,这会形成一个复杂的神经网络。这个网络使得我们可以感知环境、思考、记忆、学习等。我们的每一个思想、感觉和行动都是由这种神经元间的连接和交流驱动的。

【知识学习】

1949 年 Hebb 提出了突触学习的模型(Hebb定律)。该理论认为,神经网络是具有可塑性的,重复性的经验可以加强或削弱神经元间的连接,即:学习,在脑分子层次上,导致的是神经元间突触连接的变化。这使得我们的大脑可以适应新的信息、经历和学习。

3.2. 人工神经网络

神经网络是一种对生物神经网络组织结构和运行机制的抽象、简化和模拟,以期能够实现类人工智能的机器学习技术。

下面还是从功能的角度,以对比的方式,描述人工神经网络如何实现对生物神经网络的抽象、简化和模拟。

我们先对前面所讲的,生物神经元、神经网络最核心的特性,进行提炼:

  • 神经信号的输入:
    • 一个神经元可以接收来自多个神经元的输入。【核心1:多个输入
  • 神经元的激活:
    • 神经元会积累输入的神经信号。【核心2:积累输入
    • 积累的神经信号,超过一个阈值,神经元才会被激活【核心3:输入超过阈值才激活】。
  • 神经元的输出:
    • 被激活的神经元,会沿着轴突发出神经信号。【核心4:激活后产生输出
    • 轴突的神经末梢会向四面八方传出信号。【核心5:一个输出可以作用到多个后级神经元
    • 相同的输出可能会对后级神经元产生不同的效果。【核心5:一个输出,可能会对不同的后级神经元,产生不同的影响
  • 核心6:海量神经元相互连接,形成神经网络】。
  • 核心7:重复的经验可以加强、削弱神经元之间的联结强度。】。

所以人工神经元的抽象模型,如下图所示:

四、运行

接下来,我们从运行的角度,描述人工神经网络是如何工作的。

4.1. 一些记号

由于后面几节中会反复使用一些记号,所以在这里把后面会用到的记号以及含义写在这里,方便查阅。

4.2. 神经信号在网络中的正向传播

我们使用一个有3层、每层3个神经元的神经网络,讲解神经信号在神经网络中的正向传播过程。

第一步,计算隐藏层各神经元的神经信号输入

第二步:计算隐藏层各神经元的神经信号输出

第三步输出层各神经元的神经信号输入

第四步输出层各神经元的神经信号输出

以上就是神经信号在神经网络中的正向传播过程。

4.3. 神经网络误差的反向传播

从这一节开始,就进入了神经网络的训练过程,即神经网络积累知识的过程。

上一节描述了,神经信号如何输入神经网络并得到输出的过程。从我们要做的事情“训练出一个人工神经网络,使它能够识别手写数字”角度说,我们最终的期望就是,把一张手写数字7的图片输入神经网络,神经网络的输出是数字7,把一张手写数字3的图片输入神经网络,神经网络的输出是数字3。

所谓“训练”,就是事先准备好一堆有正确答案的数据(比如:图1是3,图2是6,图2是9 ...),把这些数据和答案输入神经网络,让神经网络自己从这堆数据中把数据中潜藏的“知识”提炼出来,这些提炼出来的知识表现为神经网络中确定下来的权重。

由于还未经过训练的神经网络无法完成我们期望它做的事情(例如:输入手写数字3,输出是6;输入手写数字1,输出是9 ...)。也就是说,对于给定神经网络的输入,我们期望神经网络应该输出的结果 和 神经网络的实际输出结果之间存在误差

所以,针对这个误差,我们要做的工作是:

  1. 将神经网络的输出误差反向传播到神经网络中的各个神经元上;
  2. 找到某种方式,能让我们利用这个误差来指导我们调整神经网络中的权重,以达到最小化神经网络输出误差的目的。

我们先解决第一个问题:将神经网络的输出误差反向传播到神经网络中的各个神经元上。

计算隐藏层各神经元的误差,采用的是按照权重的比例,将误差反向传播到隐藏层的结点上。

  • 用矩阵来表达就是

4.4. 神经网络权重的调整

在完成了第一件事(即,将神经网络的输出误差反向传播到神经网络中的各个神经元上)后

我们再完成第二件事情(即,找到某种方式,能让我们利用这个误差来指导我们调整神经网络中的权重,以达到最小化神经网络输出误差的目的),就可以实现对神经网络的训练。

既然要让神经网络的输出误差最小,那么我们需要先构建神经网络的输出误差函数

直接求误差函数的最小值很难,所以我们采用梯度下降法,以小步迭代的方式,找到目标函数(即我们的)的最小值。

4.5. 梳理一下

五、实战

下面使用 Python 把上述过程实现出来。

NeuralNetwork.py:神经网络

代码语言:javascript
复制
import scipy.special

class NeuralNetwork:
    def __init__(self, input_nodes, hidden_nodes, output_nodes, learning_rate) -> None:
        self.input_nodes = input_nodes
        self.hidden_nodes = hidden_nodes
        self.output_nodes = output_nodes

        self.weight_input_hidden = np.random.normal(0.0, pow(self.hidden_nodes, -0.5), (self.hidden_nodes, self.input_nodes))
        self.weight_hidden_output = np.random.normal(0.0, pow(self.output_nodes, -0.5), (self.output_nodes, self.hidden_nodes))

        self.learning_rate = learning_rate

        self.activation_function = lambda x: scipy.special.expit(x)
        pass

    def train(self, input_list, target_list):
        inputs = np.array(input_list, ndmin=2).T
        targets = np.array(target_list, ndmin=2).T

        hidden_inputs = np.dot(self.weight_input_hidden, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)

        final_inputs = np.dot(self.weight_hidden_output, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)

        output_errors = targets - final_outputs
        hidden_errors = np.dot(self.weight_hidden_output.T, output_errors)

        self.weight_hidden_output += self.learning_rate * np.dot(output_errors * final_outputs * (1.0 - final_outputs), np.transpose(hidden_outputs))
        self.weight_input_hidden += self.learning_rate * np.dot(hidden_errors * hidden_outputs * (1.0 - hidden_outputs), np.transpose(inputs))

        pass

    def query(self, input_list):
        inputs = np.array(input_list, ndmin=2).T

        hidden_inputs = np.dot(self.weight_input_hidden, inputs)
        hidden_outputs = self.activation_function(hidden_inputs)

        final_inputs = np.dot(self.weight_hidden_output, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)

        return final_outputs

main.py:神经网络训练与测试:

代码语言:javascript
复制
import numpy as np
import matplotlib.pyplot
import pylab
from NeuralNetwork import *

input_nodes = 784
hidden_nodes = 100
output_nodes = 10
learning_rate = 0.1

n = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
training_data_file = open("mnist_train.csv", 'r')
training_data_list = training_data_file.readlines()
training_data_file.close()

epochs = 5
total_progress = 5 * len(training_data_list)
current_progress = 0
for e in range(epochs):
    for record in training_data_list:
        all_values = record.split(',')
        inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
        targets = np.zeros(output_nodes) + 0.01
        targets[int(all_values[0])] = 0.99
        n.train(inputs, targets)
        current_progress += 1
        print("\rtraining progress: {:3}%".format((current_progress / total_progress) * 100), end="")
        pass
    pass

test_data_file = open("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])
    inputs = (np.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
    outputs = n.query(inputs)
    label = np.argmax(outputs)
    if (label == correct_label):
        scorecard.append(1)
    else:
        scorecard.append(0)
    pass

scorecard_array = np.asarray(scorecard)
print ("\nperformance = ", scorecard_array.sum() / scorecard_array.size)

参考:

《Python神经网络编程》 MNIST in CSV:https://pjreddie.com/projects/mnist-in-csv/ THE MNIST DATABASE of handwritten digits:http://yann.lecun.com/exdb/mnist/ NN-SVG:http://alexlenail.me/NN-SVG/LeNet.html NeuroMorpho.Org:https://neuromorpho.org/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-08-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WebJ2EE 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、要做什么
  • 二、背景
    • 2.1. 人工神经网络是什么
      • 2.2. 手写数字从哪来
      • 三、基础
        • 3.1. 生物神经网络
          • 3.2. 人工神经网络
          • 四、运行
            • 4.1. 一些记号
              • 由于后面几节中会反复使用一些记号,所以在这里把后面会用到的记号以及含义写在这里,方便查阅。
                • 4.2. 神经信号在网络中的正向传播
                • 4.3. 神经网络误差的反向传播
                • 4.4. 神经网络权重的调整
                • 4.5. 梳理一下
            • 五、实战
            相关产品与服务
            NLP 服务
            NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档