专栏首页磐创AI技术团队的专栏TensorFlow2.0 实战强化专栏(一):Chars74项目

TensorFlow2.0 实战强化专栏(一):Chars74项目

作者 | 小猴锅

出品 | 磐创AI团队

Chars74K项目

字符识别是一种经典的模式识别问题,字符识别在现实生活中也有着非常广泛的应用,目前对于特定环境下的拉丁字符识别已经取得了很好的效果,但是对于一些复杂场景下的字符识别依然还有很多困难,例如通过手持设备拍摄以及自然场景中的图片等,Chars74K正是针对这些困难点搜集的数据集(http://www.ee.surrey.ac.uk/CVSSP/demos/chars74k/

Chars74K包含英语和坎那达语(Kannada)两种字符,在英文数据集中包括26个拉丁文字母和10个阿拉伯数字,整个英文数据集包括64种字符(0-9,a-z,A-Z),英文数据集根据采集方式又有三种不同数据集(三种英文数据集的样本数加在一起超过了74K,Chars74K的名字也是由此而来。):

1) 7705个自然图像中采集的字符数据集(EnglishImg.tgz);

2) 3410个在平板电脑上手写的字符数据集(EnglishHnd.tgz);

3) 62992个在从计算机字体合成的字符数据集(EnglishFnt.tgz)。

在本项目中我们使用第一个数据集,即从自然场景中采集到的字符数据集,部分数据如图1所示。

图1 Chars74K数据集示例(自然场景中采集的英文字符数据集)

数据集解压之后的目录结构如图2所示,解压之后的数据集包括“BadImg”和“GoodImg”,“BadImg”中的图片质量较差,因此我们使用“GoodImg”。数据集中每一个类别的图片单独放在一个文件夹中,如图2右所示。

图2 Chars74K数据集(自然场景中采集的英文字符数据集)

数据预处理

Chars74K数据集(自然场景中采集的英文字符数据集,本项目中后续提到的Chars74K数据集一律特指该数据集)里的图片大小不一,因此我们需要将其调整为统一大小,调整图像大小的代码可以在本书配套的GitHub项目中找到,这里不做介绍。另外需要注意,原始数据集中混杂了4张单通道的灰度图,需要删除这4张图片。这里可以直接使用作者处理好的数据集。

下载地址:https://pan.baidu.com/s/1KP5JRO-M87fN-93VOsSCag

接下来我们开始实现数据处理部分,首先导入需要的包:

1  import tensorflow as tf
2  from tensorflow.keras import layers
3  import datetime
4  import numpy as np
5  from PIL import Image
6  import os

接着我们定义一个“get_dataset”函数用来获取数据集:

7  def get_dataset(path):
8      """获取数据集"""
9      data_x = []
10      data_y = []
11  
12      # 获取当前路径下所有文件夹(或文件)
13      folder_name = os.listdir(path)
14  
15      # 循环遍历每个文件夹
16      for i in folder_name:
17          file_path = os.path.join(path, i)
18  
19          # 取文件夹名后三位整数作为类标
20          label = int(i[-3:])
21  
22          # 获取当前文件夹下的所有图片文件
23          filenames = os.listdir(file_path)
24  
25          for filename in filenames:
26              # 组合得到每张图片的路径
27              image_path = os.path.join(file_path, filename)
28  
29              # 读取图片
30              image = Image.open(image_path)
31              # 将image对象转为numpy数组
32              width, height = image.size
33              image_matrix = np.reshape(image, [width*height*3])
34  
35              data_x.append(image_matrix)
36              data_y.append(label)
37  
38      return data_x, data_y

第33行代码中我们将图片转换成了numpy数组,由于我们的图像是三通道的RGB图像,因此转换后的数组大小为“width * height * 3”。

模型搭建

在本项目中我们将使用VGG-Net网络模型。VGG-Net有多种级别,其网络层数从11层到19层不等(这里的层数是指有参数更新的层,例如卷积层或全连接层),其中比较常用的是16层(VGG-Net-16)和19层(VGG-Net-19)。如图3所示是VGG-Net-16的网络结构。

图3 VGG-Net-16网络结构

VGG-Net中全部使用大小为3X3的小卷积核,希望模拟出更大的“感受野”效果,VGG-Net中的池化层均使用的是大小为2X2的最大池化。VGG-Net的设计思想在ResNet和Inception模型中也都有被采用。图4所示是不同层数的VGG-Net。

图4 不同层数的VGG-Net

本项目中我们使用的是VGG-Net-13,具体实现如下:

39  def vgg13_model(input_shape, classes):
40 model = tf.keras.Sequential()
41  
42      model.add(layers.Conv2D(64, 3, 1, input_shape=input_shape,
43                              padding='same',
44                              activation='relu',
45                              kernel_initializer='uniform'))
46      model.add(layers.Conv2D(64, 3, 1, padding='same',
47                              activation='relu',
48                              kernel_initializer='uniform'))
49      model.add(layers.MaxPooling2D(pool_size=(2, 2)))
50  
51      model.add(layers.Conv2D(128, 3, 1, padding='same',
52                              activation='relu',
53                              kernel_initializer='uniform'))
54      model.add(layers.Conv2D(128, 3, 1, padding='same',
55                              activation='relu',
56                              kernel_initializer='uniform'))
57      model.add(layers.MaxPooling2D(pool_size=(2, 2)))
58  
59      model.add(layers.Conv2D(256, 3, 1, padding='same',
60                              activation='relu',
61                              kernel_initializer='uniform'))
62      model.add(layers.Conv2D(256, 3, 1, padding='same',
63                              activation='relu',
64                              kernel_initializer='uniform'))
65      model.add(layers.MaxPooling2D(pool_size=(2, 2)))
66  
67      model.add(layers.Conv2D(512, 3, 1, padding='same',
68                              activation='relu',
69                              kernel_initializer='uniform'))
70      model.add(layers.Conv2D(512, 3, 1, padding='same',
71                              activation='relu',
72                              kernel_initializer='uniform'))
73      model.add(layers.MaxPooling2D(pool_size=(2, 2)))
74  
75      model.add(layers.Conv2D(512, 3, 1, padding='same',
76                              activation='relu',
77                              kernel_initializer='uniform'))
78      model.add(layers.Conv2D(512, 3, 1, padding='same',
79                              activation='relu',
80                              kernel_initializer='uniform'))
81      model.add(layers.MaxPooling2D(pool_size=(2, 2)))
82  
83      model.add(layers.Flatten())
84      model.add(layers.Dense(4096, activation='relu'))
85  
86      model.add(layers.Dropout(0.5))
87      model.add(layers.Dense(4096, activation='relu'))
88  
89      model.add(layers.Dropout(0.5))
90      model.add(layers.Dense(classes, activation='softmax'))
91  
92      # 模型编译
93      model.compile(loss='categorical_crossentropy',
94                    optimizer='sgd',
95                    metrics=['accuracy'])
96      return model

模型训练

定义好模型后我们加载数据集并开始训练:

97  if __name__ == '__main__':
98      path = './chars74k_data'
99      data_x, data_y = get_dataset(path)
100  
101      train_x = np.array(data_x).reshape(-1, 224, 224, 3)
102      train_y = [i - 1 for i in data_y]
103      train_y = tf.keras.utils.to_categorical(train_y, 62)
104  
105      # 随机打乱数据集顺序
106      np.random.seed(116)
107      np.random.shuffle(train_x)
108      np.random.seed(116)
109      np.random.shuffle(train_y)
110  
111      cnn_model = vgg13_model(input_shape=(224,224,3), classes=62)
112      cnn_model.summary()
113  
114      # 设置TensorBoard
115      log_dir="logs/fit/"+datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
116  tensorboard_callback=tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
117  
118      # 当验证集上的loss不再下降时就提前结束训练
119  early_stop=tf.keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0.002, patience=10, mode='auto')
120  
121      callbacks = [tensorboard_callback, early_stop]
122      cnn_model.fit(train_x, train_y,
123                    batch_size=100, epochs=300,
124                    verbose=1, validation_split=0.2,
125                    callbacks=callbacks)

在第103行代码中,由于我们之前根据目录名得到的类标是从“1”开始的,因此需要对所有类标减1,让类标从“0”开始,以便在第104代码中将类标转换为one-hot编码。

第120行代码中,我们设置了一个callback函数“EarlyStopping”,该函数可以用来设置模型自动停止训练的条件。例如这里我们设置当“val_loss”的值有10次变化不超过0.002时则提前停止训练。参数“monitor”是要监测的指标;“min_delta”是监测指标的最小变化值;“patience”是没有变化的训练回合数;“mode”有三个值,分别是“auto”、“min”和“max”,当“mode”设置为“min”时,如果监测的指标有“patience”次没有达到“min_delta”的变化量,则停止训练,“max”同理。模型训练的结果如图5所示:

图5 训练过程中的Accuracy和Loss变化(红色为训练集,蓝色为验证集)

本文分享自微信公众号 - 磐创AI(xunixs),作者:小猴锅

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 用PyCaret创建整个机器学习管道

    本教程涵盖了整个ML过程,从数据获取、预处理、模型训练、超参数拟合、预测和存储模型以备将来使用。

    磐创AI
  • PyTorch专栏(五):迁移学习

    实际中,基本没有人会从零开始(随机初始化)训练一个完整的卷积网络,因为相对于网络,很难得到一个足够大的数据集[网络很深, 需要足够大数据集]。通常的做法是在一个...

    磐创AI
  • TensorFlow官方发布剪枝优化工具:参数减少80%,精度几乎不变

    去年TensorFlow官方推出了模型优化工具,最多能将模型尺寸减小4倍,运行速度提高3倍。

    磐创AI
  • 机器学习工具代码

    \[ 1 1 0 3\\ 1 0 3 3\\ 0 1 3 3\\ 0 0 0 0\\ \] \[ \Downarrow \] \[ 0 0 0 1\\ 0 ...

    范中豪
  • 你画我猜

    Quick Draw 数据集是一个包含5000万张图画的集合,分成了345个类别,这些图画都来自于Quick, Draw! 游戏的玩家。

    故事尾音
  • 链表

    链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。...

    九州暮云
  • Ajax上传图片以及上传之前先预览

    手头上有几个小项目用到了easyUI,一开始决定使用easyUI就注定了项目整体上前后端分离,基本上所有的请求都采用Ajax来完成。在文件上传的时候用到了Aja...

    江南一点雨
  • 你不知道的SSD那些事

    从2005年三星作为第一个进入SSD市场的巨头,到现在短短15年,SSD已经成为非常普遍的存储介质了,相对于机械硬盘HDD,SSD在IOPS上提升了数百倍,带宽...

    焱融科技
  • 蚂蚁金服首席架构师:开源SQLFlow牛刀初试,实时大数据系统才是未来基石

    这就是蚂蚁金服近日开源首个将SQL应用于AI引擎项目SQLFlow后,业界给出的反应。

    养码场
  • Element UI导航菜单(NavMenu),动态多级菜单实现

    今天同事封装一个导航栏的组件,使用的 Element UI 的 NavMenu 组件。

    德顺

扫码关注云+社区

领取腾讯云代金券