数字图像处理项目——基于BCNN和迁移学习的鸟类图像细粒度分类(论文/代码)

完整的论文代码见文章末尾 以下为核心内容

摘要

本文采用了ResNet50、VGG19、InceptionV3和Xception等四种不同的深度神经网络模型,并应用于鸟类图像的细粒度分类问题中,以探究其在该任务上的性能表现。

其中,本文使用了BCNN(Bilinear CNN)方法,将两个CNN网络进行双线性池化,从而提取不同层级的特征信息,并结合SVM分类器进行分类。实验结果表明,四种不同的深度神经网络模型均能够对鸟类图像进行良好的分类。在准确率方面,Xception表现最佳,达到了92.8%的准确率,其次是InceptionV3(91.4%)、ResNet50(90.2%)和VGG19(87.5%)。同时,通过比较不同层级的特征信息,发现高层级的特征对于细粒度分类具有重要作用。

因此,本文展示了使用深度神经网络模型进行鸟类图像细粒度分类的可行性,并验证了BCNN方法在该任务上的有效性。这对于开展生物多样性研究、生态环境保护等具有重要的实际意义。

训练过程

数据集 环境

数据集:CUB_200_2011是一个用于鸟类图像分类的数据集,包含11788张鸟类图像。

图像数量:数据集中共有11788张图像,其中5994张用作训练集,5794张用作测试集。

类别:数据集中包含了200个不同的鸟类子类别,每个子类别都属于鸟类的一个类别。

每张图片:每张图像都有一些附加信息,包括15个部位的位置信息、312个二进制属性和一个边界框(bounding box)。

环境:使用TensorFlow深度学习框架。

模型搭建

首先,加载数据。通过读取CUB_200_2011文件夹下的train_test_split.txt文件,可以获得训练集和测试集的数据。然后将数据保存到new_train.h5和new_val.h5文件中,以便数据的存储和模型对数据的读取。

接下来,构建模型。基于VGG16卷积神经网络,并导入预训练好的网络参数。移除网络的最后一个全连接层,只保留卷积层。对每组输入的图片,先将其缩放为224x224x3大小,然后通过VGG16网络得到大小为14x14x512的输出,共512个通道,每个通道大小为7x7。然后将输出复制一份,对两份输出的通道进行内积运算,再将内积结果取平均并开方,得到一个512x512维的向量。将向量进行归一化,并通过一个全连接层输出一个200维的向量,对应结果的200个类别,最后选择数值最高的维度作为最后的分类结果。

在模型训练阶段,使用tf.train.MomentumOptimizer(momentum=0.9)进行优化。训练分为两步,第一步锁定卷积层参数,只训练全连接层,学习率为0.9。第二步载入第一步训练得到的全连接层数据,同时训练卷积层和全连接层参数,学习率为0.01。为了减少过拟合,采用三个策略:①随机翻转,对输入网络的图片进行上下或左右翻转。②随机变形,对输入网络的图片进行小幅度拉伸变换并裁剪成相同大小。③随机dropout,在训练过程中随机屏蔽部分全连接层的参数。

评估模型时,使用224x224大小的图片作为输入,最终训练结果达到73%的准确率,与论文中的84%相比还有差距。尝试将输入图片放大为448x448x3大小,准确率有所提高,但由于时间限制,训练不充分,最终准确率为79.9%。

BCNN效果的解释如下:增加了特征数量同时去掉了位置的影响。

在这里插入图片描述

部分代码展示

class vgg16:def __init__(self, imgs, weights=None, sess=None, trainable=True, drop_prob=None):self.imgs = imgsself.last_layer_parameters = []     self.parameters = []                self.convlayers(trainable)          self.fc_layers()                    self.weight_file = weights           self.drop_prob=drop_prob       #self.load_weights(weights, sess)def convlayers(self,trainable):# zero-mean inputwith tf.name_scope('preprocess') as scope:mean = tf.constant([123.68, 116.779, 103.939], dtype=tf.float32, shape=[1, 1, 1, 3], name='img_mean')images = self.imgs-meanprint('Adding Data Augmentation')# conv1_1with tf.name_scope('conv1_1') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 3, 64], dtype=tf.float32,stddev=1e-1), trainable=trainable, name='weights')conv = tf.nn.conv2d(images, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[64], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv1_1 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv1_2with tf.name_scope('conv1_2') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 64, 64], dtype=tf.float32,stddev=1e-1), trainable=trainable, name='weights')conv = tf.nn.conv2d(self.conv1_1, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[64],  dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv1_2 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# pool1self.pool1 = tf.nn.max_pool(self.conv1_2,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='SAME',name='pool1')# conv2_1with tf.name_scope('conv2_1') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 64, 128], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.pool1, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[128], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv2_1 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv2_2with tf.name_scope('conv2_2') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 128, 128], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.conv2_1, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[128], dtype=tf.float32), trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv2_2 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# pool2self.pool2 = tf.nn.max_pool(self.conv2_2,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='SAME',name='pool2')# conv3_1with tf.name_scope('conv3_1') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 128, 256], dtype=tf.float32,stddev=1e-1),  trainable=trainable, name='weights')conv = tf.nn.conv2d(self.pool2, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv3_1 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv3_2with tf.name_scope('conv3_2') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.conv3_1, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv3_2 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv3_3with tf.name_scope('conv3_3') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256], dtype=tf.float32,stddev=1e-1),  trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.conv3_2, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[256], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv3_3 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# pool3self.pool3 = tf.nn.max_pool(self.conv3_3,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='SAME',name='pool3')# conv4_1with tf.name_scope('conv4_1') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 512], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.pool3, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv4_1 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv4_2with tf.name_scope('conv4_2') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 512, 512], dtype=tf.float32,stddev=1e-1), trainable=trainable,   name='weights')conv = tf.nn.conv2d(self.conv4_1, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv4_2 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv4_3with tf.name_scope('conv4_3') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 512, 512], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.conv4_2, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv4_3 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# pool4self.pool4 = tf.nn.max_pool(self.conv4_3,ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1],padding='SAME',name='pool4')# conv5_1with tf.name_scope('conv5_1') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 512, 512], dtype=tf.float32,stddev=1e-1),  trainable=trainable, name='weights')conv = tf.nn.conv2d(self.pool4, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv5_1 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv5_2with tf.name_scope('conv5_2') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 512, 512], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.conv5_1, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv5_2 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]# conv5_3with tf.name_scope('conv5_3') as scope:kernel = tf.Variable(tf.truncated_normal([3, 3, 512, 512], dtype=tf.float32,stddev=1e-1), trainable=trainable,  name='weights')conv = tf.nn.conv2d(self.conv5_2, kernel, [1, 1, 1, 1], padding='SAME')biases = tf.Variable(tf.constant(0.0, shape=[512], dtype=tf.float32),trainable=trainable, name='biases')out = tf.nn.bias_add(conv, biases)self.conv5_3 = tf.nn.relu(out, name=scope)self.parameters += [kernel, biases]self.InnerPro = tf.einsum('ijkm,ijkn->imn',self.conv5_3,self.conv5_3)self.InnerPro = tf.reshape(self.InnerPro,[-1,512*512])self.InnerPro = tf.divide(self.InnerPro,14.0*14.0)  self.ySsqrt = tf.multiply(tf.sign(self.InnerPro),tf.sqrt(tf.abs(self.InnerPro)+1e-12))self.zL2 = tf.nn.l2_normalize(self.ySsqrt, dim=1)

结果展示

基于 ResNet50 模型,在 CUB_200_2011 数据集上可以获得 64.7%的准确率。利用 stacking 方法,构建基于 4 个预训练的模型分类器对 CUB_200_2011 数据集 200 类鸟进行分类,可以获得 74.5%的准确性。

在这里插入图片描述

论文 代码 获取方式

点这里 只需要一点点辛苦费

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/802563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

查分约束学习

问题模型&#xff1a; 有n个变量&#xff1a;&#xff0c;有m个约束条件 令差分数组&#xff0c;可以知道如果x1x2<q&#xff0c;那么与j和i-1有关联 由画图可知&#xff0c;如果有在i-1至j建立的有向图中跑最短路&#xff0c;那么dis[n]即为最小的约束变量 另外&#x…

Chrome浏览器如何跟踪新开标签的网络请求?

在测试一个东西的时候&#xff0c;它虽然是a链接&#xff0c;但是&#xff0c;是由前端在js里写跳转的。我又必须要知道它的跳转链接&#xff0c;只能用截屏的方式来捕捉浏览器的地址栏链接 打开浏览器控制台(F12)点击红色箭头打钩为弹出式窗口自动打开DevTools 英文版调试参…

华大单片机新建工程步骤

1.新建文件夹&#xff0c;比如00_LED 2.拷贝 hc32f460_ddl_Rev2.2.0\driver 到 00_LED 3.拷贝 hc32f460_ddl_Rev2.2.0\mcu\common 到 00_LED 4.拷贝 hc32f460_ddl_Rev2.2.0\example\ev_hc32f460_lqfp100_v2\gpio\gpio_output\source 到 00_LED 5.拷贝 hc32f460_ddl_Rev2.2.…

933.最近的请求次数

题目&#xff1a;写一个 RecentCounter 类来计算特定时间范围内最近的请求。 请你实现 RecentCounter 类&#xff1a; RecentCounter() 初始化计数器&#xff0c;请求数为 0 。int ping(int t) 在时间 t 添加一个新请求&#xff0c;其中 t 表示以毫秒为单位的某个时间&#x…

HarmonyOS 开发-使用SideBarContainer侧边栏淡入淡出动效实现案例

介绍 在2in1或平板上&#xff0c;群聊侧边栏是一种较为常用的功能&#xff0c;虽然HarmonyOS已经具备了基本的动效&#xff0c;但是部分情况下开发者可能有定制侧边栏动效的需求&#xff0c;本例主要介绍了如何基于显式动画实现侧边栏的淡入淡出动效。 效果图预览 使用说明&a…

​泛微文书定人事档案一体化管理,覆盖人事管理全过程,人事档案全量归档

人事档案是个人身份、学历、资历等方面的证据&#xff0c;与个人工资待遇、社会劳动保障、组织关系紧密挂钩&#xff0c;具有法律效力。应注重收集和鉴别、整理工作&#xff0c;提升人事档案利用率。 企业应依据国家有关人事档案管理规定&#xff0c;制定企业人事档案管理办法&…

【吊打面试官系列】Java高并发篇 - 什么是线程组,为什么在 Java 中不推荐使用?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是线程组&#xff0c;为什么在 Java 中不推荐使用&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是线程组&#xff0c;为什么在 Java 中不推荐使用&#xff1f; ThreadGroup 类&#xff0c;可以把线程归属…

领鸡蛋游戏养鸡游戏淘宝客源码广告联盟

用户中心 用户信息&#xff1a;显示用户名、头像、鸡蛋数量、足迹等基本信息。我的足迹&#xff1a;展示用户的饲料获取记录明细&#xff0c;包括来源、数量和时间。我的好友&#xff1a;展示邀请的好友列表&#xff0c;支持好友间互动&#xff0c;如串门、偷取/赠送饲料&#…

wait 和 notify

由于线程之间是抢占式执行的, 因此线程之间执行的先后顺序难以预知。但是实际开发中有时候我们可以通过一些 api 让线程主动阻塞&#xff0c;从而控制多个线程之间的执行先后顺序. 完成这些操作就需要用到 wait&#xff0c;notify / notifyAll 注意: wait, notify, notifyAll…

Google Play上架:2024年4月份政策更新改动

4月份政策更新改动 关于恶意软件新增伪装软件新增间谍软件关于移动垃圾软件详细定义关于不当内容暴力极端主义关于设备和网络滥用金融服务关于恶意软件 我们将更新恶意软件政策,阐明伪装软件是一种恶意软件。伪装软件是一种利用多种规避技术向用户提供不一致或虚假功能的应用…

如何让MacOS「终端」走代理

在 MacOS 操作系统中&#xff0c;默认情况下&#xff0c;终端命令行不会通过代理进行网络连接。这导致在应用软件研发过程中&#xff0c;许多需要通过命令行下载安装的软件或依赖包无法成功安装。经常出现Failed to connect to xxx port 443 after 75329 ms: Couldnt connect t…

html写一个登录注册页面

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>注册登录界面Ⅰ</title><link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.mi…

基于SpringBoot+vue的在线商城系统+论文+免费远程调试

基于SpringBootvue的在线商城系统034(含源码 数据库文档免费送&#xff09; 开发系统:Windows10 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springb…

苹果电脑(Mac)怎么清理 itunes 备份?

苹果电脑用户广泛利用 iTunes 应用程序对 iPhone 或 iPad进行定期备份&#xff0c;以确保珍贵的数据安全无虞。然而&#xff0c;随着备份历史的增长&#xff0c;它们会在磁盘上积累大量空间&#xff0c;尤其当您频繁为多台设备备份时&#xff0c;存储资源可能会迅速消耗殆尽。为…

第46期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

基于SpringBoot+Vue+Mysql的图书管理系统

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Php和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

为什么 C/C++ 的库很喜欢缩写?

一、正如很多回答已经提到的&#xff0c;早期的有效标识符长度有限制&#xff0c;所以缩写用得比较多。也主要是在 C 里&#xff08;Unix 的传统&#xff09;。C 里的标识符用缩写的不多。如 C98&#xff08;毕竟比 C89 晚了 9 年么&#xff09;里我们就已经有了很多挺长的名字…

亚马逊电子产品审核?需要提交UL测试报告?

亚马逊要求销售的电子产品&#xff0c;必须经过检测符合标准才可以上架。 要办理亚马逊美国站UL测试报告&#xff0c;你需要联系国内的第三方检测机构&#xff0c;当然必须是由符合ISO17025/ILAC ISO 17025标准的实验室出具的合格报告&#xff0c;ISO 17025标准是国际上广泛认…

使用flex布局写6种骰子

使用flex布局写6种骰子&#x1f3b2; 效果图 概述说明 不使用position定位&#xff0c;完全靠flex进行分配位置。 在线查看 点击查看 完整代码 <template><div class"content"><ul class"list"><li class"item" v-fo…

视频图像的两种表示方式YUV与RGB(1)

了解过计算机图形图像学的该知道&#xff0c;可用RGB和YUV两种方式表示图像像素&#xff0c;视频由一帧一帧的图像组成&#xff0c;每一张图片是一个一个的像素点组成&#xff0c;既然有两种表示像素的方法&#xff0c;那就一起解一下两种表示方式的异同及优缺点。 RGB像素 这…