可视化Faster R-CNN算法详细过程

1.项目概述

运行环境tensorflow2.x,使用VOC2007数据集实现Faster-RCNN目标检测算法。 本文将详细介绍并讲解算法的每个模块和每个函数的功能,并可视化一张图片在训练和测试过程中    的变化情况。 Faster RCNN首次提出了anchor机制,后续大量流行的SSD、R-CNN、Fast RCNN、Faster RCNN、Mask RCNN和RetinaNet等等 模型都是在建立在anchor基础上的,而yolov3、yolov5等模型尽管对anchor做了一些调整,但出发点不变, 都是从anchor的三个任务和参数化坐标出发,因此,Faster RCNN很重要。

本项目基于2.4+版本的tensorflow,使用VOC2007数据集实现Faster-RCNN目标检测算法。接下来将详细讲解Faster-RCNN算法的每个模块的主要功能,期间通过可视化一张图片在训练和测试过程中如何变化的。

整个Faster-RCNN算法的网络架构图

2.数据描述

VOC2007数据集的结构如下:

各个目录含义如下:
1、Annotations中存储的是.xml文件,即标注数据,标注了影像中的目标类型以及边界框bbox;
2、ImageSet中存储的都是一些txt文件,其实就是各个挑战任务所使用的图片序号,VOC比赛是将所有的图片存在一起,然后不同的挑战任务使用的图片就用一个txt存储使用图片的文件名即可;
3、JPEGImages文件夹中存储了数据集的所有图片;
4、SegmentationClass存储了类别分割的标注png。
5、SegmentationObject存储了实例分割的标注png。 其中类别分割与实例分割的区别是类别分割只区分物体的类别,同样类别的两个不同物体的像素分配同一个值;而实例分割不只区分目标的类别,而且同样类别的两个不同的对象,也要进行区分。例如两个人,在类别分割中都标注为person,而实例分割就需要分割为person1、person2.
VOC2007数据集的更大介绍可参考:https://www.codenong.com/cs106063597/

3.项目流程

1.导入需要的模块
2.导入数据
3.提取特征
4.恢复模型权重参数
5.可视化训练后的特征图
6.实现RPN网络
7.实现RoI Pooling
8.可视化最后结果

3.1 导入需要的模块

3.2 导入数据

第11张图片基本信息说明:
1、img的shape为(1, 600, 900, 3)分别代表了batch维度,图片的高和宽,通道数;
2、bboxes的类别数及坐标信息,shape为(n, 4),这里n表示该图片所含的类别总数,最大为20,不包括背景;
3、labels的shape为(n,),该图片所含的类别总数,类别代码,这里6表示汽车。

运行结果:

3.3 特征提取

这里使用VGG16作为主干网络(backbone),经过backbone之后,输出为特征图,其形状为(1, 38, 57, 512),1代表batch size,38和57代表特征图的高度和宽度,数值上为原来(600, 900)的1/16(中间会有向下取整操作),512代表通道数。

待续……

目标检测与识别中的几个重要概念

一、目标检测的目的和挑战

1、目标检测的目的

目标检测的目的是什么?主要就是:
(1)确定目标对象所在位置及大小;
(2)确定目标对象的类别
第1点是属于检测,第2点识别,重点是检测,目标图像检测后识别与一般图像识别一样。如何检测目标对象?我们可以通过以下图像更形象地进行说明。为简便起见,我们假设图像中只有1个目标对象(或少数几个目标对象),对这个图像进行检测的目标就是,
用矩形框界定目标对象,如下图所示。


图1 目标检测示意图
把要检测的目标用矩阵图框定,然后对框定的目标进行分类,这就是目标检测的主要目标。框定目标并识别目标两个任务中,框定目标是关键。如何框定目标呢?
我们从简单的情况开始,然后,再考虑更复杂的情况。
假设图像中只有一个目标,如图1的左图。这种情况,我们凭直觉最先想到的或许就是使用一个矩形框窗口,从左到右移动,如图2所示。

图2 用一个框进行自左向右移动示意图
这是一种非常理想情况,使用的框大小正好能框,这些候选框确定后,就可以针对每个框使用分类模型计算各框为猫的概率或得分,如图3所示。看哪个框的得分最高就选择哪个框,从图3 可知,中间这个框内容对象为猫的概率最大,故选择这个框(如图1左图所示)。框确定意味着这个框的左上点的坐标(x,y)及这个框的高(h)和宽(w)也确定了。

图3 不同框中对象的概率或得分示意图
当然这是一种非常简单的情况,实际情况往往要复杂的多,挑战更大。

2、目标检测的主要挑战

目标检测的主要挑战可归纳如下:
目标对象位置不定
目标对象有不同大小和形状
对象有多种,同一种也可能有多个
存在遮掩、光照等问题
如何既准又快的完成这些任务
如图13-1 右图所示。对这种情况,当然我们可以使用不同大小的窗口,然后采用移动的方法,这种产生候选框的方法理论上是可行的,但因此而产生的的框将很大,而且这种方法不管图像中有几个对象,都需要如此操作,效率非常低。
为解决这一问题,人们研究了很多方法,目前还在不断更新迭代中。以下我们简介几种典型方法。

二、生成候选框的常用方法

1、选择性搜索方法(SS)

选择性搜索方法(Selective Search,简称SS)如何对图像进行划分呢?它不是通过大小网格的方式,而且通过图像中的纹理、边缘、颜色等信息对图像进行自底向上的分割,然后对分割区域进行不同尺度的合并,每个生成的区域即一个候选区框,如图4所示。这种方法基于传统特征,速度较慢。

图4 使用SS算法生成候选框的示意图
SS算法基本思想为:
(1)首先通过基于图的图像分割方法(Image Segmentation)将图像分割成很多很多的小块;
(2)使用贪心策略,基于相似度(如颜色相似度、尺寸相似度、纹理相似度等)合并一些区域。

2、RPN算法

SS采用传统特征提取方法,而且非常耗时。是否有更有效方法呢?Faster R-CNN算法中提出一种基于神经网络的生成候选框方法,那就是RPN。
RPN(Region Proposal Networks)层用于生成候选框,并利用softmax判断候选框是前景还是背景,从中选取前景候选框(因为物体一般在前景中),并利用bounding box regression调整候选框的位置,从而得到特征子图,称为proposals。
RPN的工作原理:

上图展示了RPN网络的具体结构。
首先,经过一次3x3的卷积操作,最后得到了一个channel数目是256的特征图,尺寸和公共特征图相同,我们假设是256 x(H x W)。
然后,经过2条支线:
(1)上面一条支线通过softmax来分类anchors获得前景foreground和背景background(检测目标是foreground),
(2)下面一条支线用于计算anchors的边框偏移量,以获得精确的proposals。
最后的proposal层则负责综合foreground anchors和偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就完成了相当于目标定位的功能。
这里涉及一个重要概念anchor:简单地说,RPN依靠一个在共享特征图上滑动的窗口,为每个位置生成9种预先设置好长宽比与面积的目标框(即anchor)。这9种初始anchor包含三种面积(128×128,256×256,512×512),每种面积又包含三种长宽比(1:1,1:2,2:1)。示意图如下图所示:

由于共享特征图的大小约为40×60,所以RPN生成的初始anchor的总数约为20000个(40×60×9)。其实RPN最终就是在原图尺度上,设置了密密麻麻的候选anchor。进而去判断anchor到底是前景还是背景,意思就是判断这个anchor到底有没有覆盖目标,以及为属于前景的anchor进行第一次坐标修正。如何实现坐标修正?具体可参考第三部分的边框回归(Bounding Box Regression)。

3、anchor概述

RPN的目标是代替Selective Search实现候选框的提取,目标检测的实质是对候选框的回归,而网络不可能自动生成任意大小的候选框,因此Anchor的主要意义就在于根据feature map在原图片上划分出很多大小、宽高比不相同的矩形框,RPN会对这些框进行一个粗略的分类(如是否存在目标对象)和回归,选取一些微调过的包含前景的正类别框以及包含背景的负类别框,送入之后的网络结构参与训练。
Anchor的产生过程:
(1)base_size=16 这个参数代表的是网络特征提取过程中图片缩小的倍数,和网络结构有关,ZFNet的缩小倍数为16,表明了最终feature map上一个像素可以映射到原图上16 x 16区域的大小。
(2)ratios=[0.5,1,2] 这个参数指的是要将16x16的区域,按照1:2,1:1,2:1三种比例进行变换,如下图所示:

(3)scales=2**np.arange(3, 6) 这个参数是要将输入区域的宽和高进行8,16,32三种倍数的放大,如16x16的区域变成(16x8)x(16x8)=128x128的区域,(16x16)x(16x16)=256x256的区域,(16x32)x(16x32)=512x512的区域,如下图所示:

通过以上三个参数,针对于feature map上的任意一个像素点,首先映射到原图片上一个 16 x 16 的区域,然后以这个区域的中心点作为变换中心,将其变为三种宽高比的区域,再分别对这三种区域的面积扩大8,16,32倍,最终一个像素点对应到了原图的9个不同的矩形框,这些框就叫做Anchor,如下图:

注意: 将不完全在图像内部(初始化的anchor的4个坐标点超出图像边界)的anchor都过滤掉,一般过滤后只会有原来1/3左右的anchor。如果不将这部分anchor过滤,则会使训练过程难以收敛。
Anchor是目标检测中的一个重要概念,通常是人为设计的一组框,作为分类(classification)和框回归(bounding box regression)的基准框。
无论是单阶段(single-stage)检测器还是两阶段(two-stage)检测器,都广泛地使用了anchor。例如,
两阶段检测器的第一阶段通常采用 RPN 生成 proposal,是对anchor进行分类和回归的过程,即 anchor -> proposal -> detection bbox;
大部分单阶段检测器是直接对 anchor 进行分类和回归,也就是 anchor -> detection bbox。

常见的生成 anchor 的方式是滑窗(sliding window),也就是首先定义k个特定尺度(scale)和长宽比(aspect ratio)的 anchor,
然后在全图上以一定的步长滑动。这种方式在 Faster R-CNN,YOLO v2+、SSD,RetinaNet 等经典检测方法中被广泛使用。

三、优化候选框

1、交并比(IOU)

通过SS或RPN等方法,最后每类选出的候选框(Region Proposal)比较多,在这些候选框中如何选出质量较好的框?人们想到使用IOU这个度量值。IOU(Intersection Over Union)指标来计算候选框和目标实际标注边界框的重合度。假如我们要计算两个矩形框A和B的IOU,就是它们的交集与并集之比,如下图所示:

矩形框A、B的一个重合度IOU计算公式为:

2、非极大值抑制(NMS,Non Maximum Suppression)

通过SS或RPN等方法产生的大量的候选框,这些矩形框有很多是指向同一目标(如下图所示),因此就存在大量冗余的候选。如何减少这些冗余框?NMS就是一个有效方法。

非极大值抑制(Non-Maximum Suppression,以下简称NMS算法)的思想是搜索局部极大值,抑制非极大值元素。就像上图片一样,定位一个车辆,SS或RPN算法对每个目标(如上图中汽车)生成一堆的方框,过滤哪些多余的矩形框,找到那个最佳的矩形框。
非极大值抑制的基本思路为:
先假设有6个候选框,根据分类器类别分类概率做排序,如下图所示:

从小到大分别属于车辆的概率分别为A、B、C、D、E、F。
(1)从最大概率矩形框(即面积最大的框)F开始,分别判断A~E与F的重叠度IOU是否大于某个设定的阈值;
(2)假设B、D与F的重叠度超过阈值,那么就扔掉B、D(因为超过阈值,说明D与F或者B与F,已经有很大部分是重叠的,那我们保留面积最大的F即可,其余小面积的B,D就是多余的,用F完全可以表示一个物体了,所以保留F丢掉B,D);并标记第一个矩形框F,是我们保留下来的。
(3)从剩下的矩形框A、C、E中,选择概率最大的E,然后判断E与A、C的重叠度,重叠度大于一定的阈值,那么就扔掉;并标记E是我们保留下来的第二个矩形框。
(4)一直重复这个过程,找到所有曾经被保留下来的矩形框。

3、边框回归(Bounding Box Regression)

(1)边框回归的主要目的
通过SS或RPN等算法生成的大量候选框,虽然有一部分可以通过NMS等方法过滤一些多余框,但仍然还会存在很多质量不高的框图。如下图所示。

 

其中红色矩形框(内部这个框)的质量不高(红色的矩形框定位不准(IoU<0.5), 说明这个矩形框没有正确检测出飞机)。需要通过边框回归进行修改。此外,训练时作为有监督学习,也需要通过边框回归使预测框,通过迭代不断向目标框(Ground Truth)靠近。
(2)边框回归的主要原理
下图所示,红色的框A代表生成的候选框(即positive Anchors),绿色的框G代表目标框(Ground Truth),接下来需要基于A和G,找到一种映射关系得到一个预测框G’通过迭代使G’不断接近目标框G。这个过程用数学符合可表示为:,

(3)如何找到这个对应关系F?
如何通过变换F实现从上图中的矩形框A变为矩形框G’呢? 比较简单的思路就是: 平移+放缩,具体实现步骤如下:

以认为d_\astA(这里*表示x,y,w,h)变换是一种线性变换, 如此就可以用线性回归来建模对矩形框进行微调。线性回归就是给定输入的特征向量X, 学习一组参数W, 使得经过线性回归后的值跟真实值 G(Ground Truth)非常接近. 即G≈WX 。 那么 anchor Bounding-box 中的输入以及输出分别是什么呢?

(4)边框回归为何只能微调?
要使用线性回归,要求anchor A与G相乘较小,否则这些变换将可能变成复杂的非线性变换。
(5)边框回归主要应用
在RPN生成Proposal的过程中,最后输出时也使用边框回归使预测框不断向目标框逼近。
(6)改进空间
YOLO v2提出一种直接预测位置坐标的方法。之前的坐标回归实际上回归的不是坐标点,而是需要对预测结果做一个变换才能得到坐标点,这种方法在充分利用目的对象的位置信息方面效率打了较大折扣,为更好利用目标对象的位置信息,YOLO v2采用目标对象的中心坐标及左上角的方法,具体可参考下图:

其中p_w,P_h为anchor box的宽和高,t_x,\ t_y,t_w,t_h为预测边界框的坐标值,σ是sigmoid函数。C_x,C_y为是当前网格左上角到图像左上角的距离,需要将网格大小归一化,即令一个网格的宽=1,高=1。

四、模型优化

1、SPP Net

SPP-Net 是何恺明、孙健等人的作品。SPP-Net 的主要创新点就是SPP,即Spatial pyramid pooling,空间金字塔池化。该方案解决了R-CNN 中每个region proposal 都要过一次CNN 的缺点,从而提升了效率,并且避免了为了适应CNN 的输入尺寸而图像缩放导致的目标形状失真的问题。我们通常看到的RoI pooling是SPP-net的一种变换版本。

2、FPN

FPN 全称Feature Pyramid Network,其主要思路是通过特征层面(即feature map)的转换,生成语义和低层信息都很丰富的特征金字塔,用于预测
如图所示,(a) 表示的是图像金字塔(image pyramid),即对图像进行放缩,不同的尺度分别进行预测。这种方法在目标检测里较为常用,但是速度较慢,因为每次需要对不同尺度的图像分别过一次CNN 进行训练。(b)表示的是单一feature map 的预测。由于图像金字塔速度太慢,索性直接只采用最后一层输出进行预测,但这样做同时也丢失了很多信息。(c) 表示的是各个scale 的feature map 分别进行预测,但是各个层次之间(不同scale)没有交互。SSD 模型中就是采用了这种策略,将不同尺度的bbox 分配到代表不同scale 的feature map上。(d) 即为这里要将的FPN 网络,即特征金字塔。这种方式通过将所有scale 的feature map 进行打通和结合,兼顾了速度和准确率。

如何进行横向连接和融合?如下。把高层特征做2倍上采样,然后将其和对应的前一层特征结合,注意前一层特征经过 1*1 的卷积改变维度使得可以用加法进行融合。值得一提的是,这只是其中一种融合方式,当然也可以做通道上的 concat
FPN 在每两层之间为一个buiding block,结构如下:

FPN 的block 结构分为两个部分,一个自顶向下通路(top-down pathway),另一个是侧边通路(lateral pathway)。所谓自顶向下通路,具体指的是上一个小尺寸的feature map(语义更高层)做2 倍上采样,并连接到下一层。而侧边通路则指的是下面的feature map(高分辨率低语义)先利用一个1×1 的卷积核进行通道压缩,然后和上面下来的采样后结果进行合并。合并方式为逐元素相加(element-wise addition)。合并之后的结果在通过一个3×3 的卷积核进行处理,得到该scale 下的feature map。
FPN 并不是一个目标检测框架,它的这种结构可以融入到其他的目标检测框架中,去提升检测器的性能。截至现在,FPN 已经可以说成为目标检测框架中必备的结构了。

使用transformer进行图像分类


使用Transformer来提升模型的性能
最近几年,Transformer体系结构已成为自然语言处理任务的实际标准,
但其在计算机视觉中的应用还受到限制。在视觉上,注意力要么与卷积网络结合使用,
要么用于替换卷积网络的某些组件,同时将其整体结构保持在适当的位置。2020年10月22日,谷歌人工智能研究院发表一篇题为“An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale”的文章。文章将图像切割成一个个图像块,组成序列化的数据输入Transformer执行图像分类任务。当对大量数据进行预训练并将其传输到多个中型或小型图像识别数据集(如ImageNet、CIFAR-100、VTAB等)时,与目前的卷积网络相比,Vision Transformer(ViT)获得了出色的结果,同时所需的计算资源也大大减少。
这里我们以ViT我模型,实现对数据CiFar10的分类工作,模型性能得到进一步的提升。

1、导入模型

这里使用了TensorFlow_addons模块,它实现了核心 TensorFlow 中未提供的新功能。
tensorflow_addons的安装要注意与tf的版本对应关系,请参考:
https://github.com/tensorflow/addons。
安装addons时要注意其版本与tensorflow版本的对应,具体关系以上这个链接有。

2、定义加载函数

3、定义批量加载函数

4、加载数据

把数据转换为dataset格式

5、定义数据预处理及训练模型的一些超参数

6、定义数据增强模型

预处理层是在模型训练开始之前计算其状态的层。他们在训练期间不会得到更新。大多数预处理层为状态计算实现了adapt()方法。
adapt(data, batch_size=None, steps=None, reset_state=True)该函数参数说明如下:

7、构建模型

7.1 构建多层感知器(MLP)

7.2 创建一个类似卷积层的patch层

7.3 查看由patch层随机生成的图像块

运行结果
Image size: 72 X 72
Patch size: 6 X 6
Patches per image: 144
Elements per patch: 108

7.4构建patch 编码层( encoding layer)

7.5构建ViT模型

该模型的处理流程如下图所示

8、编译、训练模型

实例化类,运行模型

运行结果
Epoch 1/10
176/176 [==============================] - 68s 333ms/step - loss: 2.6394 - accuracy: 0.2501 - top-5-accuracy: 0.7377 - val_loss: 1.5331 - val_accuracy: 0.4580 - val_top-5-accuracy: 0.9092
Epoch 2/10
176/176 [==============================] - 58s 327ms/step - loss: 1.6359 - accuracy: 0.4150 - top-5-accuracy: 0.8821 - val_loss: 1.2714 - val_accuracy: 0.5348 - val_top-5-accuracy: 0.9464
Epoch 3/10
176/176 [==============================] - 58s 328ms/step - loss: 1.4332 - accuracy: 0.4839 - top-5-accuracy: 0.9210 - val_loss: 1.1633 - val_accuracy: 0.5806 - val_top-5-accuracy: 0.9616
Epoch 4/10
176/176 [==============================] - 58s 329ms/step - loss: 1.3253 - accuracy: 0.5280 - top-5-accuracy: 0.9349 - val_loss: 1.1010 - val_accuracy: 0.6112 - val_top-5-accuracy: 0.9572
Epoch 5/10
176/176 [==============================] - 58s 330ms/step - loss: 1.2380 - accuracy: 0.5626 - top-5-accuracy: 0.9411 - val_loss: 1.0212 - val_accuracy: 0.6400 - val_top-5-accuracy: 0.9690
Epoch 6/10
176/176 [==============================] - 58s 330ms/step - loss: 1.1486 - accuracy: 0.5945 - top-5-accuracy: 0.9520 - val_loss: 0.9698 - val_accuracy: 0.6602 - val_top-5-accuracy: 0.9718
Epoch 7/10
176/176 [==============================] - 58s 330ms/step - loss: 1.1208 - accuracy: 0.6060 - top-5-accuracy: 0.9558 - val_loss: 0.9215 - val_accuracy: 0.6724 - val_top-5-accuracy: 0.9790
Epoch 8/10
176/176 [==============================] - 58s 330ms/step - loss: 1.0643 - accuracy: 0.6248 - top-5-accuracy: 0.9621 - val_loss: 0.8709 - val_accuracy: 0.6944 - val_top-5-accuracy: 0.9768
Epoch 9/10
176/176 [==============================] - 58s 330ms/step - loss: 1.0119 - accuracy: 0.6446 - top-5-accuracy: 0.9640 - val_loss: 0.8290 - val_accuracy: 0.7142 - val_top-5-accuracy: 0.9784
Epoch 10/10
176/176 [==============================] - 58s 330ms/step - loss: 0.9740 - accuracy: 0.6615 - top-5-accuracy: 0.9666 - val_loss: 0.8175 - val_accuracy: 0.7096 - val_top-5-accuracy: 0.9806
313/313 [==============================] - 9s 27ms/step - loss: 0.8514 - accuracy: 0.7032 - top-5-accuracy: 0.9773
Test accuracy: 70.32%
Test top 5 accuracy: 97.73%
In [15]:
从结果看可以来看,测试精度已达70%,这是一个较大提升!

9、查看运行结果

运行结果

使用数据增强方法提升模型性能


使用数据增强来提升模型的性能

1、导入模型

2、定义加载函数

3、定义批量加载函数

4、加载数据

把数据转换为dataset格式

5、定义数据增强方法

6、构建模型

生成实例

查看模型详细结构

7、编译模型

8、训练模型

为便于比较,这里先不使用数据增强方法

9、查看运行结果

运行结果

10、使用数据增强方法

11、查看使用数据增强的运行结果

运行结果

12、结果分析

从不使用数据增强与使用数据增强方法的结果可以看出,使用数据增强方法后,模型性能有提升(未使用数据增强的验证精度为71%,使用数据增强方法后,验证精度提升到74%),而且模型的泛化能力也有提高(使用数据增强方法后,训练与验证精度曲线靠得较近)。

TensorFlow2提升模型性能的几种有效方法


这里介绍几种TensorFlow2提升模型性能的几种有效方法,如数据增强、使用经典网络、使用迁移学习、使用新架构等。

一、数据增强

数据增强是提升模型性能的常用方法之一,尤其当训练数据集较小时,通过数据增强方法,效果更加明确。通过数据增强不但可以增加数据量、丰富数据的多样性,从而有效提升模型的泛化能力。
TensorFlow2提供了多种数据增强方法,常用的几种方法为:
 有监督的数据增强:
1、使用tf.image的预处理
该方法一般基于dataset,然后把数据增强方法嵌入到map中
2、使用tf.keras.preprocessing.image.ImageDataGenerator
利用实时数据增强技术生成批量的张量图像数据
使用tf.keras.preprocessing.image.ImageDataGenerator,获取数据源的方法主要有:
(1).flow(x, y)
(2).flow_from_directory(directory)
3、使用tf.keras.layers.experimental.preprocessing
更多信息可参考官网:https://keras.io/guides/preprocessing_layers/
 无监督的数据增强
通过模型学习数据的分布,随机生成与训练数据集分布一致的图片,代表方法,GAN。
GAN模型包含两个网络,一个是生成网络(G),一个是判别网络(D),基本原理如下:
(1)G是一个生成图片的网络,它接收随机的噪声z,通过噪声生成图片,记做G(z)。
(2)D是一个判别网络,判别一张图片是不是“真实的”,即是真实的图片,还是由G生成的图片。其架构图如下:

下载所有实例使用数据(提取码为:fg29)
具体实例

二、使用现代经典模型

现代经典模型主要有: VGG、GoogLeNet、Inception、Xception、ResNet、MobileNet、DenseNet、NASNet等,各种网咯结构可参考:
https://blog.csdn.net/Forrest97/article/details/105630719

具体实例(待续)

三、利用迁移方法

Tensorflow.keras.application下载已经训练好的模型,包括如下预训练模型:
VGG、GoogLeNet、Inception、Xception、ResNet、MobileNet、DenseNet、NASNet等

具体实例(待续)

四、使用新架构如Transformer等

Transformer)模型在NLP领域取得了SOTA成绩,目前人们正把Transformer引用到CV领域,在图像识别、图像分类等领域取得不俗的表现。在目标检测(如DETR)、图像分类(如ViT)、图像分割(如SETR)都取得不错的效果。这里我们重点介绍ViT(Vision Transformer)。如何把Transformer引入CV领域?需要对CV中的图像做哪些处理?
NLP处理的语言数据是序列化的,而CV中处理的图像数据是三维的(height、width和channels)。所以需要通过某种方法将图像这种三维数据转化为序列化的数据。
Vision Transformer将CV和NLP领域知识结合起来,对原始图片进行分块,然后展平成序列,输入进原始Transformer模型的编码器Encoder部分,最后接入一个全连接层对图片进行分类。具体步骤为:
(1)原始图片(H,W,C)进行分块(patches)
进行一个类似卷积操作,把原始图片进行分块,分块数=H*W/P*P(P为块的大小)。
(2)展平每块(Flatten the patches)
把每块展平为一维向量,大小为:P*P*C(对应实例中的patch_dims)
(3)把展平后的块映射为更低维的向量
通过一个全连接层,把展平后块映射为一个更低维的向量(对应实例中的patch embedding),其大小为D(对应实例中的projection_dim),这个维度在各层保存不变,主要为便于使用残差连接。
(4)在patch embedding基础上添加一个类标签
类似BERT的[class] token,在patch embedding的序列之前添加一个可学习的embedding向量xclass
(5)加上位置嵌入(Add positional embeddings)
低维的向量+位置嵌入,
(6)把(5)的结果作为标准transformer encoder的输入
(7)在一个大数据集上训练模型
(8)在下游数据集中,进行微调。
ViT架构图如下:


具体实例

具体实例

五、练习

1、利用ResNet经典模型提升性能
2、使用keras的数据增强方法提升性能
3、viT中Transformer的输入数据的形状(shape)与哪些因素有关?包括哪些数据?如何生成Transformer的输入数据?

TensorFlow2构建模型-境界4

1.导入CIFAR-10数据集

CIFAR-10是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集。一共包含 10 个类别的 RGB 彩色图片:飞机( a叩lane )、汽车( automobile )、鸟类( bird )、猫( cat )、鹿( deer )、狗( dog )、蛙类( frog )、马( horse )、船( ship )和卡车( truck )。图片的尺寸为 32×32,3个通道 ,数据集中一共有 50000 张训练圄片和 10000 张测试图片。 CIFAR-10数据集有3个版本,这里使用python版本。

1.1 导入需要的库

1.2 定义批量导入数据的函数

1.3 定义加载数据函数

1.4 加载数据

运行结果
loading data\cifar-10-batches-py\data_batch_1
loading data\cifar-10-batches-py\data_batch_2
loading data\cifar-10-batches-py\data_batch_3
loading data\cifar-10-batches-py\data_batch_4
loading data\cifar-10-batches-py\data_batch_5
finished loadding CIFAR-10 data

1.5 可视化加载数据

运行结果

2 .数据预处理并设置超参数

3.使用tf.data构建数据管道

4.构建模型

使用子类方法自定义模型结构的一般步骤:

5.训练模型

(1)实例化模型
model = MyCNN()
(2)查看模型的详细结构
model.model01().summary()
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 32, 32, 3)] 0
_________________________________________________________________
conv2d (Conv2D) (None, 32, 32, 32) 896
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 16, 16, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 16, 16, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 8, 8, 64) 0
_________________________________________________________________
reshape (Reshape) (None, 4096) 0
_________________________________________________________________
dense (Dense) (None, 256) 1048832
_________________________________________________________________
dense_1 (Dense) (None, 10) 2570
_________________________________________________________________
tf_op_layer_Softmax (TensorF [(None, 10)] 0
=================================================================
Total params: 1,070,794
Trainable params: 1,070,794
Non-trainable params: 0
(3)编译及训练模型
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
epochs = 10
batch_size = 64
learning_rate = 0.0002

train_history = model.fit(x_train, y_train,
validation_split=0.2,
epochs=epochs,
#steps_per_epoch=100,
batch_size=batch_size,
verbose=1)
运行结果
Train on 40000 samples, validate on 10000 samples
Epoch 1/10
40000/40000 [==============================] - 5s 113us/sample - loss: 1.4482 - accuracy: 0.4811 - val_loss: 1.1808 - val_accuracy: 0.5889
Epoch 2/10
40000/40000 [==============================] - 2s 53us/sample - loss: 1.0530 - accuracy: 0.6291 - val_loss: 1.0052 - val_accuracy: 0.6466
Epoch 3/10
40000/40000 [==============================] - 2s 51us/sample - loss: 0.9031 - accuracy: 0.6814 - val_loss: 0.9358 - val_accuracy: 0.6751
Epoch 4/10
40000/40000 [==============================] - 2s 50us/sample - loss: 0.7926 - accuracy: 0.7207 - val_loss: 0.8919 - val_accuracy: 0.6909
Epoch 5/10
40000/40000 [==============================] - 2s 53us/sample - loss: 0.6966 - accuracy: 0.7573 - val_loss: 0.8932 - val_accuracy: 0.6904
Epoch 6/10
40000/40000 [==============================] - 2s 50us/sample - loss: 0.6029 - accuracy: 0.7889 - val_loss: 0.8699 - val_accuracy: 0.7036
Epoch 7/10
40000/40000 [==============================] - 2s 51us/sample - loss: 0.5131 - accuracy: 0.8210 - val_loss: 0.8832 - val_accuracy: 0.7092
Epoch 8/10
40000/40000 [==============================] - 2s 52us/sample - loss: 0.4263 - accuracy: 0.8533 - val_loss: 0.9517 - val_accuracy: 0.7028
Epoch 9/10
40000/40000 [==============================] - 2s 53us/sample - loss: 0.3407 - accuracy: 0.8815 - val_loss: 0.9970 - val_accuracy: 0.7065
Epoch 10/10
40000/40000 [==============================] - 2s 52us/sample - loss: 0.2693 - accuracy: 0.9078 - val_loss: 1.0540 - val_accuracy: 0.7090

6.可视化运行结果

7.测试模型

运行结果
10000/10000 - 1s - loss: 1.1505 - accuracy: 0.6936
test_loss: 1.1505295364379884
test_acc: 0.6936
metrics_names: ['loss', 'accuracy']

8.保存恢复整个模型

(1)保存模型参数及网络结构等
可以使用两种格式将整个模型保存到磁盘:TensorFlow SavedModel 格式和较早的 Keras H5 格式。 tensorflow官方推荐使用 SavedModel 格式。它是使用 model.save() 时的默认格式,这种保存方式适合Sequential, Functional Model, or Model subclass。

(2)恢复模型

(3)检查恢复模型的结构

运行结果
Model: "my_cnn_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_2 (Conv2D) multiple 896
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 multiple 0
_________________________________________________________________
conv2d_3 (Conv2D) multiple 18496
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 multiple 0
_________________________________________________________________
reshape_1 (Reshape) multiple 0
_________________________________________________________________
dense_2 (Dense) multiple 1048832
_________________________________________________________________
dense_3 (Dense) multiple 2570
=================================================================
Total params: 1,070,794
Trainable params: 1,070,794
Non-trainable params: 0
_______________________________
与原模型结构完全一致!

(4)基于恢复模型进行测试

运行结果
10000/10000 - 1s - loss: 1.1488 - accuracy: 0.6936
test_loss: 1.1488204129219055
test_acc: 0.6936
metrics_names: ['loss', 'accuracy']
模型精度与原模型完全一致!

TensorFlow2 构建模型-境界3


有三种计算图的构建方式:静态计算图,动态计算图,以及Autograph。 TensorFlow 2.0主要使用的是动态计算图和Autograph。 动态计算图易于调试,编码效率较高,但执行效率偏低。 静态计算图执行效率很高,但较难调试。 而Autograph机制可以将动态图转换成静态计算图,兼收执行效率和编码效率之利。 当然Autograph机制能够转换的代码并不是没有任何约束的,有一些编码规范需要遵循,否则可能会转换失败或者不符合预期。 我们将着重介绍Autograph的编码规范和Autograph转换成静态图的原理。
Autograph编码规范:
• 1.被@tf.function修饰的函数应尽可能使用TensorFlow中的函数而不是Python中的其他函数。例如使用tf.print而不是print,使用tf.range而不是range,使用tf.constant(True)而不是True.
• 2.避免在@tf.function修饰的函数内部定义tf.Variable.
• 3.被@tf.function修饰的函数不可修改该函数外部的Python列表或字典等数据结构变量。

1.导入CIFAR-10数据集

CIFAR-10是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集。一共包含 10 个类别的 RGB 彩色图片:飞机( a叩lane )、汽车( automobile )、鸟类( bird )、猫( cat )、鹿( deer )、狗( dog )、蛙类( frog )、马( horse )、船( ship )和卡车( truck )。图片的尺寸为 32×32,3个通道 ,数据集中一共有 50000 张训练圄片和 10000 张测试图片。 CIFAR-10数据集有3个版本,这里使用python版本。

1.1 导入需要的库

1.2 定义批量导入数据的函数

1.3 定义加载数据函数

1.4 加载数据

运行结果
loading data\cifar-10-batches-py\data_batch_1
loading data\cifar-10-batches-py\data_batch_2
loading data\cifar-10-batches-py\data_batch_3
loading data\cifar-10-batches-py\data_batch_4
loading data\cifar-10-batches-py\data_batch_5
finished loadding CIFAR-10 data

1.5 可视化加载数据

运行结果

2 .数据预处理并设置超参数

3.使用tf,data构建数据管道

4.定义卷积层及池化层

5.构建模型

6.定义训练模型函数

自定训练过程:
(1)打开一个遍历各epoch的for循环
(2)对于每个epoch,打开一个分批遍历数据集的 for 循环
(3)对于每个批次,打开一个 GradientTape() 作用域
(4)在此作用域内,调用模型(前向传递)并计算损失
(5)在作用域之外,检索模型权重相对于损失的梯度
(6)根据梯度使用优化器来更新模型的权重
(7)评估模型指标

train_model(model,train_data,training_steps,display_step)
运行结果
step =1000,loss = 1.3011,accuracy =0.5781 ,times=0.0000
step =2000,loss = 1.2720,accuracy =0.6094 ,times=0.0000
step =3000,loss = 1.2153,accuracy =0.5469 ,times=0.0000
step =4000,loss = 0.8636,accuracy =0.7500 ,times=0.0000
step =5000,loss = 0.7936,accuracy =0.7500 ,times=0.0000
step =6000,loss = 0.9527,accuracy =0.6875 ,times=0.0156
step =7000,loss = 0.9352,accuracy =0.7344 ,times=0.0000
step =8000,loss = 0.6892,accuracy =0.7969 ,times=0.0000
step =9000,loss = 0.7949,accuracy =0.7031 ,times=0.0000
step =10000,loss = 0.4768,accuracy =0.8438 ,times=0.0000
step =11000,loss = 0.7983,accuracy =0.7188 ,times=0.0000
step =12000,loss = 0.5601,accuracy =0.8281 ,times=0.0000
step =13000,loss = 0.7934,accuracy =0.7031 ,times=0.0000
step =14000,loss = 0.6450,accuracy =0.8438 ,times=0.0000
step =15000,loss = 0.5681,accuracy =0.7656 ,times=0.0000
step =16000,loss = 0.5413,accuracy =0.8125 ,times=0.0000
step =17000,loss = 0.3914,accuracy =0.8438 ,times=0.0000
step =18000,loss = 0.3687,accuracy =0.8906 ,times=0.0000
step =19000,loss = 0.4534,accuracy =0.8750 ,times=0.0000
step =20000,loss = 0.3855,accuracy =0.8438 ,times=0.0000

从运行结果来看,运行时间快了很多!

7.可视化运行结果

8.测试模型

运行结果
Test accuracy:0.720653
性能也有一定提升!

Tensorflow2构建模型-境界2

1.导入CIFAR-10数据集

CIFAR-10是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集。一共包含 10 个类别的 RGB 彩色图片:飞机( a叩lane )、汽车( automobile )、鸟类( bird )、猫( cat )、鹿( deer )、狗( dog )、蛙类( frog )、马( horse )、船( ship )和卡车( truck )。图片的尺寸为 32×32,3个通道 ,数据集中一共有 50000 张训练圄片和 10000 张测试图片。 CIFAR-10数据集有3个版本,这里使用python版本。

1.1 导入需要的库

1.2 定义批量导入数据的函数

1.3 定义加载数据函数

1.4 加载数据

运行结果
loading data\cifar-10-batches-py\data_batch_1
loading data\cifar-10-batches-py\data_batch_2
loading data\cifar-10-batches-py\data_batch_3
loading data\cifar-10-batches-py\data_batch_4
loading data\cifar-10-batches-py\data_batch_5
finished loadding CIFAR-10 data

1.5 可视化加载数据

运行结果

2 .数据预处理并设置超参数

3.使用tf.data构建数据管道

4.定义卷积层及池化层

5.构建模型

6.定义训练模型函数

自定义训练过程:
(1)打开一个遍历各epoch的for循环
(2)对于每个epoch,打开一个分批遍历数据集的 for 循环
(3)对于每个批次,打开一个 GradientTape() 作用域
(4)在此作用域内,调用模型(前向传递)并计算损失
(5)在作用域之外,检索模型权重相对于损失的梯度
(6)根据梯度使用优化器来更新模型的权重
(7)评估模型指标

train_model(model,train_data,training_steps,display_step)
运行结果
step =1000,loss = 1.2807,accuracy =0.5781 ,times=0.0080
step =2000,loss = 1.1832,accuracy =0.6562 ,times=0.0080
step =3000,loss = 0.9727,accuracy =0.6562 ,times=0.0080
step =4000,loss = 1.0398,accuracy =0.6406 ,times=0.0050
step =5000,loss = 0.8615,accuracy =0.6406 ,times=0.0156
step =6000,loss = 0.7207,accuracy =0.7188 ,times=0.0000
step =7000,loss = 1.0945,accuracy =0.5938 ,times=0.0090
step =8000,loss = 0.7337,accuracy =0.7656 ,times=0.0080
step =9000,loss = 0.5792,accuracy =0.7812 ,times=0.0080
step =10000,loss = 0.7154,accuracy =0.7500 ,times=0.0080
step =11000,loss = 0.6398,accuracy =0.8125 ,times=0.0156
step =12000,loss = 0.6413,accuracy =0.7500 ,times=0.0080
step =13000,loss = 0.5555,accuracy =0.7812 ,times=0.0156
step =14000,loss = 0.6729,accuracy =0.8281 ,times=0.0156
step =15000,loss = 0.5163,accuracy =0.7500 ,times=0.0156
step =16000,loss = 0.5521,accuracy =0.7969 ,times=0.0000
step =17000,loss = 0.4475,accuracy =0.8594 ,times=0.0156
step =18000,loss = 0.3158,accuracy =0.8594 ,times=0.0080
step =19000,loss = 0.3829,accuracy =0.9062 ,times=0.0090
step =20000,loss = 0.2731,accuracy =0.9062 ,times=0.0080

7.可视化运行结果

8.测试型

运行结果
Test accuracy:0.712640

TensorFlow2构建模型-境界1

1.导入CIFAR-10数据集

CIFAR-10是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集。一共包含 10 个类别的 RGB 彩色图片:飞机( a叩lane )、汽车( automobile )、鸟类( bird )、猫( cat )、鹿( deer )、狗( dog )、蛙类( frog )、马( horse )、船( ship )和卡车( truck )。图片的尺寸为 32×32,3个通道 ,数据集中一共有 50000 张训练圄片和 10000 张测试图片。 CIFAR-10数据集有3个版本,这里使用python版本。

1.1 导入需要的库

1.2 定义批量导入数据的函数

1.3 定义加载数据函数

1.4 加载数据

运行结果
loading data\cifar-10-batches-py\data_batch_1
loading data\cifar-10-batches-py\data_batch_2
loading data\cifar-10-batches-py\data_batch_3
loading data\cifar-10-batches-py\data_batch_4
loading data\cifar-10-batches-py\data_batch_5
finished loadding CIFAR-10 data

1.5 可视化加载数据

运行结果

2 .数据预处理并设置超参数

3.使用tf,data构建数据管道

4.定义卷积层及池化层

5.定义并初始化权重参数

6.构建模型

7.定义损失函数、评估函数

8.定义梯度计算函数

自定义梯度计算过程:
(1)打开一个 GradientTape() 作用域
(2)在此作用域内,调用模型(正向传播)并计算损失
(3)在作用域之外,检索模型权重相对于损失的梯度
(4)根据梯度使用优化器来更新模型的权重
(5)利用优化器进行反向传播(更新梯度)

9.训练模型

10.可视化运行结果

运行结果

11.测试模型

运行结果
Test accuracy:0.704327

TensorFlow2构建模型的五个境界

一、纯手工

定制化程度高,非常灵活,如自定义层、损失函数、优化器、性能评估、训练模型方法等,但编程难度较高。
下载所有实例使用数据(提取码为:fg29)

具体实例

二、继承tf.Module

定制化程度高,如自定义层、损失函数、优化器、性能评估、训练模型方法等,且可以使用保存或恢复模型。
具体实例

三、继承tf.Module且使用AutoGraph

定制化程度高,如自定层、损失函数、优化器、性能评估、训练模型方法等,且可以使用保存或恢复模型。通过使用Autograph可达到静态图的性能,极大提升训练模型效率。不过使用Autograph时要注意对应的编码规范,如被@tf,function装饰的函数尽可能tensorflow函数,如tf.print,tf.range等(控制语句无此限制),避免在被@tf,function装饰的函数内部定义tf.Variabe等。
具体实例

四、网络层和模型使用子类方法构建

用子类方法构建网络层、网络模型是tensorflow2才有的,这种风格类似于PyTorch构建方法。TensorFlow1构建网络一般使用Sequential按层顺序构建模型,使用函数式API构建任意结构模型。当然,这两种方法在TensorFlow2也是常用方法。构建网络层时继承
tf.keras.layers.Layer,构建网络模型继承tf.keras.Model, 然后使用compile编辑模型,用fit训练模型。这样构建的网络既有一定的灵活性,又不失简洁性。
具体实例

五、使用tf,keras的Sequential模型按层顺序构建模型

最简洁,构建模型很简单,可是直接使用内置的层、损失函数、优化器、评估指标等,训练也可直接使用函数fit即可。Keras 提供了称为tf.keras.Model 的全功能模型类。它继承自 tf.keras.layers.Layer,使用SaveModel保存模型,可以非常方便移植到其他非Python环境(具体环境可参考下图)。构建这个模型相对较简单,有兴趣的朋友作为练习。