CNN | 02实现几何图形分类

2024-03-07 17:58

本文主要是介绍CNN | 02实现几何图形分类,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文及数据集

https://github.com/microsoft/ai-edu/tree/master/%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/A2-%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86/%E7%AC%AC8%E6%AD%A5%20-%20%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C

2 实现几何图形分类

2.1 提出问题

有一种儿童玩具:在一个平板上面有三种形状的洞:圆形、三角形、正方形,让小朋友们拿着这三种形状的积木从对应的洞中穿过那个平板就算成功。如果形状不对是穿不过去的,比如一个圆形的积木无法穿过一个方形的洞。这就要求儿童先学会识别几何形状,学会匹配,然后手眼脑配合才能成功。

人工智能现在还是初期阶段,它能否达到3岁儿童的能力呢?先看一下图18-21所示的样本数据。

图18-21 样本数据

一共有5种形状:圆形、菱形、直线、矩形、三角形。上图中列出了一些样本,由于图片尺寸是28x28的灰度图,所以在放大显示后可以看到很多锯齿,读者可以忽略。需要强调的是,每种形状的尺寸和位置在每个样本上都是有差异的,它们的大小和位置都是随机的,比如圆形的圆心位置和半径都是不一样的,还有可能是个椭圆。

其实二维几何形状识别是一个经典的话题了,如果不用神经网络的话,用一些传统的算法已经实现了,有兴趣的读者可以查询相关的知识,比如OpenCV库中就提供了一套方法。

2.2 用前馈神经网络解决问题

我们下面要考验一下神经网络的能力。我们先用前面学过的全连接网络来解决这个问题,搭建一个三层的网络如下:

def dnn_model():num_output = 5max_epoch = 50batch_size = 16learning_rate = 0.1params = HyperParameters_4_2(learning_rate, max_epoch, batch_size,net_type=NetType.MultipleClassifier,init_method=InitialMethod.MSRA,optimizer_name=OptimizerName.SGD)net = NeuralNet_4_2(params, "pic_dnn")f1 = FcLayer_2_0(784, 128, params)net.add_layer(f1, "f1")r1 = ActivationLayer(Relu())net.add_layer(r1, "relu1")f2 = FcLayer_2_0(f1.output_size, 64, params)net.add_layer(f2, "f2")r2 = ActivationLayer(Relu())net.add_layer(r2, "relu2")f3 = FcLayer_2_0(f2.output_size, num_output, params)net.add_layer(f3, "f3")s3 = ClassificationLayer(Softmax())net.add_layer(s3, "s3")return net

样本数据为28x28的灰度图,所以我们要把它展开成1x784的向量,第一层用128个神经元,第二层用64个神经元,输出层5个神经元接Softmax分类函数。

最后可以得到如下训练结果。

图18-22 训练过程中损失函数值和准确度的变化

在测试集上得到的准确度是89.8%,这已经超出笔者的预期了,本来猜测准确度会小于80%。有兴趣的读者可以再精调一下这个前馈神经网络网络,看看是否可以得到更高的准确度。

2.3 用卷积神经网络解决问题

下面我们来看看卷积神经网络能不能完成这个工作。首先搭建网络模型如下:

def cnn_model():num_output = 5max_epoch = 50batch_size = 16learning_rate = 0.1params = HyperParameters_4_2(learning_rate, max_epoch, batch_size,net_type=NetType.MultipleClassifier,init_method=InitialMethod.MSRA,optimizer_name=OptimizerName.SGD)net = NeuralNet_4_2(params, "shape_cnn")c1 = ConvLayer((1,28,28), (8,3,3), (1,1), params)net.add_layer(c1, "c1")r1 = ActivationLayer(Relu())net.add_layer(r1, "relu1")p1 = PoolingLayer(c1.output_shape, (2,2), 2, PoolingTypes.MAX)net.add_layer(p1, "p1") c2 = ConvLayer(p1.output_shape, (16,3,3), (1,0), params)net.add_layer(c2, "c2")r2 = ActivationLayer(Relu())net.add_layer(r2, "relu2")p2 = PoolingLayer(c2.output_shape, (2,2), 2, PoolingTypes.MAX)net.add_layer(p2, "p2") params.learning_rate = 0.1f3 = FcLayer_2_0(p2.output_size, 32, params)net.add_layer(f3, "f3")bn3 = BnLayer(f3.output_size)net.add_layer(bn3, "bn3")r3 = ActivationLayer(Relu())net.add_layer(r3, "relu3")f4 = FcLayer_2_0(f3.output_size, num_output, params)net.add_layer(f4, "f4")s4 = ClassificationLayer(Softmax())net.add_layer(s4, "s4")return net

表18-2展示了模型中各层的作用和参数。

表18-2 模型各层的作用和参数

ID类型参数输入尺寸输出尺寸
1卷积8x3x3, S=1,P=11x28x288x28x28
2激活Relu8x28x288x28x28
3池化2x2, S=2, Max8x28x288x14x14
4卷积16x3x3, S=18x14x1416x12x12
5激活Relu16x12x1216x12x12
6池化2x2, S=2, Max16x6x616x6x6
7全连接3257632
8归一化3232
9激活Relu3232
10全连接5325
11分类Softmax55

经过50个epoch的训练后,我们得到的结果如图18-23。

图18-23 训练过程中损失函数值和准确度的变化

以下是打印输出的最后几行:

......
epoch=49, total_iteration=14099
loss_train=0.002093, accuracy_train=1.000000
loss_valid=0.163053, accuracy_valid=0.944000
time used: 259.32207012176514
testing...
0.935
load parameters
0.96

可以看到我们在测试集上得到了96%的准确度,比前馈神经网络模型要高出很多,这也证明了卷积神经网络在图像识别上的能力。

图18-24是部分测试集中的测试样本的预测结果。

图18-24 测试结果

绝大部分样本预测是正确的,只有最后一个样本,看上去应该是一个很扁的三角形,被预测成了菱形。

2.4 形状分类可视化解释

图18-25 可视化解释

参看图18-25,表18-3解释了8个卷积核的作用。

表18-3 8个卷积核的作用

卷积核序号作用直线三角形菱形矩形圆形
1左侧边缘01011
2大色块区域01111
3左上侧边缘01101
445度短边11101
5右侧边缘、上横边00011
6左上、右上、右下01101
7左边框和右下角00011
8左上和右下,及背景00101

表18-3中,左侧为卷积核的作用,右侧为某个特征对于5种形状的判别力度,0表示该特征无法找到,1表示可以找到该特征。

  1. 比如第一个卷积核,其作用为判断是否有左侧边缘,那么第一行的数据为[0,1,0,1,1],表示对直线和菱形来说,没有左侧边缘特征,而对于三角形、矩形、圆形来说,有左侧边缘特征。这样的话,就可以根据这个特征把5种形状分为两类:

    • A类有左侧边缘特征:三角形、矩形、圆形
    • B类无左侧边缘特征:直线、菱形
  2. 再看第二个卷积核,是判断是否有大色块区域的,只有直线没有该特征,其它4种形状都有。那么看第1个特征的B类种,包括直线、菱形,则第2个特征就可以把直线和菱形分开了。

  3. 然后我们只关注A类形状,看第三个卷积核,判断是否有左上侧边缘,对于三角形、矩形、圆形的取值为[1,0,1],即矩形没有左上侧边缘,这样就可以把矩形从A类中分出来。

  4. 对于三角形和圆形,卷积核5、7、8都可以给出不同的值,这就可以把二者分开了。

当然,神经网络可能不是按照我们分析的顺序来判定形状的,这只是其中的一种解释路径,还可以有很多其它种路径的组合,但最终总能够把5种形状分开来。

代码位置

ch18, Level2

思考和练习

  1. 我们使用了3x3的卷积核,如果用5x5的卷积核,但是在其它参数不变的情况下,其效果会不会更好?
  2. 可以建立一个数据集,只包括正圆、椭圆、正方形、矩形等四种形状,看看卷积神经网络是不是能分辨出来。

这篇关于CNN | 02实现几何图形分类的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

Golang如何用gorm实现分页的功能

《Golang如何用gorm实现分页的功能》:本文主要介绍Golang如何用gorm实现分页的功能方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景go库下载初始化数据【1】建表【2】插入数据【3】查看数据4、代码示例【1】gorm结构体定义【2】分页结构体

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C