前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >task 7_修改 FCN(图像读取使用开源代码)

task 7_修改 FCN(图像读取使用开源代码)

作者头像
平凡的学生族
发布于 2022-05-13 11:09:50
发布于 2022-05-13 11:09:50
69600
代码可运行
举报
文章被收录于专栏:后端技术后端技术
运行总次数:0
代码可运行

1. FCN 论文学习

1.1 写作背景

卷积网络是视觉处理中可以有效生成多层特征的架构,是最前沿的技术。因此作者想构造一个“全卷积网络”,来处理任意尺寸的输入图片,并生成相应尺寸的输出。

通过改造当下热门的分类网络(VGG,AlexNet,GoogleLeNet等),我们可以让它们的架构应用于图像分类任务。

该网络得到很好的语义分割的效果,另外处理每张图片的速度也很快只需要五分之一秒。 通过skip-architecture,我们可以把深层的输出特征(更全面但更粗糙)与浅层的输出特征(更细节但更精确)相结合。这种操作有利于生成更加准确、细节饱满的分割结果。

1.2 FCN架构

卷积网络里每一层的数据都是三维数组。如果这三维为h × w × d,则h和w是图片的高和宽,d为图片的特征或者是通道数。

第一层输入图片,图片维度为[高, 宽, 色彩通道数]。网络深层的每个数据都与网络浅层的一片数据有关,这就叫做感知野

  • FCN的输入更灵活。普通的LeNet,AlexNet等卷积网络只能接受固定维度的输入,而FCN可以接受任意维度的输入
  • FCN的运算更高效。
    • 进行预测时,在普通的GPU上对某个227227的图片进行预测,AlexNet耗费1.2ms;而FCN从500500的图片中生成10*10的输出只需要22ms,其中的效率相差了5倍。
    • 进行后向传播时,AlexNet需要2.4ms,而FCN只需要37ms。

1.3 把粗糙输出转换为原尺寸图片

对于如何把coarse output转换得到dense prediction,作者研究过3种方案:

  1. shift-and-stitch
  2. filter rarefaction
  3. deconvolution 具体见分析三种粗糙图片转换为原尺寸图案的方案

3.1 shift-and-stich

另外,此文还详细分析了shift-and-stich方案: shift-and-stich解释

1.4 Patchwise training is loss sampling

参考[深度学习论文阅读]Fully Convolutional Networks for Semantic Segmentation(FCN网络) 通常做语义分割的方法都是使用Patchwise训练,就是指将一张图片中的重要部分裁剪下来进行训练以避免整张照片直接进行训练所产生的信息冗余,这种方法有助于快速收敛

但是本文章提出直接使用整张图片也许可能使效果更好而Patchwise可能使信息受损(所以此节名为Patchwise training is loss sampling)。

这里一个直觉得想法是一整张图像可能是有空间相关性的,那么Patchwise就减少了这种相关性

1.5 Segmentation Architecture(skip Architecture)

FCN的skip Achitecture有三种架构:FCN-32s、FCN-16s和FCN-8s。skip Achitecture通过把深层数据的结果与浅层的准确结果相结合,再恢复到原图的输出,可以生成更准确的结果。

  1. FCN-32s是指用逆卷积把conv7放大到32倍。
  2. FCN-16s是指先用逆卷积把conv7放大到2倍,将放大结果与pool4的输出相加,再把相加结果放大16倍。
  3. 同理,FCN-8s是指用逆卷积把conv7放大到2倍,将放大结果与pool4的输出相加,再把相加结果用逆卷积放大两倍,与pool3相加。最后把第二次的相加结果放大8倍到原来的图像尺寸。

根据试验,FCN-8s的效果最好,而如果再叠加层数,反而效果变差了,所以论文做到此处就停止了。 这也是FCN提升预测结果最关键的部分。

2. FCN重写

2.1 概括

在参考了github上别人的FCN框架后,我认真研究了它的代码,并结合自己的想法,重新写了一遍。 我的代码主要分为以下几个模块:

  1. FCN.py, FCN_down_sizing.py. FCN_down_sizing.py定义了FCN网络中downsizing的部分,而FCN.py结合downsizing的部分来组装FCN-8s, FCN-16s和FCN-32s
  2. read_MITSceneParsingData.py.用于为每个image找到对应的annotation,并把这些关系组保存为一个.pickle文件,供处理图片时读取。
  3. BatchDatsetReader.py.给定image与annotation相互对应的关系组,找到并读取这些图片的数据。
  4. FCN_train.py, FCN_test.py, FCN_infer.py. 显然是用于train, test和infer的。

2.2 FCN.py, FCN_down_sizing.py

我把FCN网络看做两个部分:

  1. downsizing,通过卷积使矩阵的尺寸缩小
  2. upscaling,通过逆卷积使图片恢复原本的尺寸。

不管是FCN-8s, FCN-16s还是FCN-32s,他们都需要用到把图片downsize的过程,所以FCN_down_sizing.py定义了FCN中进行downsize的这个部分。 而FCN.py则利用FCN_down_sizing.py的部分组装成FCN-8s, FCN-16s和FCN-32s(由于时间缘故,只完成了FCN-8s)。

  • downsize的部分是用vgg19搭建的(论文里是用vgg16,但效果差不多)。
  • FCN_down_sizing.py中的get_FCN_8s_net则实现了论文中的sky-architecture

2.2 read_MITSceneParsingData.py

用于从.pickle文件中读取image-annotation的路径数组,供BatchDatsetReader.py读取图片数据。 如果没有.pickle文件,则要先生成一个.pickle文件。具体做法是:遍历images目录,对每个jpg图片在annotations目录中找到对应的png图像分割文件。由此生成image-annotation的文件名集合。 这样,我们为所有的image都找到了对应的annotation的路径,就可以把它们存储为.pickle文件,供日后训练用。

2.3 BatchDatsetReader.py

在开始训练之前要读取所有的图片和图片分割。读取.pickle文件,利用其中的信息可以找到所有的image和annotation并读取为矩阵的形式。 这样,image_list的维度为(num_images, height, width, 3), annotation_list的维度为(num_annotations, height, width, 1),且类型都是numpy.ndarray。

  • 由于训练的数据并非全部是Rgb的三通道图,有些是灰度图(只有单通道)。为了统一处理,要把这些灰度图转换为三通道的形式。

2.3 ImageReader.py

training中,通常的程序逻辑是这样的:

  1. 生成image-annotation的文件名集合。遍历images目录,对每个jpg图片在annotations目录中找到对应的png图像分割文件。这样,我们为所有的image都找到了对应的annotation的路径,就可以把它们存储为.pickle文件,供日后训练用。
  2. 在开始训练之前要读取所有的图片和图片分割。读取.pickle文件,利用其中的信息可以找到所有的image和annotation并读取为矩阵的形式。这样,image_list的维度为(num_images, height, width, 3), annotation_list的维度为(num_annotations, height, width, 1),且类型都是numpy.ndarray。
    • 由于训练的数据并非全部是Rgb的三通道图,有些是灰度图(只有单通道)。为了统一处理,要把这些灰度图转换为三通道的形式。重写时在此栽过跟头。

3. 遇到的问题

3.1 问题1 image维度不统一

image数据大部分是三维的(h, w, 3),但有少部分是灰度图,也就是二维的(h, w) annotation数据则都是二维的(h, w)

因此处理image数据时,如果遇到二维的图片,要先转为三维且有3个通道的图片。

3.2 问题2 scipy.misc.imresize is deprecated

问题描述 原作者的代码中,图片的变形使用的是scipy.misc.imresize函数。 但我发现这个函数除了对图片变形,还会自行做一些多余的动作。它会把数组里的值标准归一化到[0, 255]的区间内,破坏图片原本的信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
arr = np.array([[[100, 2, 220], [3, 4, 5]], [[1, 2, 3], [3, 4, 5]]])

print(type(arr))
print(arr.shape)

resize_size = 4
arr = misc.imresize(arr, [resize_size, resize_size], interp='nearest')
print(type(arr))
print(arr.shape)
print(arr)

输出

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<class 'numpy.ndarray'>
(2, 2, 3)
<class 'numpy.ndarray'>
(4, 4, 3)
[[[115   1 255]
  [115   1 255]
  [  2   3   5]
  [  2   3   5]]

 [[115   1 255]
  [115   1 255]
  [  2   3   5]
  [  2   3   5]]

 [[  0   1   2]
  [  0   1   2]
  [  2   3   5]
  [  2   3   5]]

 [[  0   1   2]
  [  0   1   2]
  [  2   3   5]
  [  2   3   5]]]

解决方法 最后查阅官方文档才知道这个函数已经被废止。 于是我将对图片的操作都改用skimage库实现了。而对图片的变形则使用skimage.transform.resize函数。

3.3 问题3 ValueError: could not broadcast input array from shape (224,224,3) into shape (224,224)

问题描述

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    reader = ImageReader("train")
  File "/root/Desktop/FCN/ImageReader.py", line 58, in __init__
    self.image_list = np.array([self.readImage(record["image"]) for record in self.records])
ValueError: could not broadcast input array from shape (224,224,3) into shape (224,224)

在改用skimage库操作图片后,出现了无法把元素合并到一个数组的问题。对image里的图片的操作失败了。

查阅stackoverflow的问题发现原来是元素的维度并不统一。

我原以为所有image里的图片都是三通道的,也就是(h, w, 3)的。这样如果我要得到固定尺寸的图片(比如224 * 224),只需调用skimage.transform.resize,就能把图片转为(224, 224, 3)。理应所有图片都会被转换成(224, 224, 3)的维度。可是既然图片们无法共容在一个数组里,说明有的图片没有转换成这种维度

问题原因 原来,image里并不是所有图片都是(h, w, 3)形式的,有的图片是灰度图(在20210张图片中有4张是灰度图),也就是(h, w)形式。而我的代码没有考虑到这一点,导致这几张灰度图被转换后的维度错误。

解决方法 对于这几张灰度图,需要将其转换为三通道的形式。只需要把单通道上的值重复三次作为三个通道的值即可。

3.4 问题4 图片转换后内容被破坏

问题描述

在给skimage.transform.resize添加reserve_range = True设置后,发现转换后的图片内容完全被破坏。似乎维持值的范围会破坏图片的可见性。

问题原因

查阅了stackoverflow 原来pyplot.imshow只能显示[0.0, 1.0]范围的图片,而reserve_range = True会使图片仍然在[0, 255]范围内,且数据类型为float64,被以[0.0, 1.0]的范围来看待,这就无法正确显示了。

另外,查阅官方文档reserve_range参数

preserve_range : bool, optional Whether to keep the original range of values. Otherwise, the input image is converted according to the conventions of img_as_float. 确实如果不设置reserve_range = True,函数会把值的范围标准归一化到[0.0, 1.0]内,也就是img_as_float.

问题解决

显示图片时先使用image = np.copy(old_image).astype('uint8'),把类型从float64转换为uint8即可。

3.5 问题5 查看源代码的卷积核维度

通过在源代码中添加如下代码可输出各层卷积核的维度

输出:

仅截取部分输出

根据输出,我发现源代码使用的是VGG-19,而论文中使用的是VGG-16。两者的效果应该差不多,为了保持一致,我依旧按照VGG-19来叠加。

3.6 问题6 tf.layers.conv2d_transpose的放大倍数

tf.layers.conv2d_transpose只能指定strides来调整输出图片的尺寸。 strides = [2, 2]时放大两倍,strides = [8, 8]时放大8倍

3.7 问题7 numpy array的特殊索引方式

代码中此段是用来打乱images和annotations的,开始看的时候不懂,感觉这不符合Python的语法,后来查了官方文档发现,原来这是numpy.ndarray重载过的行为,是numpy.ndarray的特殊的索引方式。

基本用法如下:

所以,通过传递一

3.8 mean_iou过低

问题描述 发现不管如何调优,mean_iou的数值很低。 问题原因 原来是因为在缩放annotation的过程中,使用的方法会拉扯那些值,使得annotation出现了本来不存在的分类。比如原本annotation里的值只有3,4,5,经过缩放,值被拉扯,变成了二点几、三点几、和六点几,等等。而图原本是没有6这个分类的,这就导致mean_iou的计算出现巨大的偏差。 解决方法 图片缩放函用回scipy.sisc.imresize,因为这个函数有按nearest模式缩放的功能,在缩放图片的同时不改变图片内的值的种类。

感想

  1. 在测试的时候图方便,总是读取整个数据集,其中等待浪费了很长时间,经常读取完以后才发现bug。以后应该先只读取一部分,保证代码正确运行,再读取整个数据集
  2. 代码对内存的优化不好。由于每次测试都读取整个数据集,有时候出现内存用爆导致Memory Error的情况,以后编程要注意节省内存空间
  3. 第一次从头到尾地进行编程,有些手忙脚乱。以后应当先分析数据集的成分,构建读取器,再构建神经网络,读取部分数据进行测试。保证无bug后才对。

参考

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
前端-关于 Vue 和 React 区别的一些笔记
这篇文章记录我在使用Vue和React的时候,对他们的不同之处的一些思考,不仅局限于他们本身,也会包括比如 Vuex/Redux 等经常搭配使用的工具。因为涉及到的内容很多,可能下面的每一个点都能写成一篇文章,这次先简单做一个概要,等我有空做一个详细的专题出来。
grain先森
2019/03/29
6K0
前端-关于 Vue 和 React 区别的一些笔记
关于 “ React 和 Vue 该用哪个” 我真的栓 Q
来源 | OSCHINA 社区 作者 | 京东云开发者-孙凯 原文链接:https://my.oschina.net/u/4090830/blog/5587296 一、前言:我全都要 面对当今前端界两座大山一样的主流框架,React 和 Vue,相信很多小伙伴都或多或少都产生过这样疑问,而这样的问题也往往很让人头疼和犹豫不决: 业务场景中是不是团队用什么我就用什么? 如果选择了其中一个使用,那为什么不用另一个? 这两个框架各有什么优点和无法解决的问题? 最新版本的 Vue3 已经出了一段时间了,我要不要做组
程序猿DD
2023/04/24
2.4K1
关于 “ React 和 Vue 该用哪个” 我真的栓 Q
公司要求会使用框架vue,面试题会被问及哪些?
如果你是一个已经在学习前端开发的初学者亦或者是一名在代码界纵横多年的程序员,那你一定知道现在最火的前端框架之一Vue.js。它相比于React与Angular上手更加容易,或许这也是很多初学者选择vue的原因之一。
coder_koala
2019/07/30
2.4K0
公司要求会使用框架vue,面试题会被问及哪些?
vue和react的区别
React默认是通过比较引用的方式(diff)进行的,如果不优化可能导致大量不必要的VDOM的重新渲染。为什么React不精确监听数据变化呢?这是因为Vue和React设计理念上的区别,Vue使用的是可变数据,而React更强调数据的不可变,两者没有好坏之分,Vue更加简单,而React构建大型应用的时候更加鲁棒。
扬起
2022/06/28
6820
vue和react的区别
前端一面经典vue面试题(持续更新中)
只需要在组件即将被销毁的生命周期 componentWillUnmount (react)中在 LocalStorage / SessionStorage 中把当前组件的 state 通过 JSON.stringify() 储存下来就可以了。在这里面需要注意的是组件更新状态的时机。
bb_xiaxia1998
2022/12/07
9230
react16常见api以及原理剖析
React 与 Vue 有很多相似之处,React 和 Vue 都是非常优秀的框架,它们之间的相似之处多过不同之处,并且它们大部分最棒的功能是相通的:如他们都是 JavaScript 的 UI 框架,专注于创造前端的富应用。不同于早期的 JavaScript 框架“功能齐全”,Reat 与 Vue 只有框架的骨架,其他的功能如路由、状态管理等是框架分离的组件。
前端迷
2019/09/25
1K0
react16常见api以及原理剖析
VUE
当 一 个 Vue 实 例 创 建 时 , Vue 会 遍 历 data 中 的 属 性 , 用 Object.defineProperty ( vue3.0 使 用 proxy ) 将 它 们 转 为 getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组
江拥羡橙
2023/11/27
2770
VUE
一大波vue面试题及答案精心整理
keep-alive是 Vue 提供的一个内置组件,用来对组件进行缓存——在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
bb_xiaxia1998
2022/11/04
5950
Vue 和 React 有什么不同?
其实我对这两大框架也没有认真钻研过它们的细节,也就是工作上用它们写一些简单业务,或偶尔看看相关的博客文章,但还是有一些浅显的认识的,写下来记录一下。
前端西瓜哥
2022/12/21
1.8K0
Vue 和 React 有什么不同?
2022前端二面必会vue面试题汇总
key是为Vue中的vnode标记的唯一id,通过这个key,我们的diff操作可以更准确、更快速
bb_xiaxia1998
2022/09/16
9380
React常见面试题
动态加载(异步组件)加载时会有延迟,在延迟期间可以将一些内容展示给用户,比如:loading
隔壁老陈
2023/01/12
4.2K0
React常见面试题
这可能是你需要的vue考点梳理
Vue2.x开始引入"Virtual DOM",消除了和React在这方面的差异,但是在具体的细节还是有各自的特点。
bb_xiaxia1998
2022/11/01
1.1K0
React移动web极致优化
本文start kit: steamer-react PS: 要看效果得将一个QQ群组转换成家校群,可到此网址进行转换(手Q/PC都可以访问): http://qun.qq.com/homework
李成熙heyli
2018/01/05
1.5K0
React移动web极致优化
【Vuejs】778- 超全 Vuejs 知识点(基础到进阶)
https://juejin.im/post/5ec358126fb9a0432a3c49e6
pingan8787
2020/11/19
3.3K0
【Vuejs】778- 超全 Vuejs 知识点(基础到进阶)
React 移动 web 极致优化
image.png 引言 最近一个季度,我们都在为手Q家校群做重构优化,将原有那套问题不断的框架换掉。经过一些斟酌,决定使用react 进行重构。 选择react,其实也主要是因为它具有下面的三大特性。 React的特性 1.Learn once, write anywhere 学习React的好处就是,学了一遍之后,能够写 web, node 直出,以及 native,能够适应各种纷繁复杂的业务。需要轻量快捷的,直接可以用 Reactjs;需要提升首屏时间的,可以结合 React Server Rende
腾讯Bugly
2018/03/23
1K0
React 移动 web 极致优化
vue高频面试题合集(一)附答案
Vue 3.0 正走在发布的路上,Vue 3.0 的目标是让 Vue 核心变得更小、更快、更强大,因此 Vue 3.0 增加以下这些新特性:
helloworld1024
2022/08/11
9870
React应用优化:避免不必要的render
React在组件的生命周期方法中提供了一个钩子shouldComponentUpdate,这个方法默认返回true,表示需要重新执行render方法并使用其返回的结果作为新的Virtual DOM节点。通过实现这个方法,并在合适的时候返回false,告诉React可以不用重新执行render,而是使用原有的Virtual DOM 节点,这是最常用的避免render的手段,这一方式也常被很形象地称为“短路”(short circuit)。
博文视点Broadview
2020/06/12
1.4K0
Vue的前世今生 | 核心原理分析
watcher不再与单个dom节点、指令关联,一个component对应一个watcher,极大减少了vue 1 中watcher数量过多导致的内存问题。同时以来vdom diff在渲染时能以最小的代价来更新dom。
前端LeBron
2021/12/08
6650
Vue的前世今生 | 核心原理分析
前端面试题汇总-Vue篇
当一个Vue实例创建时,Vue会遍历data中的属性,用 Object.defineProperty(vue3.0使用proxy )将它们转为 getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。
越陌度阡
2023/01/01
1.6K0
前端面试题汇总-Vue篇
前端react面试题(边面边更)
(1)无状态函数式组件 它是为了创建纯展示组件,这种组件只负责根据传入的props来展示,不涉及到state状态的操作
beifeng1996
2022/10/26
1.3K0
相关推荐
前端-关于 Vue 和 React 区别的一些笔记
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验