国企网站建设需要注意,哪里有未成年做的网站,c2c模式有哪些,h5界面设计接下来#xff0c;我们将从零开始讲解一个基于TensorFlow的图像多标签分类实例#xff0c;这里以图片验证码为例进行讲解。
在我们访问某个网站的时候#xff0c;经常会遇到图片验证码。图片验证码的主要目的是区分爬虫程序和人类#xff0c;并将爬虫程序阻挡在外。
下面…接下来我们将从零开始讲解一个基于TensorFlow的图像多标签分类实例这里以图片验证码为例进行讲解。
在我们访问某个网站的时候经常会遇到图片验证码。图片验证码的主要目的是区分爬虫程序和人类并将爬虫程序阻挡在外。
下面的程序就是模拟人类识别验证码从而使网站无法区分是爬虫程序还是人类在网站登录。
10.4.1 使用TFRecord生成训练数据
以图10.5所示的图片验证码为例将这幅验证码图片标记为label[3,8,8,7]。我们知道分类网络一般一次只能识别出一个目标那么如何识别这个多标签的序列数据呢?
通过下面的TFRecord结构可以构建多标签训练数据集从而实现多标签数据识别。 图10.5 图片验证码
以下为构造TFRecord多标签训练数据集的代码
import tensorflow as tf
# 定义对整型特征的处理
def _int64_feature(value):return tf.train.Feature(int64_listtf.train.Int64List(value[value]))
# 定义对字节特征的处理
def _bytes_feature(value):return tf.train.Feature(bytes_listtf.train.BytesList(value[value]))
# 定义对浮点型特征的处理
def _floats_feature(value):return tf.train_Feature(float_listtf.train.floatList(value[value]))
# 对数据进行转换
def convert_to_record(name, image, label, map):filename os.path.join(params.TRAINING_RECORDS_DATA_DIR,name . params.DATA_EXT)writer tf.python_io.TFRecordWriter(filename)image_raw image.tostring()map_raw map.tostring()label_raw label.tostring()example tf.train.Example(featuretf.train.Feature(feature{image_raw: _bytes_feature(image_raw),map_raw: _bytes_feature(map_raw),1abel_raw: _bytes_feature(label_raw)}))writer.write(example.SerializeToString())writer.close()通过上面的代码我们构建了一条支持多标签的TFRecord记录多幅验证码图片可以构建一个验证码的多标签数据集用于后续的多标签分类训练。
10.4.2 构建多标签分类网络
通过前一步操作我们得到了用于多标签分类的验证码数据集现在需要构建多标签分类网络。
我们选择VGG网络作为特征提取网络骨架。通常越复杂的网络对噪声的鲁棒性就越强。验证码中的噪声主要来自形变、粘连以及人工添加VGG网络对这些噪声具有好的鲁棒性代码如下
import tensorflow as tf
tf.enable_eager_execution ()
def model_vgg(x, training False):
# 第一组第一个卷积使用64个卷积核核大小为3
conv1_1 tf.layers.conv2d(inputsx, filters64,nameconv1_1,kernel_size3, activationtf.nn.relu, paddingsame)
# 第一组第二个卷积使用64个卷积核核大小为3
convl_2 tf.layers.conv2d(inputsconv1_1,filters64, nameconv1_2,kernel_size3, activationtf.nn.relu,paddingsame)
# 第一个pool操作核大小为2步长为2
pooll tf.layers.max_pooling2d(inputsconv1_2, pool_size[2, 2],strides2, name pool1)
# 第二组第一个卷积使用128个卷积核核大小为3
conv2_1 tf.layers.conv2d(inputspool1, filters128, nameconv2_1,kernel_size3, activationtf.nn.relu, paddingsame)
# 第二组第二个卷积使用64个卷积核核大小为3
conv2_2 tf.layers.conv2d(inputsconv2_1, filters128,nameconv2_2,kernel_size3, activationtf.nn.relu, paddingsame)
# 第二个pool操作核大小为2步长为2
pool2 tf.layers.max_pooling2d(inputsconv2_2, pool_size[2 2],strides2, namepool1)
# 第三组第一个卷积使用128个卷积核核大小为3
conv3_1 tf.layers.conv2d(inputspool2, filters128, nameconv3_1, kernel_size3, activationtf.nn.relu, paddingsame)
# 第三组第二个卷积使用128个卷积核核大小为3
conv3_2 tf.layers.conv2d(inputsconv3_1, filters128, nameconv3_2, kernel_size3, activationtf.nn.relu, paddingsame)
# 第三组第三个卷积使用128个卷积核核大小为3
conv3_3 tf.layers.conv2d(inputsconv3_2, filters128, nameconv3_3, kernel_size3, activationtf.nn.relu, padding same)
# 第三个pool 操作核大小为2步长为2
pool3 tf.layers.max_pooling2d(inputsconv3_3, pool_size[2, 2], strides2,namepool3)
# 第四组第一个卷积使用256个卷积核核大小为3
conv4_1 tf.layers.conv2d(inputs-pool3, filters256, nameconv4_1, kernel_size3, activationtf.nn.relu, paddingsame)
# 第四组第二个卷积使用128个卷积核核大小为3
conv4_2 tf.layers.conv2d(inputsconv4_1, filters128, nameconv4_2, kernel_size3, activationtf.nn.relu, paddingsame)
# 第四组第三个卷积使用128个卷积核核大小为3
conv4_3 tf.layers.conv2d(inputsconv4_2, filters128, namecov4_3, kernel_size3, activationtf.nn.relu, paddingsame )
# 第四个pool操作核大小为2步长为2
pool4 tf.layers.max.pooling2d(inputsconv4_3, pool_size[2,2], strides2, namepool4)
# 第五组第一个卷积使用512个卷积核核大小为3
conv5_1 tf.layers.conv2d(inputspool4, filters512, nameconv5_1, kernel_size3, activationtf.nn.relu, padding same)
# 第五组第二个卷积使用512个卷积核核大小为3
conv5_2 t.layers.conv2d(inputsconv5_1, filters512, nameconv5_2, kernel_size3, activationtf.nn.relu, paddingsame)
# 第五组第三个卷积使用512个卷积核核大小为3
conv5_3 tf.layers.conv2d(inputs-conv5_2, filters512, nameconv5_3, kernel_size3, activationtf.nn.relu, paddingsame)
# 第五个pool操作核大小为2步长为2
pool5 tf.layers.max_pooling2d(inputsconv5_3, pool_size[2, 2], strides2, namepool5)
flatten tf.layers.flatten(inputspoo15, nameflatten)上面是VGG网络的单标签分类TensorFlow代码但这里我们需要实现的是多标签分类因此需要对VGG网络进行相应的改进代码如下
# 构建输出为4096的全连接层
fc6 tf.layers.dense(inputsflatten, units4096,
activationtf.nn.relu, namefc6)
# 为了防止过拟合引入dropout操作
drop1 tf.layers.dropout(inputsfc6,rate0.5, trainingtraining)
# 构建输出为4096的全连接层
fc7 tf.layers.dense(inputsdrop1, units4096,
activationtf.nn.relu, namefc7)
# 为了防止过报合引入dropout操作
drop2 tf.layers.dropout(inputsfc7, rate0.5, trainingtraining)
# 为第一个标签构建分类器
fc8_1 tf.layers.dense(inputsdrop2, units10,
activationtf.nn.sigmoid, namefc8_1)
# 为第二个标签构建分类器
fc8_2 tf.layers.dense(inputsdrop2, units10,
activationtf.nn.sigmoid, namefc8_2)
# 为第三个标签构建分类器
fc8_3 tf.layers.dense(inputsdrop2, units10,
activationtf.nn.sigmoid, namefc8_3)
# 为第四个标签构建分类器
fc8_4 tf.layers.dense(inputsdrop2,units10,
activationtf.nn.sigmoid, namefc8_4)
# 将四个标签的结果进行拼接操作
fc8 tf.concat([fc8_1,fc8_2,fc8_3,fc8_4], 0)这里的fc6和fc7全连接层是对网络的卷积特征进行进一步的处理在经过fc7层后我们需要生成多标签的预测结果。由于一幅验证码图片中存在4个标签因此需要构建4个子分类网络。这里假设图片验证码中只包含10 个数字因此每个网络输出的预测类别就是10类最后生成4个预测类别为10的子网络。如果每次训练时传入64幅验证码图片进行预测那么通过4个子网络后分别生成(64,10)、(64,10)、(64,10)、(64,10) 4个张量。如果使用Softmax分类器的话就需要想办法将这4个张量进行组合于是使用tf.concat函数进行张量拼接操作。
以下是TensorFlow中tf.concat函数的传参示例
tf.concat (
values,
axis,
nameconcat
)通过fc8tf.concat([fc8_1,fc8_2,fc8_3,fc8_4], 0)的操作可以将前面的4个(64.10)张量变换成(256.10)这样的单个张量生成单个张量后就能进行后面的Softmax分类操作了。
10.4.3 多标签训练模型
模型训练的第一个步骤就是读取数据读取方式有两种一种是直接读取图片进行操作另一种是转换为二进制文件格式后再进行操作。前者实现起来简单但速度较慢后者实现起来复杂但读取速度快。这里我们以后者二进制的文件格式介绍如何实现多标签数据的读取操作下面是相关代码。
首先读取TFRecord文件内容
tfr TFrecorder()
def input_fn_maker(path, data_info_path, shuffleFalse, batch_size 1,
epoch 1, padding None) :
def input_fn():filenames tfr.get_filenames(pathpath, shuffleshuffle)datasettfr.get_dataset(pathsfilenames,data_infodata_info_path, shuffle shuffle,batch_size batch_size, epoch epoch, padding padding)iterator dataset.make_one_shot_iterator ()return iterator.get_next()
return input_fn
# 原始图片信息
padding_info ({image:[30, 100,3,], label:[]})
# 测试集
test_input_fn input_fn_maker(captcha_data/test/,
captcha_tfrecord/data_info.csv,
batch_size 512, padding padding_info)
# 训练集
train_input_fn input_fn_maker(captcha_data/train/,
captcha_tfrecord/data_info.csv,
shuffleTrue, batch_size 128,padding padding_info)
# 验证集
train_eval_fn input_fn_maker(captcha_data/train/,
captcha_tfrecord/data_info.csv,
batch_size 512,adding padding_info)然后是模型训练部分
def model_fn(features, net, mode):
features[image] tf.reshape(features[image], [-1, 30, 100, 3])
# 获取基于net网络的模型预测结果
predictions net(features[image])
# 判断是预测模式还是训练模式
if mode tf.estimator.ModeKeys.PREDICT:return tf.estimator.EstimatorSpec(modemode,predictionspredictions)
# 因为是多标签的Softmax所以需要提前对标签的维度进行处理
lables tf.reshape(features[label], features[label].shape[0]*4,))
# 初始化softmaxloss
loss tf.losses.sparse_softmax_cross_entropy(labelslabels,logitslogits)
# 训练模式下的模型结果获取
if mode tf.estimator.ModeKeys.TRAIN:# 声明模型使用的优化器类型optimizer tf.train.AdamOptimizer(learning_rate1e-3)train_op optimizer.minimize(lossloss,global_steptf.train.get_global_step())return tf.estimator.EstimatorSpec(modemode,lossloss, train_optrain_op)
# 生成评价指标
eval_metric_ops {accuracy: tf.metrics.accuracy(labelsfeatures[label],predictionspredictions[classes]) }
return tf.estimator.EstimatorSpec(modemode, lossloss,eval_metric_ops eval_metric_ops)多标签的模型训练流程与普通单标签的模型训练流程非常相似唯一的区别就是需要将多标签的标签值拼接成一个张量以满足Softmax分类操作的维度要求。
本文节选自《Python深度学习原理、算法与案例》。