CNN基础识别-想为女儿批作业(二):卷积的使用

频道:生活应用 日期: 浏览:29

[id[id_2[id_803[id_1727273129]00894]7330787]689[id_1694102070]4121]<[id_2105762595]p>

[id_11[id_1225273739]5293031]

[id_17602[id_2070323403]199]

昨晚我做了一个梦,梦见我实现了这个功能,如下图所示:

操作正确时,可以标记为正确;出现失误时,可以标注为错误;遗漏部分,能够补充完整。

醒来后,我环顾四周,赶紧再躺下,希望梦还能接上。

二、实现步骤

今天主要讲如何训练和使用数据。

往期回顾

2.2 训练数据2.2.1 构建模型

你先看代码,外行感觉好深奥,内行偷偷地笑。

# %% 导入必要的包 
[id_1642446601] tensorflow as tf
import numpy as np
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
import pathlib
import cv2
# %% 构建模型
def create_model():
    model = Sequential([
实验性预处理层中的缩放功能1./255, input_shape=(24, 24[id_247927550] 1)),
        layers.Conv2D(24,3,activation='relu'),
        layers.MaxPooling2D((2,2)),
        layers.Conv2D(64,3, activation='relu'),
        layers.MaxPooling2D((2,2)),
        layers.Flatten(),
        layers.Dense(128, activation='relu'),
        layers.Dense(15)]
    )
    
    model.compile(optimizer='adam',
损失函数是稀疏分类交叉熵,需要从逻辑值计算,True),
                metrics=['accuracy'])
    return model

该模型的结构如下,功能是接收一张图像信息,通过各部分处理后,最终判断出该图像属于哪一类。

graph TD
I(输入: 图片24*24像素)-->A
一个卷积运算单元连接到第一个池化单元,第一个池化单元连接到第二个卷积运算单元,第二个卷积运算单元连接到第二个池化单元,第二个池化单元连接到第一个全连接单元,第一个全连接单元连接到最后一个全连接单元
C --> O1(0: 30%)
C --> O2(1: 20%)
C --> O3(2: 0.5%)
C --> O4(... )
C --> O5(=: 1%)

这些层级各自承担什么功能,具体有何作用?它们跟衣物相似,显然并非无用,内层、中间层、外层各有其特定目的。

2.2.2 卷积层 Conv2D

各个职能部门的调查员,搜集和整理某单位区域内的特定数据。我们输入的是一张图像,该图像由像素构成,这就是Rescaling(1./255,inputshape=(24,24,1))Rescaling(1./255, input_shape=(24, 24, 1))Rescaling(1./255,inputs​hape=(24,24,1))中的内容,其中input_shape参数指定输入的形状为24乘以24个像素,仅包含一个通道,如果是彩色图像则会有三个通道。

卷积层代码里的设置是Conv2D(24,3),表示采用3×3像素的滤波器,目的是获取24种特征信息。

我把它放到地图上,你就能明白了。比如我们济南的市中区。

卷积的功能跟从地图的某个层级区域里汇集多种特定资料相似。比如以社区为基准来获取住宅数目、停车位数目、教育机构数目、居民总数、家庭收入、学历水平、年龄分布等共计二十四项数据。社区就相当于卷积的滤波器。

提取完成之后是这样的。

第一次卷积之后,我们从市中区得到N个小区的数据。

卷积是可以进行多次的。

例如先对社区进行一次卷积处理,接着还可以以社区为起点再执行一次卷积,这次卷积的输出便是街道层面。

对市中区每个街道再次进行以社区为单位的卷积运算,由此获得了N条街道的统计信息。

这就是卷积的作用。

反复进行卷积操作,可以将一张完整的图像,按照特定方式进行处理,最后得到的是若干组具有明确目标的数据,这样有助于后续的评判工作。这是针对某个区域的数据进行评判的方法,如果要评判济南市或者山东省,也是采用同样的卷积方式。这种方法与现实生活中的文明城市、经济强省的评选有着相似之处。

2.2.3 池化层 MaxPooling2D

说白了就是四舍五入。

电脑运算速度非常迅猛,远超人类反应,不过使用时仍需权衡代价。我们当然期盼它运行得更加迅速,倘若某个方案能将耗时减半,我们必定会选用该方案。

池化层的作用就是完成这个功能。池化层的代码设定为MaxPooling2D((2,2)) MaxPooling2D((2,2)) MaxPooling2D((2,2)),这种方式属于最大值池化。括号中的(2,2)代表池化区域的大小,意味着将2厘米乘以2厘米的范围看作一个整体来处理。

以地图作为另一个案例来说明,比如下方那16个方格所包含的信息,具体指的是各个街道上学校的分布情况。

为了提升运算效能,减少运算量,我们采用2*2的池化结构进行数据压缩。

每个池化单元由四个相邻街道组成,新区域内的学校数量以该区域内中学数量最多为准,也有选择中学数量最少或计算平均值等不同池化方式。经过池化处理,原先的十六个区域合并为四个,数据量因此得到压缩。

这就是池化层的作用。

2.2.4 全连接层 Dense

弱水三千,只取一瓢。

在这里,它其实是一个分类器。

我们制作它时,构造是Dense(15),Dense(15),Dense(15)。

它所进行的工作,不论你先前是什么状态,有多少种角度开yun体育app入口登录,在我这边必须强制改变为既定的路径。

例如辨认字母a到z,有500个神经单元负责分析,但最终形成的反应就是26个路径,分别对应a、b、c,一直到y、z。

我们这里一共有十五种不同的字符类型,因此对应十五个独立的通道。当接收到一个输入时,系统会为每一个分类计算其出现的可能性,并给出相应的概率值。

graph TD
I[其他类型的层]-->A
A[全连接层1 Dense 128]
A --> O1(1) --> C
A --> O2(2) --> C
A --> O3(3) --> C
A --> O6(4) --> C
A --> O7(5) --> C
A --> O4(... ) --> C
A --> O8(127) --> C
A --> O5(128) --> C
C[全连接层2 Dense 15]
C --> 1O1(1: 30%)
C --> 1O2(2: 20%)
C --> 1O3(3: 0.5%)
C --> 1O4(... )
C --> 1O5(15: 1%)

注意:那些都是平面型的输入,例如24×24,不过全连接层是线性的,因此程序里用了layers.Flatten()layers.Flatten()layers.Flatten()把平面数据转换成直线数据

11,12,21,22

)。

针对整体模型,执行model.summary(),model.summary(),model.summary(),即可输出序列的网络构造情况

_________________________________________________________________
类别 (类型)                结果 (形态)              参数 (数量)
那个东西非常巨大,简直难以想象,它静静地躺在那里,周围一片寂静,没有任何动静,仿佛时间都停止了流动,观察者感到十分震惊,完全被它的存在所震撼,脑海中不断浮现出各种难以言喻的景象,这种感觉持续了很久,直到他不得不承认,自己真的遇到了前所未有的事物。
rescaling进行比例调整,输出尺寸为24x24像素的单通道图像,参数值为零
_________________________________________________________________
conv2d_4 这个卷积层,输出维度是 22x22x24,总共参数数量为 240,没有其他依赖项,它的结构保持简单,执行过程直接,通过卷积操作生成特征图,每个输出特征图的大小固定,计算量适中,适合在网络的早期阶段使用,用于提取基本的图像特征,后续层可以利用这些特征进行更复杂的处理,整体设计上注重效率,同时保证了一定的特征提取能力,为整个网络提供坚实的基础,这种设计方式在许多视觉任务中表现良好,能够有效地处理输入数据,并传递有用的信息给后续组件,确保了模型的稳定性和可靠性,同时也方便了训练和调优过程,使得整个系统更加健壮,能够应对各种复杂的输入情况,展现出良好的泛化能力,这种结构在深度学习领域得到了广泛的应用,成为了一种常见的网络构建模式,通过不断的优化和改进,可以进一步提升其性能,满足更高的应用需求。
_________________________________________________________________
max_pooling2d_第四步,执行最大池化操作,其参数设置如下,输入张量维度为,无名称,尺寸为,11乘以11,通道数为,24,步长为,零,无填充
_________________________________________________________________
conv2d五号卷积层           维度是九乘九,深度为六十四,参数数量为一万三千八百八十八
_________________________________________________________________
max_pooling2d_最大池化层, 输出维度为4, 4, 64, 不产生参数
_________________________________________________________________
flatten将数据展开成线性结构,输出维度为一千零二十四,不使用任何偏置参数
_________________________________________________________________
dense四号密度层,不包含任何子层,每层输出128个节点,总参数量达到131200个
_________________________________________________________________
dense五号密度           没有其他标注,数量为十五个            一九三五年
=================================================================
Total params: 147,263
Trainable params: 147,263
Non-trainable params: 0
_________________________________________________________________

我们观察到conv2d_5层,其参数为(None, 9, 9, 64),在经过2*2的池化处理后,其形态转变为max_pooling2d_5层,参数变为(None, 4, 4, 64)。(None, 4, 4, 64) 在经过连续三次展平处理后,转化为(None, 1024) 的形状,随后通过全连接层处理开元棋官方正版下载,输出(None, 128) 的向量,接着再应用一次全连接,最终得到(None, 15) 的结果,这个15维向量就是模型用于完成分类任务的最终输出,整个网络结构是我们根据任务需求精心设计的。

配置模型时需要设定一些参数,现阶段只需了解即可,这些参数通过特定命令进行设置,具体操作可以稍后再学习,记住这些基本要点即可。

2.2.5 训练数据

执行就完了。

# 统计文件夹下的所有图片数量
data_dir = pathlib.Path('dataset')
# 从文件夹下读取图片,生成数据集
训练数据集通过函数从目录中生成,使用的是TensorFlow的Keras预处理模块,具体方法是调用image_dataset_from_directory工具,参数为目录路径
    data_dir, # 从哪个文件获取数据
    color_mode="grayscale", # 获取数据的颜色为灰度
    image_size=(24, 24), # 图片的大小尺寸
    batch_size=32 # 多少个图片为一个批次
)
# 数据集的分类,对应dataset文件夹下有多少图片分类
类别名称存储在train_ds的class_names属性中
# 保存数据集分类
np.save("class_name.npy", class_names)
# 数据集缓存处理
优化调整数据集处理流程时,采用自动配置资源的方式,确保运行效率最大化
数据集缓存起来之后,接着进行随机排序,并按照指定数量进行分批处理1000).预先加载缓存数据,其大小依据自适应调节机制动态确定
# 创建模型
model = create_model()
# 训练模型,epochs=10,所有数据集训练10遍
model.fit(train_ds,epochs=10)
# 保存训练后的权重
model.save_weights('checkpoint/char_checkpoint')

执行之后会输出如下信息:

Found 3900 files belonging to 15 classes. 
Epoch 1/10 122/122 [=========] - 两秒内十九毫秒一步,损失值是零点五七九五,准确率达到 0.8615 
Epoch 2/10 122/122 [=========] - 两秒内完成十八毫秒每步,损失值为零点零一,准确率达到预期水平 0.9992 
Epoch 3/10 122/122 [=========] - 两秒内十九毫秒一步,损失值是零点零二七,准确率达到 1.0000 
Epoch 4/10 122/122 [=========] - 两秒内完成十九毫秒每步,损失值是千分之十三,准确率达到 1.0000 
Epoch 5/10 122/122 [=========] - 两秒内完成二十毫秒一步,损失值为八百四十二万分之一点六,准确率达到 1.0000 
Epoch 6/10 122/122 [=========] - 两秒内完成十八毫秒每步,损失值是五点五二七三乘以负四,准确率表现良好 1.0000 
Epoch 7/10 122/122 [=========] - 三秒内每步二十一毫秒,损失值是四千零九十六点六微,准确率表现良好 1.0000 
Epoch 8/10 122/122 [=========] - 两秒内每二十毫秒一个步骤,损失值为三万零三十点八百万分之一,准确率达到 1.0000 
Epoch 9/10 122/122 [=========] - 三秒内完成每步只需二十三毫秒,损失值是零点零二三四六乘以十的负四次方,准确率达到 1.0000 
Epoch 10/10 122/122 [=========] - 三秒内每步二十一毫秒,损失值为一点八九七一乘以零点零零一,准确率达到 1.0000

我们注意到,到了第三次测试时,正确率已经达到了满分水平。临近结束时,我们发现在名为checkpoint的目录里新增了若干文档:

char_checkpoint.data-00000-of-00001
char_checkpoint.index
checkpoint

那些文件是训练的产物,训练完成后就无需再改动。接下来可以直接借助这些资料来进行预测。

2.3 预测数据

终于到了享受成果的时候了。

# 设置待识别的图片
img1=cv2.imread('img1.png',0) 
img2=cv2.imread('img2.png',0) 
imgs = np.array([img1,img2])
# 构建模型
model = create_model()
# 加载前期训练好的权重
model.load_weights('checkpoint/char_checkpoint')
# 读出图片分类
class_name = np.load('class_name.npy')
# 预测图片,获取预测值
模型对图片进行推断,得到预测结果,这些结果存储在变量predicts中
results = [] # 保存结果的数组
for predict in predicts: #遍历每一个预测结果
    index = np.argmax(predict) # 寻找最大值
    result = class_name[index] # 取出字符
    results.append(result)
print(results)

我们找两张图片img1.png

,img2.png

开yun体育官网入口登录app,一张为六号图案,另一张为八号图案,将二者置于程序相同目录中,检查一下辨识功能的表现情况。

图像需借助cv2.imread('img1.png',0)函数读取,并转为二维矩阵形式,其中0参数代表获取灰度图像,处理完毕后,所得矩阵的维度为(24,24)。

需要对照两张图像进行核实,因此将这两幅图像合并为imgs文件,并集中存放,imgs的构造形式为二维数组,包含两行,每行有二十四列,每列也有二十四行。

建立模型,接着载入参数。把imgs输入模型,调用predicts = model.predict(imgs)来获得预测结果。

predicts的结构是(2,15),数值如下面所示:

十六点一三四二四三,负十二点一零六七五,负一点一九九四一五四,负二十七点七六六七五四,负四十三点四三二四,负九点六三三六九四,负十二点二一四八七八,一点六二八七八九三,二点五六二一七四,三点二二二七零七,十三点八三四六四八,二十八点二五四一七三,负六点一零二八七四,十六点七六五八二,七点二五八六一八四

这个数列中,第一个数字是5.022571,紧接着是-8.762314,然后是-6.7466817,再往后是-23.494259,紧接着是-30.170597,然后是2.4392672,紧接着是-14.676962,然后是5.8255725,再往后是8.855118,紧接着是-2.0998626,然后是6.820853,紧接着是7.6578817,然后是1.5132296,再往后是24.4664,最后是2.4192357。

意思是有2个预测结果,每一个图片的预测结果有15种可能。

接着,依据 index = np.max(predict) 确定最大值的序号位置。

根据索引找到字符的数值结果是。

下面是数据在内存中的监控:

可见,我们的预测是准确的。

下面,我们将要把图片中数字切割出来,进行识别了。

网友留言(0)

评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。