TensorFlow图像多标签分类实例
接下来,我们将从零开始讲解一个基于TensorFlow的图像多标签分类实例,这里以图片验证码为例进行讲解。
在我们访问某个网站的时候,经常会遇到图片验证码。图片验证码的主要目的是区分爬虫程序和人类,并将爬虫程序阻挡在外。
下面的程序就是模拟人类识别验证码,从而使网站无法区分是爬虫程序还是人类在网站登录。
以图10.5所示的图片验证码为例,将这幅验证码图片标记为label=[3,8,8,7]。我们知道分类网络一般一次只能识别出一个目标,那么如何识别这个多标签的序列数据呢?
通过下面的TFRecord结构可以构建多标签训练数据集,从而实现多标签数据识别。
图10.5 图片验证码
以下为构造TFRecord多标签训练数据集的代码:
import tensorflow as tf
# 定义对整型特征的处理
def _int64_feature(value):return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
# 定义对字节特征的处理
def _bytes_feature(value):return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
# 定义对浮点型特征的处理
def _floats_feature(value):return tf.train_Feature(float_list=tf.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(feature=tf.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记录,多幅验证码图片可以构建一个验证码的多标签数据集,用于后续的多标签分类训练。
通过前一步操作,我们得到了用于多标签分类的验证码数据集,现在需要构建多标签分类网络。
我们选择VGG网络作为特征提取网络骨架。通常越复杂的网络,对噪声的鲁棒性就越强。验证码中的噪声主要来自形变、粘连以及人工添加,VGG网络对这些噪声具有好的鲁棒性,代码如下:
import tensorflow as tf
tf.enable_eager_execution ()
def model_vgg(x, training = False):
# 第一组第一个卷积使用64个卷积核,核大小为3
conv1_1 = tf.layers.conv2d(inputs=x, filters=64,name="conv1_1",kernel_size=3, activation=tf.nn.relu, padding="same")
# 第一组第二个卷积使用64个卷积核,核大小为3
convl_2 = tf.layers.conv2d(inputs=conv1_1,filters=64, name="conv1_2",kernel_size=3, activation=tf.nn.relu,padding="same")
# 第一个pool操作核大小为2,步长为2
pooll = tf.layers.max_pooling2d(inputs=conv1_2, pool_size=[2, 2],strides=2, name= 'pool1')
# 第二组第一个卷积使用128个卷积核,核大小为3
conv2_1 = tf.layers.conv2d(inputs=pool1, filters=128, name="conv2_1",kernel_size=3, activation=tf.nn.relu, padding="same")
# 第二组第二个卷积使用64个卷积核,核大小为3
conv2_2 = tf.layers.conv2d(inputs=conv2_1, filters=128,name="conv2_2",kernel_size=3, activation=tf.nn.relu, padding="same")
# 第二个pool操作核大小为2,步长为2
pool2 = tf.layers.max_pooling2d(inputs=conv2_2, pool_size=[2, 2],strides=2, name="pool1")
# 第三组第一个卷积使用128个卷积核,核大小为3
conv3_1 = tf.layers.conv2d(inputs=pool2, filters=128, name="conv3_1", kernel_size=3, activation=tf.nn.relu, padding="same")
# 第三组第二个卷积使用128个卷积核,核大小为3
conv3_2 = tf.layers.conv2d(inputs=conv3_1, filters=128, name="conv3_2", kernel_size=3, activation=tf.nn.relu, padding="same")
# 第三组第三个卷积使用128个卷积核,核大小为3
conv3_3 = tf.layers.conv2d(inputs=conv3_2, filters=128, name="conv3_3", kernel_size=3, activation=tf.nn.relu, padding=" same")
# 第三个pool 操作核大小为2,步长为2
pool3 = tf.layers.max_pooling2d(inputs=conv3_3, pool_size=[2, 2], strides=2,name='pool3')
# 第四组第一个卷积使用256个卷积核,核大小为3
conv4_1 = tf.layers.conv2d(inputs-pool3, filters=256, name="conv4_1", kernel_size=3, activation=tf.nn.relu, padding="same")
# 第四组第二个卷积使用128个卷积核,核大小为3
conv4_2 = tf.layers.conv2d(inputs=conv4_1, filters=128, name="conv4_2", kernel_size=3, activation=tf.nn.relu, padding="same")
# 第四组第三个卷积使用128个卷积核,核大小为3
conv4_3 = tf.layers.conv2d(inputs=conv4_2, filters=128, name="cov4_3", kernel_size=3, activation=tf.nn.relu, padding="same" )
# 第四个pool操作核大小为2,步长为2
pool4 = tf.layers.max.pooling2d(inputs=conv4_3, pool_size=[2,2], strides=2, name='pool4')
# 第五组第一个卷积使用512个卷积核,核大小为3
conv5_1 = tf.layers.conv2d(inputs=pool4, filters=512, name="conv5_1", kernel_size=3, activation=tf.nn.relu, padding=" same")
# 第五组第二个卷积使用512个卷积核,核大小为3
conv5_2 = t.layers.conv2d(inputs=conv5_1, filters=512, name="conv5_2", kernel_size=3, activation=tf.nn.relu, padding="same")
# 第五组第三个卷积使用512个卷积核,核大小为3
conv5_3 = tf.layers.conv2d(inputs-conv5_2, filters=512, name="conv5_3", kernel_size=3, activation=tf.nn.relu, padding="same")
# 第五个pool操作核大小为2,步长为2
pool5 = tf.layers.max_pooling2d(inputs=conv5_3, pool_size=[2, 2], strides=2, name='pool5')
flatten = tf.layers.flatten(inputs=poo15, name="flatten")
上面是VGG网络的单标签分类TensorFlow代码,但这里我们需要实现的是多标签分类,因此需要对VGG网络进行相应的改进,代码如下:
# 构建输出为4096的全连接层
fc6 = tf.layers.dense(inputs=flatten, units=4096,
activation=tf.nn.relu, name='fc6')
# 为了防止过拟合,引入dropout操作
drop1 = tf.layers.dropout(inputs=fc6,rate=0.5, training=training)
# 构建输出为4096的全连接层
fc7 = tf.layers.dense(inputs=drop1, units=4096,
activation=tf.nn.relu, name='fc7')
# 为了防止过报合,引入dropout操作
drop2 = tf.layers.dropout(inputs=fc7, rate=0.5, training=training)
# 为第一个标签构建分类器
fc8_1 = tf.layers.dense(inputs=drop2, units=10,
activation=tf.nn.sigmoid, name='fc8_1')
# 为第二个标签构建分类器
fc8_2 = tf.layers.dense(inputs=drop2, units=10,
activation=tf.nn.sigmoid, name='fc8_2')
# 为第三个标签构建分类器
fc8_3 = tf.layers.dense(inputs=drop2, units=10,
activation=tf.nn.sigmoid, name='fc8_3')
# 为第四个标签构建分类器
fc8_4 = tf.layers.dense(inputs=drop2,units=10,
activation=tf.nn.sigmoid, name='fc8_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,
name='concat'
)
通过fc8=tf.concat([fc8_1,fc8_2,fc8_3,fc8_4], 0)的操作,可以将前面的4个(64.10)张量变换成(256.10)这样的单个张量,生成单个张量后就能进行后面的Softmax分类操作了。
模型训练的第一个步骤就是读取数据,读取方式有两种:一种是直接读取图片进行操作,另一种是转换为二进制文件格式后再进行操作。前者实现起来简单,但速度较慢;后者实现起来复杂,但读取速度快。这里我们以后者二进制的文件格式介绍如何实现多标签数据的读取操作,下面是相关代码。
首先读取TFRecord文件内容:
tfr = TFrecorder()
def input_fn_maker(path, data_info_path, shuffle=False, batch_size = 1,
epoch = 1, padding = None) :
def input_fn():filenames = tfr.get_filenames(path=path, shuffle=shuffle)dataset=tfr.get_dataset(paths=filenames,data_info=data_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',
shuffle=True, 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(mode=mode,predictions=predictions)
# 因为是多标签的Softmax,所以需要提前对标签的维度进行处理
lables = tf.reshape(features['label'], features['label'].shape[0]*4,))
# 初始化softmaxloss
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels,logits=logits)
# 训练模式下的模型结果获取
if mode ==tf.estimator.ModeKeys.TRAIN:# 声明模型使用的优化器类型optimizer = tf.train.AdamOptimizer(learning_rate=1e-3)train_op = optimizer.minimize(loss=loss,global_step=tf.train.get_global_step())return tf.estimator.EstimatorSpec(mode=mode,loss=loss, train_op=train_op)
# 生成评价指标
eval_metric_ops = {"accuracy": tf.metrics.accuracy(labels=features['label'],predictions=predictions["classes"]) }
return tf.estimator.EstimatorSpec(mode=mode, loss=loss,eval_metric_ops= eval_metric_ops)
多标签的模型训练流程与普通单标签的模型训练流程非常相似,唯一的区别就是需要将多标签的标签值拼接成一个张量,以满足Softmax分类操作的维度要求。
本文节选自《Python深度学习原理、算法与案例》。
相关文章:

TensorFlow图像多标签分类实例
接下来,我们将从零开始讲解一个基于TensorFlow的图像多标签分类实例,这里以图片验证码为例进行讲解。 在我们访问某个网站的时候,经常会遇到图片验证码。图片验证码的主要目的是区分爬虫程序和人类,并将爬虫程序阻挡在外。 下面…...

Python程序设计期末复习笔记
文章目录 一、数据存储1.1 倒计时1.2 os库1.3 字符串操作1.4 文件操作1.5 列表操作1.6 元组1.7 字典 二、文本处理及可视化2.1 jieba分词2.2 集合操作2.3 pdf文件读取2.4 参数传递2.5 变量作用域 三、数据处理分析3.1 Sumpy3.2 Matplotlib3.3 Numpy 四、Pandas4.1 索引操作4.2 …...
人大与加拿大女王大学金融硕士—与您共创辉煌
生活的本质就是有意识的活着,而生活的智慧就是活出了自己想要的样子,那些真正厉害的人,从来都在默默努力,伴随着金融人才的需求日益增长,中国人民大学与加拿大女王大学联合推出了人大女王金融硕士项目,旨在…...

Generalized Zero-Shot Learning With Multi-Channel Gaussian Mixture VAE
L D A _{DA} DA最大化编码后两种特征分布之间的相似性 辅助信息 作者未提供代码...
10.30 知识总结(标签分类、css介绍等)
一、 标签的分类 1.1 单标签 img br hr <img /> 1.2 双标签 a h p div <a></a> 1.3 按照标签属性分类 1.3.1 块儿标签 即自己独自占一行 h1-h6 p div 1.3.2 行内(内联)标签 即自身文本有多大就占多大 a span u i b s 二、 标签的嵌套 标签之间是可以互相…...

DoLa:对比层解码提高大型语言模型的事实性
DoLa:对比层解码提高大型语言模型的事实性 摘要1 引言2 方法2.1 事实知识在不同层级上演化2.2 动态早期层选择2.3 预测对比 3 实验3.1 任务3.2 实验设置3.3 多项选择3.3.1 TruthfulQA:多项选择3.3.2 FACTOR:维基、新闻 3.4 开放式文本生成3.4…...

解决由于找不到mfc140u.dll无法继续执行此代码问题的4个方法
mfc140u.dll是Microsoft Foundation Class(微软基础类库)中的一个动态链接库文件,它包含了许多用于实现Windows应用程序的基本功能。当我们在编写或运行基于MFC的程序时,如果系统中缺少这个文件,就会出现“找不到mfc14…...
MySQL高性能优化规范建议
当涉及到MySQL数据库的性能优化时,有许多方面需要考虑。以下是一些通用的MySQL性能优化规范建议: 合适的索引: 确保表中的字段使用了适当的索引。这能大幅提升检索速度。但避免过多索引,因为它会增加写操作的成本。 优化查询语句…...

pytorch 入门 (五)案例三:乳腺癌识别-VGG16实现
本文为🔗小白入门Pytorch内部限免文章 🍨 本文为🔗小白入门Pytorch中的学习记录博客🍦 参考文章:【小白入门Pytorch】乳腺癌识别🍖 原作者:K同学啊 在本案例中,我将带大家探索一下深…...

vue中electron与vue通信(fs.existsSync is not a function解决方案)
electron向vue发送消息 dist/main.js (整个文件配置在另一条博客里) win new BrowserWindow({width:1920,height:1080,webPreferences: {// 是否启用Node integrationnodeIntegration: true, // Electron 5.0.0 版本之后它将被默认false// 是否在独立 JavaScript 环境中运行…...
LSTM-Based Anomaly Detection of Process Instances Benchmark and Tweaks翻译
论文《LSTM-Based Anomaly Detection of Process Instances Benchmark and Tweaks》翻译 LSTM-Based Anomaly Detection of Process Instances Benchmark and Tweaks翻译...
文件类漏洞总结, 文件包含, 文件上传, 文件下载
文件类漏洞总结 一, 文件包含 1. 文件包含绕过 实际环境中不是都是像$_GET[file]; incude $file 这样直接把变量传入包含函数的。 在很多时候包含的变量文件不是完全可控的,比如下面这段代码指定了前缀和后缀: <?php $file S_GET[filename]; include /opt/…...
SpringBoot篇---第四篇
系列文章目录 文章目录 系列文章目录一、springboot常用的starter有哪些二、 SpringBoot 实现热部署有哪几种方式?三、如何理解 Spring Boot 配置加载顺序? 一、springboot常用的starter有哪些 spring-boot-starter-web 嵌入tomcat和web开发需要servlet…...
Knife4j使用教程(一) -- 在不同版本SpringBoot,选用不同的Knife4j相关的jar包
目录 1. Knife4j的项目背景 2. Knife4j的选择 2.1 选用 Spring Boot 版本在 2.4.0~3.0.0之间 2.2 选用 Spring Boot 版本在 3.0.0之上...
Octave Convolution学习笔记 (附代码)
论文地址:https://export.arxiv.org/pdf/1904.05049 代码地址:https://gitcode.com/mirrors/lxtgh/octaveconv_pytorch/overview?utm_sourcecsdn_github_accelerator 1.是什么? OctaveNet网络属于paper《Drop an Octave: Reducing Spatia…...

SpringSecurity 认证实战
一. 项目数据准备 1.1 添加依赖 <dependencies><!--spring security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!--web起步依赖-…...

echarts中横向柱状图的数字在条纹上方
实现效果: 数字在条纹的上方 实现方法:这些数字是用新添加一个坐标轴来实现的 直接添加坐标轴数字显示是在条纹的正右边 所以需要配置一下偏移 完整代码 var option {grid: {left: "3%",right: "4%",bottom: "3%",cont…...

【仙逆】尸阴宗始祖现身,王林修得黄泉生窍诀,阿呆惊险逃生
【侵权联系删除】【文/郑尔巴金】 深度爆料最新集,王林终于成功筑基,这一集的《仙逆》动漫真是让人热血沸腾啊!在这个阶段,王林展现出了他的决心和毅力,成功地击杀了藤厉,并采取了夺基大法,从藤…...
C++二叉树剪枝
文章目录 C二叉树剪枝题目链接题目描述解题思路代码复杂度分析 C二叉树剪枝 题目链接 LCR 047. 二叉树剪枝 - 力扣(LeetCode) 题目描述 给定一个二叉树 根节点 root ,树的每个节点的值要么是 0,要么是 1。请剪除该二叉树中所有节…...

ZooKeeper中节点的操作命令(查看、创建、删除节点)
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

【C++】纯虚函数类外可以写实现吗?
1. 答案 先说答案,可以。 2.代码测试 .h头文件 #include <iostream> #include <string>// 抽象基类 class AbstractBase { public:AbstractBase() default;virtual ~AbstractBase() default; // 默认析构函数public:virtual int PureVirtualFunct…...

客户案例 | 短视频点播企业海外视频加速与成本优化:MediaPackage+Cloudfront 技术重构实践
01技术背景与业务挑战 某短视频点播企业深耕国内用户市场,但其后台应用系统部署于东南亚印尼 IDC 机房。 随着业务规模扩大,传统架构已较难满足当前企业发展的需求,企业面临着三重挑战: ① 业务:国内用户访问海外服…...