python深度学习tensorflow和fme结合,实现档案扫描件数据⾃
动分类
前⾔
之前我发过⼀遍⽤fme调⽤⾕歌的汉字识别库来实现扫描件分类的⽂章,虽然能减少⼤量的⼈⼒物⼒,但是缺点依旧有很多,⽐如很多扫描件资料⽂字不清晰,房屋照⽚图像资料⽆法识别,⽂字识别率低,环境配置复杂,同时分类效率低下,⼤概需要花费1秒才能完成⼀张照⽚的分类。于是悟空我开始从深度学习上探索如何实现扫描件的0误差分类。学习了接近⼀个⽉的机器学习基础,深度学习算法,终于是实现了这个案例的接近于99的正确率分类。
⼀、深度学习基础知识简介
1、什么是深度学习
深度学习是机器学习的⼀个分⽀,主要通过学习样本数据的内在规律和表⽰层次,这些学习过程中获得的信息对诸如⽂字,图像和声⾳等数据的解释有很⼤的帮助。它的最终⽬标是让机器能够像⼈⼀样具有分析学习能⼒,能够识别⽂字、图像和声⾳等数据。 深度学习是⼀个复杂的机器学习算法,在语⾳和图像识别⽅⾯取得的效果,远远超过先前相关技术。
2、深度学习的原理
深度学习为什么叫深度学习,故名思义其实就是通过庞⼤复杂的卷积层、池化层、隐藏层、全连接层、输出层来对⽬标进⾏特征提取,特征降维,通过线性回归的⽅式,求出能预测输出结果的最合适的权重。深度学习不同于机器学习,其最⼤的特点就是模拟了⼈脑的神经⽹络结构,通过激活函数,来实现快速,⾼效对⽬标的计算。
3、深度学习应⽤场景
深度学习不局限于图像语⾳识别,深度学习其实就是模拟⼈脑的⼀种算法,为什么⼈和计算机相⽐计算能⼒如此低下,却能在⼤部分时候,分辨物体,神经反射等时候,拥有⽐计算机更强⼤的性能,其实就是得益于神经元的和神经元的全连接的结构,平时不做功,但是⼀旦传⼊信号,相应的神经元便⽴刻激活,通过庞⼤的神经⽹络,快速做出反应。所以深度学习是⼀种⾮常有潜⼒的技术,可以部署到系统,完成各种复杂的数据计算。
⼆、深度学习环境搭建
1.深度学习库的安装
我这⾥选取了⾕歌开发的tensorflow2,当然也可以选择pytorch,这个看个⼈喜好,两者功能⼏乎没什么
区别,只是如果考虑后期部署到服务器给平台后台计算使⽤,⼀般我会推荐使⽤tensorflow,如果是做学术研究,都推荐使⽤pytorch。安装很简单,只需要pip install tensorflow  就可以了。这⾥由于我的开发环境是fme,所以我选择 python -m pip install tensorflow --target "C:\Program Files\FME\python" 进⾏安装。
2.CUDA和对应版本的cudnn下载
这⾥我不做赘述,只需要进⼊官⽹下载,但是需要注意⼀点就是,必须要注意版本的对应,我这⾥⽤的是11.2CUDA,8.1的
CUDNN,2.7的tensorflow,以及python3.7的编译环境。
三、实战教学
1.基础数据集的准备
因为图像分类是监督学习,所以我们需要事先准备好数据集,数据集需要图⽚本⾝以及图⽚对应的⽬标值。我这⾥直接截图数据集格式。
其中每个数字都包含了⼀种类型的⽂档扫描件。我⼀共准备了2300张图⽚,其实为了满⾜精度,⼀般来说图⽚数量是越多越好,这⾥的准备我使⽤了我以前博客提过的调⽤⾕歌的⽂字识别库的fme模板来处理的基础数据。
2、图⽚数据集转换为可训练数据集
⾸先我们需要了解最终我们要输出给神经⽹络进⾏训练的数据格式什么样⼦的,因为神经⽹络模型不能直接识别图像,所以我们要先将图像转换为⼀个np.array格式的4维数组如下图所⽰。
这⾥我⾸先使⽤了fme的路径读模块,然后筛选出图像,将结果打⼊字段,同时对要素进⾏了打乱,因为最终我们需要将数据划分为训练集和测试集,所以这⾥提前打乱排序,切割样本的时候就会达到均匀的分割。
这⾥是我需要导⼊的模块
import fme
import fmeobjects
import pandas as pd
import tensorflow.keras as keras
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras import layers
通过init⽅法实例化列表对象
def __init__(self):
self.all_image=[]
self.label=[]
pass
在input⽅法中将要素迭代,添加进列表
def input(self,feature):
self.all_image.Attribute('path_windows'))
self.label.append(Attribute('label')))
self.pyoutput(feature)
将数据划分为训练集和测试集
split=int(len(self.all_image)*0.8)
train_dir=self.all_image[ :split]
test_dir=self.all_image[split: ]
train_label=np.array(self.label[:split])
test_label=np.array(self.label[split:])
将训练集列表数据转换为4维数组
train_image=[]
for path in train_dir:
image=keras.preprocessing.image.load_img(path,target_size=(224,224))
image_array=keras.preprocessing.image.img_to_array(image)
image_array=image_array/255#数据归⼀化
train_image.append(image_array)
train_image_array=np.stack(train_image)
将测试集列表数据转换为4维数组
test_image=[]
for path1 in test_dir:
image1=keras.preprocessing.image.load_img(path1,target_size=(224,224))
image1_array=keras.preprocessing.image.img_to_array(image1)
image1_array=image1_array/255#数据归⼀化
test_image.append(image1_array)#⽣成图⽚测试集
test_image_array=np.stack(test_image)
以上基础数据就准备好了,(1867, 224, 224, 3)我在这解释⼀下这4个维度的数据分辨代表什么,第⼀个是图⽚张数,第⼆个是x轴像素,第三个是y轴像素,最后⼀个是颜⾊的rgb通道,如果是⿊⽩就是1,彩⾊就是3,当然处理过的图⽚也会出现2的情况,这个结合实际情况⽽定。
3、模型搭建
这⾥我的卷积层直接采⽤了预训练模型 MobileNetV2,当然我们也可以⾃⼰搭建神经⽹络结构。这⾥我主要讲解⼀下卷积和池化的概念:卷积按我的理解其实就是对图⽚特征值提取的⼀个过程,通过定义的卷积核(在卷积核上定义好权重)然后把图⽚从左到右从上到下全部摸⼀遍,最终得到⼀个卷积核认识过后的初始图像数据,池化层就是在卷积后将图像数据进⼀步缩⼩,把厚度进⼀步加深。这⾥激活函数我选择的relu,使⽤的是函数api格式搭建的模型,⽤了⼀次Droput防⽌过拟合
mobile_net=keras.applications.MobileNetV2(input_shape=
(224,224,3),include_top=False)#使⽤预训练模型,不包括头部
inputs=keras.Input(shape=(224,224,3))
x=mobile_net(inputs)
x=keras.layers.GlobalAveragePooling2D()(x)#将卷积后的数据展平
x1=keras.layers.Dense(1024,activation='relu')(x)#构建全链接层
x2=keras.layers.Dropout(0.5)(x1)
out_type=keras.layers.Dense(17,activation='softmax')(x2)#构建输出层
model=keras.Model(inputs=inputs,outputs=out_type)
model.summary()
4、模型初始化和模型训练以及模型保存
这⾥没什么好说的,注意的是因为我⽤了⾃定义函数,所以只把模型的权重保存。
可以看到准确率已经到 了百分之98 ⽽且拟合度⾮常之好。
modelpile(optimizer=keras.optimizers.Adam(learning_rate=0.0001),loss='sparse_categorical_crossentropy',metrics=['acc'])
model.fit(train_image_array,train_label,epochs=5,batch_size=4,validation_data=(test_image_array,test_label))
model.save_weights('23333.h5')
5、模型再优化
⾸先我要说明,模型的优化最好的⽅法就是增⼤数据集,但是很多时候我们并没有这个条件,所以这⾥就引⼊了图像增强的⽅法,由于扫
描件数据格式都⽐较接近,⽽且训练的结果已经⾮常理想,我并没有做图像增强,但是我还是简单介绍⼀下图像增强的原理。过拟合通常发⽣在训练样本较少时。数据增强采⽤的⽅法是从现有⽰例中⽣成额外的训练数据,⽅法是使⽤随机变换来增强它们,从⽽产⽣看起来可信的图像。这有助于将模型暴露于数据的更多⽅⾯并更好地概括。 您将使⽤以下Keras预处理层实现数据增强:
tf.keras.layers.RandomFlip,tf.keras.layers.RandomRotation,和tf.keras.layers.RandomZoom。这些可以像其他层⼀样包含在您的模型中,并在 GPU 上运⾏。
data_augmentation = keras.Sequential(  [ layers.RandomFlip("horizontal",                                                            input_shape=(img_height,  img_width,  3))                                        layers.RandomRotation(0.1),
layers.RandomZoom(0.1),  ] )
6、使⽤模型进⾏预测
这⾥我直接调⽤模型进⾏预测,并将预测结果保留到字段
pass
def input(self,feature):
image=keras.preprocessing.image.load_Attribute('path_windows'),target_size=(224,224))
image_array=keras.preprocessing.image.img_to_array(image)
image_array=image_array/255#数据归⼀化
train_image_pand_dims(image_array,0)#拓展维度
#模型结构
mobile_net=keras.applications.MobileNetV2(input_shape=(224,224,3),include_top=False)#使⽤预训练模型,不包括头部
inputs=keras.Input(shape=(224,224,3))
x=mobile_net(inputs)
x=keras.layers.GlobalAveragePooling2D()(x)#将卷积后的数据展平
x1=keras.layers.Dense(1024,activation='relu')(x)#构建全链接层
x2=keras.layers.Dropout(0.5)(x1)
out_type=keras.layers.Dense(17,activation='softmax')(x2)#构建输出层
model=keras.Model(inputs=inputs,outputs=out_type)
#模型数据初始化(优化函数和loss函数)
# modelpile(optimizer=keras.optimizers.Adam(learning_rate=0.0001),loss='sparse_categorical_crossentropy',metrics=['acc'])        #
model.load_weights('23333.h5')
a=model(train_image_array)
#print(a)
b=np.argmax(a[0])
#  print(b)
feature.setAttribute("分类结果",int(b))
tensorflow版本选择self.pyoutput(feature)
然后使⽤filecopy将预测结果整理好转换为⽂本,并输出为成果