2.神经网络的实现
创建神经网络类
import numpy
# scipy.special包含S函数expit(x)
import scipy.special
# 打包模块
import pickle# 激活函数
def activation_func(x):return scipy.special.expit(x)# 用于创建、 训练和查询3层神经网络
class neuralNetwork:# 初始化神经网络def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):# 设置 输入层, 隐藏层, 输出层 结点个数self.inodes = inputnodesself.hnodes = hiddennodesself.onodes = outputnodes# 两个链接权重矩阵 wih, who# w11 w21# w12 w22 etcself.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))# 学习率self.lr = learningrate# 激活函数是S函数,使用lambda定义函数# self.activation_function = lambda x: scipy.special.expit(x)# 使用lambda定义函数时无法打包保存神经网络对象self.activation_function = activation_funcpass# 训练神经网络def train(self, inputs_list, targets_list):# 使用完全相同的方式从输入层前馈信号到最终输出层,因此代码几乎与query()相同inputs = numpy.array(inputs_list, ndmin=2).T# 使用包含期望值训练样本来训练网络targets = numpy.array(targets_list, ndmin=2).Thidden_inputs = numpy.dot(self.wih, inputs)hidden_outputs = self.activation_function(hidden_inputs)final_inputs = numpy.dot(self.who, hidden_outputs)# 此处的final_outputs和上面的hidden_outputs都经过了激活函数,后面更新权重时不需要再代入了final_outputs = self.activation_function(final_inputs)# 期望矩阵和输出矩阵相减获得误差矩阵output_errors = targets - final_outputs# 根据所连接的权重分割误差,为每个隐藏层结点重组这些误差hidden_errors = numpy.dot(self.who.T, output_errors)# 应用更新权重的矩阵形式表达式# 学习率*误差Ek*sigmoid(输出Ok)*(1-sigmoid(Ok))·前一层输出OjTself.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))pass# 查询神经网络,接受输入,返回输出def query(self, inputs_list):# 将输入列表转换成二维列表,保证计算类型正确inputs = numpy.array(inputs_list, ndmin=2).T# 输入层-隐藏层权重矩阵 点乘 输入矩阵 = 隐藏层输入hidden_inputs = numpy.dot(self.wih, inputs)# 隐藏层输入应用激活函数hidden_outputs = self.activation_function(hidden_inputs)# 隐藏层-输出层权重矩阵 点乘 输隐藏层输出矩阵 = 输出层输入final_inputs = numpy.dot(self.who, hidden_outputs)# 输出层输入应用激活函数final_outputs = self.activation_function(final_inputs)return final_outputs
数据集采用在人工智能领域流行的手写数字的MNIST数据库,MNIST数据库的格式不容易使用, 因此其他人已经创建了相对简单的数据文件格式——CSV文件,其纯文本中的每一个值都是由逗号分
隔的。
训练集是用来训练神经网络的60 000个标记样本集。标记是指输入与期望的输出匹配,也就是答案应该是多少。
可以使用较小的只有10 000个样本的测试集来测试我们的想法或算法工作的好坏程度。 由于这也包含了正确的标记, 因此可以观察神经网络是否得到正确的答案。
在文本中, 这些记录或这些行的内容很容易理解:
第一个值是标签, 即书写者实际希望表示的数字, 如“7”或“9”。 这是我们希望神经网络学习得到的正确答案。随后的值,由逗号分隔,是手写体数字的像素值。像素数组的尺寸是28乘以28,因此在标签后有784个值。
# 读取并显示数据集数据表示的含义
import numpy
import matplotlib.pyplot as plt
# %matplotlib inlinedata_file = open(".../mnist_train_100.csv", 'r')
data_list = data_file.readlines()
data_file.close()
print(len(data_list))# 显示第一个
all_values = data_list[0].split(',')
# 将文本字符串转换成实数, .reshape((28,28))可以确保数字列表每28个元素折返一次,形成28乘28的方形矩阵
image_array = numpy.asfarray(all_values[1:]).reshape((28, 28))
# 对图像做处理
plt.imshow(image_array, cmap='Greys', interpolation='None')
# 显示图像
plt.show()
在将数据抛给神经网络之前需要准备数据
我们先前看到,如果输入数据和输出值, 形状正好适合, 这样它们就可以待在网络节点激活函数的舒适区域内,那么神经网络的工作会更出色。
我们需要做的第一件事情是将输入颜色值从较大的0到255的范围,缩放至较小的0.01 到 1.0的范围。 我们刻意选择0.01作为范围最低点,是为了避免先前观察到的0值输入最终会人为地造成权重更新失败。我们没有选择0.99作为输入的上限值, 是因为不需要避免输入1.0会造成这个问题。 我们只需要避免输出值为1.0。
将在0到255范围内的原始输入值除以255,就可以得到0到1范围的输入值。
然后,需要将所得到的输入乘以0.99,把它们的范围变成0.0 到0.99。接下来,加上0.01,将这些值整体偏移到所需的范围0.01到1.00。
scaled_input = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01
现在, 我们需要思考神经网络的输出。 先前, 我们看到输出值应该匹配激活函数可以输出值的范围。 我们使用的逻辑函数不能输出如 -2.0 或 255 这样的数字,能输出的范围为0.0到1.0,事实上不能达到0.0或1.0,这是逻辑函数的极限值,逻辑函数仅接近这两个极限,但不能真正到达那里。因此,看起来在训练时必须调整目标值。
我们要求神经网络对图像进行分类, 分配正确的标签。 这些标签是0到9共10个数字中的一个。 这意味着神经网络应该有10个输出层节点, 每个节点对应一个可能的答案或标签。 如果答案是“0”, 输出层第一个节点激发, 而其余的输出节点则保持抑制状态。

依照这种方向,我们可以构建目标矩阵
onodes = 10
targets = numpy.zeros(onodes) + 0.01
targets[int(all_values[0])] = 0.99
# 训练网络
def train_network(network, output_nodes, train_path, epochs):# 加载MNIST训练数据集training_data_file = open(train_path, 'r')training_data_list = training_data_file.readlines()training_data_file.close()# 训练世代,即训练几次for e in range(epochs):# 遍历读取的训练集for record in training_data_list:all_values = record.split(',')# 将文本字符串转换成实数,并将输入颜色值从0~255缩小为0.01~1.0,保证输入inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01# 目标数组targets = numpy.zeros(output_nodes) + 0.01# 设置目标数字对应的数组内容为0.99targets[int(all_values[0])] = 0.99network.train(inputs, targets)passpass# 测试单个输入
def query_network_one_input(network, img_data):# 设置输入inputs = (numpy.asfarray(img_data[:]) / 255.0 * 0.99) + 0.01# 查询网络outputs = network.query(inputs)# 取出输出数组中的最高值对应的下标label = numpy.argmax(outputs)return label# 测试文件,文件中有多条数据
def query_network(network, test_path):# 读取测试数据test_data_file = open(test_path, 'r')test_data_list = test_data_file.readlines()test_data_file.close()# 评分表,回答正确添加一个1scorecard = []for record in test_data_list:all_values = record.split(',')# 取出目标数字correct_label = int(all_values[0])print("aim=", correct_label, end="")# 设置输入inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01# 查询网络outputs = network.query(inputs)# 取出输出数组中的最高值对应的下标label = numpy.argmax(outputs)print("ans=", label)# 设置评分表if (label == correct_label):scorecard.append(1)else:scorecard.append(0)passpass# 计算正确率scorecard_array = numpy.asarray(scorecard)print("performance = ", scorecard_array.sum() / scorecard_array.size)# 保存神经网络对象
def save_network(path, network):with open(path, 'wb') as f:pickle.dump(network, f)# 加载神经网络对象
def load_network(path):with open(path, 'rb') as f:network = pickle.load(f)return network
改进网络
调整学习率
学习率是影响梯度下降发生速度的重要参数。

多次运行
通过提供更多爬下斜坡的机会, 有助于在梯度下降过程中进行权重更新

结果呈现出不可预测性。 在大约5或7个世代时, 有一个甜蜜点。 在此之后, 性能会下降, 这可能是过度拟合的效果。 性能在6个世代的情况下下降, 这可能是运行中出了问题, 导致网络在梯度下降过程中被卡在了一个局部的最小值中。 事实上, 由于没有对每个数据点进行多次实验, 无法减
小随机过程的影响,

直观上, 如果你打算使用更长的时间(多个世代) 探索梯度下降, 那么你可以承受采用较短的步长(学习率) , 并且在总体上可以找到更好的路径, 这是有道理的。 确实, 对于MNIST学习任务, 我们的神经网络的甜蜜点看起来是5个世代。 请再次记住, 我们在使用一种相当不科学的方式来进行实验。 要正确、 科学地做到这一点, 就必须为每个学习率和世代组合进行多次实验, 尽量减少在梯度下降过程中随机性的影响。
改变网络形状
随着增加隐藏层节点的数量, 结果有所改善, 但是不显著。 由于增加一个隐藏层节点意味着增加了到前后层的每个节点的新网络链接, 这一切都会产生额外较多的计算, 因此训练网络所用的时间也显著增加了! 因此, 必须在可容忍的运行时间内选择某个数目的隐藏层节点。
手写数字
import imageio.v2 as imageio
import neuralNetwork
import splitimg# 分割图片保存目录
test = ".../test/"# 分析含有多个数字的图片
def parse_img_numbers(img_path, network):result = 0number = splitimg.split_img(img_path, test)for i in range(0, number):img_array = imageio.imread(test + '%d.jpg' % i, pilmode='L')img_data = 255.0 - img_array.reshape(784)label = neuralNetwork.query_network_one_input(network, img_data)result += label * pow(10, number-1)number -= 1print(result)# 分析只有一个数字的图片
def parse_img(img_path, network):img_array = imageio.imread(img_path, pilmode='L')img_data = 255.0 - img_array.reshape(784)label = neuralNetwork.query_network_one_input(network, img_data)return label
# 按数字分割图片
import cv2
import numpy as npP_A = 10def split_img(source_path, temp_save_path):# 图像resizedsize = 28img = cv2.imread(source_path)data = np.array(img)height = data.shape[0]width = data.shape[1]# 设置最小的文字像素高度min_val = 10start_i = -1end_i = -1# 存放每行的起止坐标rowinfo = []# 行分割for i in range(height):# 行中有字相关信息if (not data[i].all()):end_i = iif (start_i < 0):start_i = ipass# 行中无字相关信息elif (data[i].all() and start_i >= 0):if (end_i - start_i >= min_val):rowinfo.append((start_i, end_i))passstart_i, end_i = -1, -1# 列分割start_j = -1end_j = -1# 最小文字像素宽度min_val_word = 5# 分割后保存编号number = 0for start, end in rowinfo:for j in range(width):# 列中有字相关信息if (not data[start: end, j].all()):end_j = jif (start_j < 0):start_j = jpass# 列中无字信息elif (data[start: end, j].all() and start_j >= 0):if (end_j - start_j >= min_val_word):img = data[start:end, start_j: end_j]im2save = cv2.resize(cv2.copyMakeBorder(img, P_A, P_A, P_A, P_A, cv2.BORDER_CONSTANT, value=(255, 255, 255)), (28, 28)) # 归一化处理cv2.imwrite(temp_save_path + '%d.jpg' % number, im2save)number += 1passstart_j, end_j = -1, -1return number
让我们来看看是否可以到神经网络内部一探究竟, 是否能够理解神经网络所学习到的知识, 将神经网络通过训练搜集到的知识可视化。
我们可以观察权重, 这毕竟是神经网络学习的内容。 但是, 权重不太可能告诉我们太多信息。 特别是, 神经网络的工作方式是将学习分布到不同的链接权重中。 这种方式使得神经网络对损坏具有了弹性, 这就像是生物大脑的运行方式。 删除一个节点甚至相当多的节点, 都不太可能彻底破坏神经网络良好的工作能力。
向后查询

https://github.com/makeyourownneuralnetwork/makeyourownneuralnetwork/blob/master/part3_neural_network_mnist_backquery.ipynb
上面是反向查询神经网络的代码
为了学习多样的变化类型,我们可以通过旋转图像创建新的训练数据
# create rotated variations
# rotated anticlockwise by 10 degrees
inputs_plus10_img = scipy.ndimage.interpolation.rotate(scaled_input.reshape(28,28), 10,cval=0.01, reshape=False)
# rotated clockwise by 10 degrees
inputs_minus10_img=scipy.ndimage.interpolation.rotate(scaled_input.reshape(28,28), -10,cval=0.01, reshape=False)

相关文章:
2.神经网络的实现
创建神经网络类 import numpy # scipy.special包含S函数expit(x) import scipy.special # 打包模块 import pickle# 激活函数 def activation_func(x):return scipy.special.expit(x)# 用于创建、 训练和查询3层神经网络 class neuralNetwork:# 初始化神经网络def __init__(se…...
合宙Air724UG LuatOS-Air LVGL API控件-键盘 (Keyboard)
键盘 (Keyboard) LVGL 可以添加触摸键盘,但是很明显,使用触摸键盘的话必须要使用触摸的输入方式,否则无法驱动键盘。 示例代码 function keyCb(obj, e)-- 默认处理事件lvgl.keyboard_def_event_cb(keyBoard, e)if(e lvgl.EVENT_CANCEL)the…...
pytorch深度学习实践
B站-刘二大人 参考-PyTorch 深度学习实践_错错莫的博客-CSDN博客 线性模型 import numpy as np import matplotlib.pyplot as pltx_data [1.0, 2.0, 3.0] y_data [2.0, 4.0, 6.0]def forward(x):return x * wdef loss(x, y):y_pred forward(x)return (y_pred - y) ** 2# …...
直方图反向投影(Histogram Backprojection)
直方图反向投影(Histogram Backprojection)是一种在计算机视觉中用于对象检测和图像分割的技术。它的原理基于图像的颜色分布,允许我们在一幅图像中找到与给定对象颜色分布相匹配的区域。这个技术常常用于图像中的目标跟踪、物体识别和图像分…...
day32 泛型 数据结构 List
一、泛型 概述 JDK1.5同时推出了两个和集合相关的特性:增强for循环,泛型 泛型可以修饰泛型类中的属性,方法返回值,方法参数, 构造函数的参数 Java提供的泛型类/接口 Collection, List, Set,Iterator 等 …...
DW-AHB Central DMAC
文章目录 AHB Central DMAC —— Design Ware AHB Central DMAC —— Design Ware AHB(Adavenced High-performace BUS) Central DMAC(Direct Memory Access Controller) : 一个高性能总线系统。 作用:在嵌入式系统种连接高速设备,如处理器内存&#x…...
JavaScript设计模式(四)——策略模式、代理模式、观察者模式
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
JS画布的基本使用
直线 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> <style> #myname{ border: 1px solid red; /* background: linear-gradient(to righ…...
c++ set/multiset
set/multiset 集合,一个单个,一个多个(multi)。两个库都是"set"。 https://blog.csdn.net/fckbb/article/details/130917681 对象创建 set(const Pred& compPred(),const A& alA()):创建空集合。set(const set& x):…...
多线程与高并发——并发编程(4)
文章目录 四、阻塞队列1 基础概念1.1 生产者消费者概念1.2 JUC阻塞队列的存取方法2 ArrayBlockingQueue2.1 ArrayBlockingQueue的基本使用2.2 生产者方法实现原理2.2.1 ArrayBlockingQueue的常见属性2.2.2 add方法2.2.3 offer方法2.2.4 offer(time,unit)方法2.2.5 put方法2.3 消…...
设计模式之建造者模式
文章目录 盖房项目需求传统方式解决盖房需求传统方式的问题分析建造者模式概述是建造者模式的四个角色建造者模式原理类图建造者模式的注意事项和细节 盖房项目需求 需要建房子:这一过程为打桩、砌墙、封顶房子有各种各样的,比如普通房,高楼…...
源码编译安装opencv4.6.0,别的版本也行
1.下载opencv4.6.0 系统: ubuntu 1804 64位点我下载opencv 4.6.0 https://codeload.github.com/opencv/opencv/zip/refs/tags/4.6.0 指令下载 推荐: wget -O opencv.zip https://github.com/opencv/opencv/archive/4.6.0.zip wget -O opencv_contrib.zip https://github.com/…...
【MongoDB】Springboot中MongoDB简单使用
1. docker安装MongoDB 拉取镜像 docker pull mongo创建容器 docker run -di --name mongo-service --restartalways -p 27017:27017 -v ~/data/mongodata:/data mongo2. 导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactI…...
Python 面试:单元测试unit testing 使用pytest
1. 对于函数进行单元测试 calc.py def add(x, y):"""Add Function"""return x ydef subtract(x, y):"""Subtract Function"""return x - ydef multiply(x, y):"""Multiply Function""…...
螺旋矩阵、旋转矩阵、矩阵Z字打印
螺旋矩阵 #include <iostream> #include <vector> void display(std::vector<std::vector<int>>&nums){for(int i 0; i < nums.size(); i){for(int j 0; j < nums[0].size(); j){std::cout<<nums[i][j]<< ;}std::cout<<…...
Seaborn绘制热力图的子图
Seaborn绘制热力图的子图 提示:如何绘制三张子图 绘制的时候,会出现如下问题 (1)如何绘制1*3的子图 (2)三个显示条,如何只显示最后一个 提示:下面就展示详细步骤 Seaborn绘制热力…...
C++二级题目4
小白鼠再排队 不会 多余的数 #include<iostream> #include<string.h> #include<stdio.h> #include<iomanip> #include<cmath> #include<bits/stdc.h> int a[2000][2000]; int b[2000]; char c[2000]; long long n; using namespace std; i…...
Tomcat 部署时 war 和 war exploded区别
在 Tomcat 调试部署的时候,我们通常会看到有下面 2 个选项。 是选择war还是war exploded 这里首先看一下他们两个的区别: war 模式:将WEB工程以包的形式上传到服务器 ;war exploded 模式:将WEB工程以当前文件夹的位置…...
Delphi IdTcpServer IdTcpClient 传输简单文本
Delphi IdTcpServer IdTcpClient 传输简单文本 已经很久敲代码了,想找一段直接Delphi11 TCP简单文本传输,费劲!FStringStream 、FStrStream : FStringStream:TStringStream.Create(,TEncoding.UTF8); 已经很久敲代码了,…...
界面控件Telerik UI for WPF——Windows 11主题精简模式提升应用体验
Telerik UI for WPF拥有超过100个控件来创建美观、高性能的桌面应用程序,同时还能快速构建企业级办公WPF应用程序。Telerik UI for WPF支持MVVM、触摸等,创建的应用程序可靠且结构良好,非常容易维护,其直观的API将无缝地集成Visua…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
