目录

介绍

背景

使用代码

解决方案

为什么这么多框架?

解析Mnist数据

实例化和训练神经网络

Mnist培训师

前进通行证

反向传播

Mnist测试用户界面

图像预处理

最后


C#面向对象的神经网络,培训师和Windows窗体用户界面,用于识别手写数字。

  • 下载源文件 - 18.5 MB

介绍

该源代码演示了如何训练和使用神经网络来解释手写数字。
本文不会有任何数学知识。这完全是关于基础的机器学习的C#实现。

背景

使用Mnist手写数字数据集2训练人工神经网络人工神经网络(ANN) 。这是数据科学领域的经典问题。它也被称为机器学习的Hello World应用程序。 Code Project上已经发布了一些关于此主题的演示应用程序,但我认为我的源代码可以帮助某人。复杂的问题可能需要不止一个解释,我试图让它尽可能简单。

使用代码

在Visual Studio 2017中下载,解压缩并打开解决方案。

解决方案

该解决方案包含五个项目:

项目

描述

骨架

DeepLearningConsole

训练控制台的入口点

.NET Core 2.2

DeepLearning

主库

.NET Standard 2.0

Data

解析数据。目前只有Mnist。

.NET Standard 2.0

MnistTestUi

用于手动测试的用户界面

.NET Framework 4.7.1

Tests

一些单元测试

.NET Core 2.2

为什么这么多框架?

我意识到.NET Core比.NET Framework快了大约30%,我想在Windows Forms应用程序中使用.NET Framework。
遗憾的是,您无法从.NET Framework引用.NET Core库。它们不兼容。
为解决这个问题,我使用.NET Standard作为通用组件。

.NET Standard不是一个框架。它是.NET API的正式规范。
所有.NET实现都应该与它兼容,不仅仅是.NET Core和.NET Framework,还有Xamarine,Mono,Unity和Windows Mobile。
这就是为可重用组件选择目标框架(Target Framework)的原因。

解析Mnist数据

这些是Mnist数据库中的四个文件:

  • t10k-images-idx3-ubyte——测试图像
  • t10k-labels-idx1-ubyte——测试图像的标签
  • train-images-idx3-ubyte——培训图像(60000)
  • train-labels-idx1-ubyte——60000次培训图像的标签

Mnist中的图像必须从字节数组转换为从0到1的双精度数组。
这些文件还包含一些标题字段。

private static List<Sample> LoadMnistImages(string imgFileName, string idxFileName, int imgCount)
{var imageReader = File.OpenRead(imgFileName);var byte4 = new byte[4];imageReader.Read(byte4, 0, 4); //magic numberimageReader.Read(byte4, 0, 4); //magic numberArray.Reverse(byte4);//var imgCount = BitConverter.ToInt32(byte4, 0);imageReader.Read(byte4, 0, 4); //width (28)imageReader.Read(byte4, 0, 4); //height (28)var samples = new Sample[imgCount];var labelReader = File.OpenRead(idxFileName);labelReader.Read(byte4, 0, 4);//magic numberlabelReader.Read(byte4, 0, 4);//countvar targets = GetTargets();for (int i = 0; i < imgCount; i++){samples[i].Data = new double[784];var buffer = new byte[784];imageReader.Read(buffer, 0, 784);for (int b = 0; b < buffer.Length; b++)samples[i].Data[b] = buffer[b] / 256d;samples[i].Label = labelReader.ReadByte();samples[i].Targets = targets[samples[i].Label];}return samples.ToList();
}

解析过程产生两个训练和测试样本列表。
样本由图像像素数组和长度为10的目标数组组成,目标数组是图像所在的数字的信息。
数字零是数组:1,0,0,0,0,0,0,0,0,0。
数字五是:0,0,0,0,1,0,0,0,0,0(五分之一),依此类推。

实例化和训练神经网络

要实例化新的人工神经网络(ANN),您需要提供其拓扑,层数和每层中的神经元数量。
必须有784个神经元输入用于mnist图像(28x28像素)。输出层必须具有10。
培训师类使用TrainData指定的学习速率训练神经网络。

var neuralNetwork = new NeuralNetwork(rndSeed: 0, sizes: new[] { 784, 200, 10 });
neuralNetwork.LearnRate = 0.3;
var trainer = new Trainer(neuralNetwork, Mnist.Data);
trainer.Train();

接下来,每个训练样本都被送到网络,以便学习。
我发现隐藏层中的200个神经元使得人工神经网络(人工神经网络(ANN))的准确率达到98.5%,这似乎已经足够了。
有400个神经元,精度最高可达98.8%,但需要两倍的时间训练。

Mnist培训师

培训师反复训练人工神经网络(ANN),让它看到一个训练样本。
所有60000张训练图像中的一个循环称为纪元。

在每个纪元之后,人工神经网络(ANN)被序列化并保存到文件中。
然后针对测试样本测试人工神经网络(ANN),并将结果记录到csv文件中。
训练图像也在每个纪元之间进行混洗。

public void Train(int epochs = 100)
{            var rnd = new Random(0);var name = $"Sigmoid LR{NeuralNetwork.LearnRate} HL{NeuralNetwork.Layers[1].Count}";var csvFile = $"{name}.csv";var bestResult = 0d;for (int epoch = 1; epoch < epochs; epoch++){Shuffle(TrainData.TrainSamples, rnd);TrainEpoch();                var result = Test();Log($"Epoch {epoch} {result.ToString("P")}");File.AppendAllText(csvFile, $"{epoch};{result};{NeuralNetwork.TotalError}\r\n");if (result > bestResult){NeuralNetwork.Save($"{name}.bin");Log($"Saved {name}.bin");bestResult = result;}}}

前进通行证

这通过总结所有先前神经元乘以其权重来计算每个神经元值。
然后通过激活函数传递该值。然后可以从最后一层(也称为输出层)获得结果或输出。

private void Compute(Sample sample, bool train)
{for (int i = 0; i < sample.Data.Length; i++)Layers[0][i].Value = sample.Data[i];for (int l = 0; l < Layers.Length - 1; l++){for (int n = 0; n < Layers[l].Count; n++){var neuron = Layers[l][n];foreach (var weight in neuron.Weights)weight.ConnectedNeuron.Value += weight.Value * neuron.Value;}var neuronCount = Layers[l + 1].Count;if (l + 1 < Layers.Count() - 1)neuronCount--; //skipping biasfor (int n = 0; n < neuronCount; n++){var neuron = Layers[l + 1][n];neuron.Value = LeakyReLU(neuron.Value / Layers[l].Count);}}
}

反向传播

该算法调整神经元之间的所有权重。它使网络学习并逐步提高其性能。

private void ComputeNextWeights(double[] targets)
{var output = OutputLayer;for (int t = 0; t < output.Count; t++)output[t].Target = targets[t];//Output Layerforeach (var neuron in output){neuron.Error = Math.Pow(neuron.Target - neuron.Value, 2) / 2;neuron.Delta = (neuron.Value - neuron.Target) * (neuron.Value > 0 ? 1 : 1 / 20d));}this.TotalError = output.Sum(n => n.Error);foreach (var neuron in Layers[1]){foreach (var weight in neuron.Weights)weight.Delta = neuron.Value * weight.ConnectedNeuron.Delta;}//Hidden LayerParallel.ForEach(Layers[0], GetParallelOptions(), (neuron) => {foreach (var weight in neuron.Weights){foreach (var connectedWeight in weight.ConnectedNeuron.Weights)weight.Delta += connectedWeight.Value * connectedWeight.ConnectedNeuron.Delta;var cv = weight.ConnectedNeuron.Value;weight.Delta *= (cv > 0 ? 1 : 1 / 20d);weight.Delta *= neuron.Value;}});//All deltas are done. Now calculate new weights.for (int l = 0; l < Layers.Length - 1; l++){var layer = Layers[l];foreach (var neuron in layer)foreach (var weight in neuron.Weights)weight.Value -= (weight.Delta * this.LearnRate);}
}

Mnist测试用户界面

Test UI用于测试您自己的手写内容。它有两个面板。小面板解释单个绘制的数字,而在较大的底部,您可以绘制一个数字。

图像预处理

Mnist数据库主页说明:

来自NIST的原始黑白(双层)图像的大小被标准化以适应20x20像素的盒子,同时保留它们的宽高比。由于归一化算法使用的抗锯齿技术,得到的图像包含灰度级。通过计算像素的质心,并将图像平移以便将该点定位在28x28域的中心,图像以28x28图像为中心。

以下是如何使用位图和Windows窗体图形进行操作的说明。

首先,找到绘制数字周围的最小方块。

public Rectangle DrawnSquare()
{var fromX = int.MaxValue;var toX = int.MinValue;var fromY = int.MaxValue;var toY = int.MinValue;var empty = true;for (int y = 0; y < Bitmap.Height; y++){for (int x = 0; x < Bitmap.Width; x++){var pixel = Bitmap.GetPixel(x, y);if (pixel.A > 0){empty = false;if (x < fromX)fromX = x;if (x > toX)toX = x;if (y < fromY)fromY = y;if (y > toY)toY = y;}}}if (empty)return Rectangle.Empty;var dx = toX - fromX;var dy = toY - fromY;var side = Math.Max(dx, dy);if (dy > dx)fromX -= (side - dx) / 2;elsefromY -= (side - dy)/ 2;return new Rectangle(fromX, fromY, side, side);
}

裁剪出正方形并调整大小为20x20的新位图。

public DirectBitmap CropToSize(Rectangle drawnRect, int width, int height)
{var bmp = new DirectBitmap(width, height);bmp.Bitmap.SetResolution(Bitmap.HorizontalResolution, Bitmap.VerticalResolution);var gfx = Graphics.FromImage(bmp.Bitmap);gfx.CompositingQuality = CompositingQuality.HighQuality;gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;gfx.PixelOffsetMode = PixelOffsetMode.HighQuality;gfx.SmoothingMode = SmoothingMode.AntiAlias;var rect = new Rectangle(0, 0, width, height);gfx.DrawImage(Bitmap, rect, drawnRect, GraphicsUnit.Pixel);return bmp;
}

最后,绘制20 x 20的图像,其质心集中在28x28位图内。

public Point GetMassCenterOffset()
{var path = new List<Vector2>();for (int y = 0; y < Height; y++){for (int x = 0; x < Width; x++){var c = GetPixel(x, y);if (c.A > 0)path.Add(new Vector2(x, y));}}var centroid = path.Aggregate(Vector2.Zero, (current, point) => current + point) / path.Count();return new Point((int)centroid.X - Width / 2, (int)centroid.Y - Height / 2);
}protected DirectBitmap PadAndCenterImage(DirectBitmap bitmap)
{var drawnRect = bitmap.DrawnRectangle();if (drawnRect == Rectangle.Empty)return null;var bmp2020 = bitmap.CropToSize(drawnRect, 20, 20);//Make image larger and center on center of massvar off = bmp2020.GetMassCenterOffset();var bmp2828 = new DirectBitmap(28, 28);var gfx2828 = Graphics.FromImage(bmp2828.Bitmap);gfx2828.DrawImage(bmp2020.Bitmap, 4 - off.X, 4 - off.Y);bmp2020.Dispose();return bmp2828;
}

然后,只需从图像中提取字节并使用它们查询人工神经网络(ANN)。

public byte[] ToByteArray()
{var bytes = new List<byte>();for (int y = 0; y < Bitmap.Height; y++){for (int x = 0; x < Bitmap.Width; x++){var color = Bitmap.GetPixel(x, y);var i = color.A;bytes.Add(i);}}return bytes.ToArray();
}

如果您对它们的外观感到好奇,界面(UI)还具有显示Mnist图像的功能。但是我不会过多地介绍界面(UI)的每个细节,因为我觉得我们正在脱离主题。

最后

我希望你喜欢我的文章,也许你学到了一些你还不知道的东西。如果您有任何问题,意见或想法,请留言。

原文地址:https://www.codeproject.com/Articles/1273125/Handwritten-Digits-Reader-UI

手写数字阅读器用户界面相关推荐

  1. 对于CNN的文献阅读和识别手写数字的复现

    摘要 一.文献阅读 1.题目 2.摘要 3.引言 4.CNN模型结构 5.实验过程 6.同GS算法的对比 二.CNN识别手写数字 1.两个性质 2.图像卷积 总结 摘要 在论文方面阅读了基于CNN网络 ...

  2. c++手写数字识别(贝叶斯分类器)

    大家好啊!这次的文章是上一个文章的后续,与上一次不同的是,这一次对数字识别采用的是贝叶斯(Bayes)分类器.前面的文件夹遍历以及将图片处理成数字字符串本篇文章就不介绍了,大家有兴趣可以看之前的文章: ...

  3. 【TensorFlow-windows】(三) 多层感知器进行手写数字识别(mnist)

    主要内容: 1.基于多层感知器的mnist手写数字识别(代码注释) 2.该实现中的函数总结 平台: 1.windows 10 64位 2.Anaconda3-4.2.0-Windows-x86_64. ...

  4. 深度学习-Pytorch:项目标准流程【构建、保存、加载神经网络模型;数据集构建器Dataset、数据加载器DataLoader(线性回归案例、手写数字识别案例)】

    1.拿到文本,分词,清晰数据(去掉停用词语): 2.建立word2index.index2word表 3.准备好预训练好的word embedding 4.做好DataSet / Dataloader ...

  5. python-机器学习-手写数字识别

    机器学习简单的来说,分为监督式学习和无监督式学习: 对于监督式学习就是需要人为的来告诉计算机这是什么,需要我们给他一个标签(答案). 无监督式学习就是不需要我们给出标签(答案). 图像识别(Image ...

  6. 【深度学习】学习案例:Keras 多层感知器手写数字识别

    实验:Keras 多层感知器 手写数字识别 1. 下载 MNIST数据集(前提) 2. 进行数据预处理 3. 建立模型 4. 进行训练 5. 以测试数据评估模型 6. 进行预测 拓展: 1. 显示混淆 ...

  7. 朴素贝叶斯分类器_MINST手写数字识别

    朴素贝叶斯分类器_MINST手写数字识别 import numpy as np import pandas as pd from sklearn.preprocessing import Binari ...

  8. 利用朴素贝叶斯分类器实现手写数字的识别

    利用贝叶斯分类器实现手写数字的识别 贝叶斯决策理论: 条件:类别数一定,

  9. 全栈AI工程师指南,DIY一个识别手写数字的web应用

    作者 | shadow chi 本文经授权转载自 无界社区mixlab(ID:mix-lab) 网上大量教程都是教如何训练模型, 往往我们只学会了训练模型, 而实际应用的环节是缺失的. def AIF ...

最新文章

  1. 02搭建cdh版本控制
  2. Spring boot错误处理原理
  3. Python正则表达式尽可能小的匹配(遇到第一个结束字符串就停止匹配)
  4. javascript 嵌入python_通过Python将区块链数据嵌入Javascript,这是正确的方法吗?
  5. 基于softmax的文本多分类模型代码实现
  6. java创建xml设置路径_java 写入xml文件 地址如何设置为局域网内的另一台服务器上...
  7. redis中value大小_查看redis的Value值大小
  8. uBar如何设置Mac拥有Win式任务栏
  9. 恐龙母带混音插件-IK Multimedia T-RackS 5 MAX 5.5.1 macOS
  10. LORA 网关上电后对应配置 以及常用的AT指令
  11. GitLab强制关闭双因素认证
  12. CVPR'22 最新132篇论文分方向整理|包含目标检测、图像处理、医学影像等28个方向...
  13. Circos从入门到精通
  14. 新手进阶建模 (写论文摘要和看论文)
  15. 有机无脂牛奶的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  16. Spark抽取MySQL分表优化
  17. 戴尔笔记本电脑重装Win10 Pro 后,开机慢的解决方法,DELL Vostro 3420
  18. 【Excel--高级筛选】学习总结
  19. 蓝牙助手android,蓝牙助手手机版
  20. 误提交了target目下的文件怎么删除?

热门文章

  1. python创建双链表_Python双链表原理与实现方法详解
  2. 支付页面设计灵感|最美剁手的正确姿势!
  3. 导入数据_导入外部数据的三个技巧
  4. Intel VMM-虚拟机监控器
  5. 4KB/2MB/1GB 4级/5级分页模式下的线性地址翻译以及CR3
  6. 4G终端-基站-核心网 信令流与数据流
  7. matlab gui教程 计算器,matlab gui编写的计算器程序
  8. Django:DjangoProject项目结构简介
  9. Hadoop之MapReduce介绍
  10. ethtool -g rx_魔兽怀旧服:黑G团避坑指南