Faster R-CNN Keras版源码史上最详细解读系列之RPN训练数据处理一

本文主要是介绍Faster R-CNN Keras版源码史上最详细解读系列之RPN训练数据处理一,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Faster R-CNN Keras版源码史上最详细解读系列之RPN训练数据处理一

  • 训练数据处理
    • 训练数据处理

训练数据处理

前面我们将了RPN模型,同时包含特征提取的,输入是图片,输出是分类和回归,我们现在有了模型的预测输出,因为做的是有监督学习,所以我们还需要真实值输出,也就是标注框相关的分类和回归部分,以便于去计算损失。还是train_frcnn.py

            # 图片,rpn的分类和回归,增强后的图片数据X, Y, img_data = next(data_gen_train)# 返回三个损失 总得loss rpn_loss_cls  rpn_loss_regrloss_rpn = model_rpn.train_on_batch(X, Y)

上面的Y就是真实的分类和回归,因为要统一成RPN模型的输出格式才可以进行损失计算,所以我们需要把他们预处理一下,我们通过data_gen_train迭代器来获取预处理后的数据,每次就一张图片。

# 获取真实的标注训练数据
data_gen_train = data_generators.get_anchor_gt(train_imgs, classes_count, C, nn.get_img_output_length,K.image_dim_ordering(), mode='train')
# 获取真实的标注测试数据
data_gen_val = data_generators.get_anchor_gt(val_imgs, classes_count, C, nn.get_img_output_length,K.image_dim_ordering(), mode='val')

可以看到迭代器其实是这个函数data_generators.get_anchor_gt,就是获取真实框的预处理信息,下面我们来看看这个方法。

训练数据处理

来看看这个文件data_generators.pySampleSelector

# 样本选择器
class SampleSelector:def __init__(self, class_count):# ignore classes that have zero samples# 获取所有类别名的序列,除去个数是0的,针对bgself.classes = [b for b in class_count.keys() if class_count[b] > 0]# 把传入的序列无限重复下去 比如序列 ABC ,重复就是 ABCABCBC... 这样是为了实现样本均衡,所有类别比例都均衡,按ABCABC这样的序列下去self.class_cycle = itertools.cycle(self.classes)# 依次迭代获取下一个类别self.curr_class = next(self.class_cycle)# 判断图片中是否含有采样器的当前类,为了实现样本均衡,没有就不处理了,有才处理def skip_sample_for_balanced_class(self, img_data):class_in_img = Falsefor bbox in img_data['bboxes']:cls_name = bbox['class']#只要图片中包含类别就够了,几个没关系if cls_name == self.curr_class:class_in_img = Trueself.curr_class = next(self.class_cycle)break# 包含了这个类别就可以处理,不包含就这个图片就没用了if class_in_img:return Falseelse:return True

这个样本选择器,主要是为了样本均衡的时候用的,他的目的就是为了保持样本均衡,要一个迭代器不停的迭代出样本的类别的序列,比如ABCABC…这样循环下去,以保证样本的比例是均衡的。skip_sample_for_balanced_class这个方法就是在筛选图片是否符合样本均衡的要求,具体在get_anchor_gt这个方法里会看到。如果我现在需要的是类别A的框,你图片里没有,那对不起,你这张图片我不要了,继续检查下一张,如果有,我才去处理。然后我继续迭代下一个需要的是类别B,继续检查图片。这样就强制实现了样本均衡,但是会丢掉很多不符合他类别序列顺序的样本了,其实不太合理,比如如果我的样本序列是AABBCC明显也是符合样本均衡的,但是强制那么多,就把一般的样本丢了,这样就浪费了,所以貌似这个样本均衡的机制也没启动,可以看到配置里是self.balanced_classes = False

好了,其实这个选择器没啥用,因为样本均衡没启动,但是我也讲一下这个干嘛用的,便于理解。接下来要讲get_anchor_gt这个方法了,怎么预处理标注框:

'''
获取真实的标注框信息
'''
def get_anchor_gt(all_img_data, class_count, C, img_length_calc_function, backend, mode='train'):''':param all_img_data: 所有的图片数据:param class_count: 类别数量的字典:param C: 配置:param img_length_calc_function: 特征图的尺寸:param backend: 后台是tf还是th:param mode: 是否训练:return:'''# The following line is not useful with Python 3.5, it is kept for the legacy# all_img_data = sorted(all_img_data)sample_selector = SampleSelector(class_count)while True:#训练的时候混洗一下if mode == 'train':np.random.shuffle(all_img_data)# 迭代所有的图片信息for img_data in all_img_data:try:# 是否要实现样本均衡,就是按照sample_selector迭代的序列进行样本的提取,否则就不要这个样本,# 比如样本迭代是A B C A B C... 如果图片中有这个类别的框,就处理,如果没有就不处理这个图片,直接看下一个图片了if C.balanced_classes and sample_selector.skip_sample_for_balanced_class(img_data):continue# read in image, and optionally add augmentationif mode == 'train':img_data_aug, x_img = data_augment.augment(img_data, C, augment=True)else:img_data_aug, x_img = data_augment.augment(img_data, C, augment=False)# 原始图像的宽高(width, height) = (img_data_aug['width'], img_data_aug['height'])(rows, cols, _) = x_img.shapeassert cols == widthassert rows == height# get image dimensions for resizing# 获取原图按照规定尺寸缩放后的宽高 默认是以最大600的长度,可以设置(resized_width, resized_height) = get_new_img_size(width, height, C.im_size)# resize the image so that smalles side is length = 600px# 将原图缩放到规定尺寸x_img = cv2.resize(x_img, (resized_width, resized_height), interpolation=cv2.INTER_CUBIC)try:# 计算RPN分类和回归y_rpn_cls, y_rpn_regr = calc_rpn(C, img_data_aug, width, height, resized_width, resized_height, img_length_calc_function)except:continue# Zero-center by mean pixel, and preprocess image# 更改维度顺序,转成RGB,cv默认是BGRx_img = x_img[:,:, (2, 1, 0)]  # BGR -> RGBx_img = x_img.astype(np.float32)# 做自定义的标准化x_img[:, :, 0] -= C.img_channel_mean[0]x_img[:, :, 1] -= C.img_channel_mean[1]x_img[:, :, 2] -= C.img_channel_mean[2]x_img /= C.img_scaling_factor# 转置 通道放最前面了x_img = np.transpose(x_img, (2, 0, 1)) # (3,600,1000)x_img = np.expand_dims(x_img, axis=0) # (1,3,600,1000)# 将回归误差后半部分误差值进行缩放y_rpn_regr[:, y_rpn_regr.shape[1]//2:, :, :] *= C.std_scaling# tf的话通道放最后if backend == 'tf':x_img = np.transpose(x_img, (0, 2, 3, 1))y_rpn_cls = np.transpose(y_rpn_cls, (0, 2, 3, 1))y_rpn_regr = np.transpose(y_rpn_regr, (0, 2, 3, 1))yield np.copy(x_img), [np.copy(y_rpn_cls), np.copy(y_rpn_regr)], img_data_augexcept Exception as e:print(e)continue

从头开始看,初始化样本选择器,其实没啥用,如果是训练就混洗图片数据,看一下图片数据的格式:
在这里插入图片描述
然后遍历所有的图片数据,如果开启了样本均衡,就要判断样本选择器是否选这个样本了,不选就直接遍历下一个样本了,这里没开启,所以也不用管,就处理样本就好了。如果训练集的话可能要进行数据增强,也就是data_augment.py里的augment方法,我们先来看看这个方法吧,不然上面的代码不好理解:

# 图片增强 翻转,旋转
def augment(img_data, config, augment=True):assert 'filepath' in img_dataassert 'bboxes' in img_dataassert 'width' in img_dataassert 'height' in img_data# 深拷贝,不然会修改原图img_data_aug = copy.deepcopy(img_data)# 图片信息 cv读出来的是BGRimg = cv2.imread(img_data_aug['filepath'])# 如果要进行数据增强的话,其实也就是旋转 翻转 然后更新一些信息if augment:# 高和宽rows, cols = img.shape[:2]# 水平翻转 50%概率if config.use_horizontal_flips and np.random.randint(0, 2) == 0:img = cv2.flip(img, 1)# 修正xfor bbox in img_data_aug['bboxes']:x1 = bbox['x1']x2 = bbox['x2']bbox['x2'] = cols - x1bbox['x1'] = cols - x2# 竖直翻转 50%概率if config.use_vertical_flips and np.random.randint(0, 2) == 0:img = cv2.flip(img, 0)# 修正yfor bbox in img_data_aug['bboxes']:y1 = bbox['y1']y2 = bbox['y2']bbox['y2'] = rows - y1bbox['y1'] = rows - y2# 旋转 顺时针,转置可以看成图片主对角线对称过来的样子if config.rot_90:angle = np.random.choice([0,90,180,270],1)[0]if angle == 270:img = np.transpose(img, (1,0,2))# 垂直翻转img = cv2.flip(img, 0)elif angle == 180:# 水平垂直翻转img = cv2.flip(img, -1)elif angle == 90:img = np.transpose(img, (1,0,2))# 水平翻转img = cv2.flip(img, 1)elif angle == 0:pass# 旋转后坐标修正for bbox in img_data_aug['bboxes']:x1 = bbox['x1']x2 = bbox['x2']y1 = bbox['y1']y2 = bbox['y2']if angle == 270:bbox['x1'] = y1bbox['x2'] = y2bbox['y1'] = cols - x2bbox['y2'] = cols - x1elif angle == 180:bbox['x2'] = cols - x1bbox['x1'] = cols - x2bbox['y2'] = rows - y1bbox['y1'] = rows - y2elif angle == 90:bbox['x1'] = rows - y2bbox['x2'] = rows - y1bbox['y1'] = x1bbox['y2'] = x2        elif angle == 0:pass# 旋转过后可能宽高有变化img_data_aug['width'] = img.shape[1]img_data_aug['height'] = img.shape[0]return img_data_aug, img

上面的代码也比较好理解,数据增强后,坐标肯定就变啦,具体可以自己画个图算算,光脑子想想不清楚,画个图就知道坐标怎么回事了,还有就是图片转置其实就是沿着颜色矩阵的主对角线进行翻转,然后配合图片本身的水平和竖直翻转就可以等价于角度的旋转,只是取了90,180,270这些比较好算的角度,否则就可能要进行复杂了。最后结果返回增强后的图片信息,和图片颜色信息。

然后我们继续看get_anchor_gt,后面获取了原始图片的高和宽,进行了缩放,把短边强制缩放成600,长边跟着比例缩放,可以看这个函数get_new_img_size比较简单不多说了,看代码就好了:

# 获得新的图片尺寸,短边长设置为600,等比例缩放比如500x300 变为 1000x600
def get_new_img_size(width, height, img_min_side=600):if width <= height:f = float(img_min_side) / widthresized_height = int(f * height)resized_width = img_min_sideelse:f = float(img_min_side) / heightresized_width = int(f * width)resized_height = img_min_sidereturn resized_width, resized_height

然后就用cv把图片给缩放了,之后我们要对图片真实数据进行RPN网络的分类和回归梯度的计算,主要是为了就是让标注数据处理成RPN输出的格式,好计算误差,用的是这个函数calc_rpn,因为这个方法比较复杂,所以我打算用新的篇章去讲。
在这里插入图片描述

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵,部分图片来自网络,侵删。

这篇关于Faster R-CNN Keras版源码史上最详细解读系列之RPN训练数据处理一的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/657218

相关文章

使用Docker构建Python Flask程序的详细教程

《使用Docker构建PythonFlask程序的详细教程》在当今的软件开发领域,容器化技术正变得越来越流行,而Docker无疑是其中的佼佼者,本文我们就来聊聊如何使用Docker构建一个简单的Py... 目录引言一、准备工作二、创建 Flask 应用程序三、创建 dockerfile四、构建 Docker

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

SpringBoot整合liteflow的详细过程

《SpringBoot整合liteflow的详细过程》:本文主要介绍SpringBoot整合liteflow的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋...  liteflow 是什么? 能做什么?总之一句话:能帮你规范写代码逻辑 ,编排并解耦业务逻辑,代码

MySQL之InnoDB存储页的独立表空间解读

《MySQL之InnoDB存储页的独立表空间解读》:本文主要介绍MySQL之InnoDB存储页的独立表空间,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、独立表空间【1】表空间大小【2】区【3】组【4】段【5】区的类型【6】XDES Entry区结构【

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

MySQL主从复制与读写分离的用法解读

《MySQL主从复制与读写分离的用法解读》:本文主要介绍MySQL主从复制与读写分离的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、主从复制mysql主从复制原理实验案例二、读写分离实验案例安装并配置mycat 软件设置mycat读写分离验证mycat读

HTML img标签和超链接标签详细介绍

《HTMLimg标签和超链接标签详细介绍》:本文主要介绍了HTML中img标签的使用,包括src属性(指定图片路径)、相对/绝对路径区别、alt替代文本、title提示、宽高控制及边框设置等,详细内容请阅读本文,希望能对你有所帮助... 目录img 标签src 属性alt 属性title 属性width/h

CSS3打造的现代交互式登录界面详细实现过程

《CSS3打造的现代交互式登录界面详细实现过程》本文介绍CSS3和jQuery在登录界面设计中的应用,涵盖动画、选择器、自定义字体及盒模型技术,提升界面美观与交互性,同时优化性能和可访问性,感兴趣的朋... 目录1. css3用户登录界面设计概述1.1 用户界面设计的重要性1.2 CSS3的新特性与优势1.