写给程序员的机器学习入门 (九) - 对象识别 RCNN 与 Fast-RCNN
因为这几个月饭店生意恢复,加上研究 Faster-RCNN 用掉了很多时间,就没有更新博客了。这篇开始会介绍对象识别的模型与实现方法,首先会介绍最简单的 RCNN 与 Fast-RCNN 模型,下一篇会介绍 Faster-RCNN 模型,再下一篇会介绍 YOLO 模型。
图片分类与对象识别
在前面的文章中我们看到了如何使用 CNN 模型识别图片里面的物体是什么类型,或者识别图片中固定的文字 (即验证码),因为模型会把整个图片当作输入并输出固定的结果,所以图片中只能有一个主要的物体或者固定数量的文字。
如果图片包含了多个物体,我们想识别有哪些物体,各个物体在什么位置,那么只用 CNN 模型是无法实现的。我们需要可以找出图片哪些区域包含物体并且判断每个区域包含什么物体的模型,这样的模型称为对象识别模型 (Object Detection Model),最早期的对象识别模型是 RCNN 模型,后来又发展出 Fast-RCNN (SPPnet),Faster-RCNN ,和 YOLO 等模型。因为对象识别需要处理的数据量多,速度会比较慢 (例如 RCNN 检测单张图片包含的物体可能需要几十秒),而对象识别通常又要求实时性 (例如来源是摄像头提供的视频),所以如何提升对象识别的速度是一个主要的命题,后面发展出的 Faster-RCNN 与 YOLO 都可以在一秒钟检测几十张图片。

对象识别的应用范围比较广,例如人脸识别,车牌识别,自动驾驶等等都用到了对象识别的技术。对象识别是当今机器学习领域的一个前沿,2017 年研发出来的 Mask-RCNN 模型还可以检测对象的轮廓。

因为看上去越神奇的东西实现起来越难,对象识别模型相对于之前介绍的模型难度会高很多,请做好心理准备。
对象识别模型需要的训练数据
在介绍具体的模型之前,我们首先看看对象识别模型需要什么样的训练数据:

对象识别模型需要给每个图片标记有哪些区域,与每个区域对应的标签,也就是训练数据需要是列表形式的。区域的格式通常有两种,(x, y, w, h) => 左上角的坐标与长宽,与 (x1, y1, x2, y2) => 左上角与右下角的坐标,这两种格式可以互相转换,处理的时候只需要注意是哪种格式即可。标签除了需要识别的各个分类之外,还需要有一个特殊的非对象 (背景) 标签,表示这个区域不包含任何可以识别的对象,因为非对象区域通常可以自动生成,所以训练数据不需要包含非对象区域与标签。
RCNN
RCNN (Region Based Convolutional Neural Network) 是最早期的对象识别模型,实现比较简单,可以分为以下步骤:
- 用某种算法在图片中选取 2000 个可能出现对象的区域
- 截取这 2000 个区域到 2000 个子图片,然后缩放它们到一个固定的大小
- 用普通的 CNN 模型分别识别这 2000 个子图片,得出它们的分类
- 排除标记为 "非对象" 分类的区域
- 把剩余的区域作为输出结果

你可能已经从步骤里看出,RCNN 有几个大问题:
- 结果的精度很大程度取决于选取区域使用的算法
- 选取区域使用的算法是固定的,不参与学习,如果算法没有选出某个包含对象区域那么怎么学习都无法识别这个区域出来
- 慢,贼慢,识别 1 张图片实际等于识别 2000 张图片
后面介绍模型结果会解决这些问题,但首先我们需要理解最简单的 RCNN 模型,接下来我们细看一下 RCNN 实现中几个重要的部分吧。
选取可能出现对象的区域
选取可能出现对象的区域的算法有很多种,例如滑动窗口法 (Sliding Window) 和选择性搜索法 (Selective Search)。滑动窗口法非常简单,决定一个固定大小的区域,然后按一定距离滑动得出下一个区域即可。滑动窗口法实现简单但选取出来的区域数量非常庞大并且精度很低,所以通常不会使用这种方法,除非物体大小固定并且出现的位置有一定规律。

选择性搜索法则比较高级,以下是简单的说明,摘自 opencv 的文章:

如果你觉得难以理解可以跳过,因为接下来我们会直接使用 opencv 类库中提供的选择搜索函数。而且选择搜索法精度也不高,后面介绍的模型将会使用更好的方法。
# 使用 opencv 类库中提供的选择搜索函数的代码例子
import cv2
img = cv2.imread("图片路径")
s = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
s.setBaseImage(img)
s.switchToSelectiveSearchFast()
boxes = s.process() # 可能出现对象的所有区域,会按可能性排序
candidate_boxes = boxes[:2000] # 选取头 2000 个区域
按重叠率 (IOU) 判断每个区域是否包含对象
使用算法选取出来的区域与实际区域通常不会完全重叠,只会重叠一部分,在学习的过程中我们需要根据手头上的真实区域预先判断选取出来的区域是否包含对象,再告诉模型预测结果是否正确。判断选取区域是否包含对象会依据重叠率 (IOU - Intersection Over Union),所谓重叠率就是两个区域重叠的面积占两个区域合并的面积的比率,如下图所示。

我们可以规定重叠率大于 70% 的候选区域包含对象,重叠率小于 30% 的区域不包含对象,而重叠率介于 30% ~ 70% 的区域不应该参与学习,这是为了给模型提供比较明确的数据,使得学习效果更好。
计算重叠率的代码如下,如果两个区域没有重叠则重叠率会为 0:
def calc_iou(rect1, rect2):
"""计算两个区域重叠部分 / 合并部分的比率 (intersection over union)"""
x1, y1, w1, h1 = rect1
x2, y2, w2, h2 = rect2
xi = max(x1, x2)
yi = max(y1, y2)
wi = min(x1+w1, x2+w2) - xi
hi = min(y1+h1, y2+h2) - yi
if wi > 0 and hi > 0: # 有重叠部分
area_overlap = wi*hi
area_all = w1*h1 + w2*h2 - area_overlap
iou = area_overlap / area_all
else: # 没有重叠部分
iou = 0
return iou
原始论文
如果你想看 RCNN 的原始论文可以到以下的地址:
https://arxiv.org/pdf/1311.2524.pdf
使用 RCNN 识别图片中的人脸
好了,到这里你应该大致了解 RCNN 的实现原理,接下来我们试着用 RCNN 学习识别一些图片。
因为收集图片和标记图片非常累人
写给程序员的机器学习入门 (九) - 对象识别 RCNN 与 Fast-RCNN的更多相关文章
- 写给程序员的机器学习入门 (十) - 对象识别 Faster-RCNN - 识别人脸位置与是否戴口罩
每次看到大数据人脸识别抓逃犯的新闻我都会感叹技术发展的太快了,国家治安水平也越来越好了
- 写给程序员的机器学习入门 (十一) - 对象识别 YOLO - 识别人脸位置与是否戴口罩
这篇将会介绍目前最流行的对象识别模型 YOLO,YOLO 的特征是快,识别速度非常快
- 写给程序员的机器学习入门 (八 补充) - 使用 GPU 训练模型
在之前的文章中我训练模型都是使用的 CPU,因为家中黄脸婆不允许我浪费钱买电脑.终于的,附近一个废品回收站的朋友转让给我一台破烂旧电脑,所以我现在可以体验使用 GPU 训练模型了
- 写给程序员的机器学习入门 (二) - pytorch 与矩阵计算入门
pytorch 简介 pytorch 是目前世界上最流行的两个机器学习框架的其中之一,与 tensoflow 并峙双雄.它提供了很多方便的功能,例如根据损失自动微分计算应该怎样调整参数,提供了一系列的 ...
- 写给程序员的机器学习入门 (五) - 递归模型 RNN,LSTM 与 GRU
递归模型的应用场景 在前面的文章中我们看到的多层线性模型能处理的输入数量是固定的,如果一个模型能接收两个输入那么你就不能给它传一个或者三个.而有时候我们需要根据数量不一定的输入来预测输出,例如文本就是 ...
- 写给程序员的机器学习入门 (七) - 双向递归模型 (BRNN) - 根据上下文补全单词
这一篇将会介绍什么是双向递归模型和如何使用双向递归模型实现根据上下文补全句子中的单词. 双向递归模型 到这里为止我们看到的例子都是按原有顺序把输入传给递归模型的,例如传递第一天股价会返回根据第一天股价 ...
- 写给程序员的机器学习入门 (八) - 卷积神经网络 (CNN) - 图片分类和验证码识别
这一篇将会介绍卷积神经网络 (CNN),CNN 模型非常适合用来进行图片相关的学习,例如图片分类和验证码识别,也可以配合其他模型实现 OCR. 使用 Python 处理图片 在具体介绍 CNN 之前, ...
- Java程序员的Golang入门指南(下)
Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合 ...
- Java程序员的Golang入门指南(上)
Java程序员的Golang入门指南 1.序言 Golang作为一门出身名门望族的编程语言新星,像豆瓣的Redis平台Codis.类Evernote的云笔记leanote等. 1.1 为什么要学习 如 ...
随机推荐
- Vue.js 学习笔记之六:构建更复杂的组件
在掌握了如何构建与编译 Vue 组件的基础知识之后,接下来就可以试着来构建一些更具有实际用处的复杂组件了.为了赋予组件更具实用性的后面,首先要做的就是让这些组件具备监听用户自定义事件的能力,并且允许用 ...
- Lock接口之Condition接口
之前在写显示锁的是后,在显示锁的接口中,提到了new Condition这个方法,这个方法会返回一个Condition对象 简单介绍一下 Condition接口: 任意一个Java对象,都拥有一组监视 ...
- K8s之实践Pod深入理解
K8s之实践Pod深入理解 1.同一pod下的nginx+php+mysql nginx+php+mysql.yaml文件 --- apiVersion: v1 kind: Secret meta ...
- 适合 C++ 新手学习的开源项目——在 GitHub 学编程
作者:HelloGitHub-小鱼干 俗话说:万事开头难,学习编程也是一样.在 HelloGitHub 的群里,经常遇到有小伙伴询问编程语言如何入门方面的问题,如: 我要学习某一门编程语言,有什么开源 ...
- find命令的简单使用
Find命令 格式:find [option] [Path] [筛选条件] [处理动作] Path:默认当前目录 筛选条件:对文件/目录设置筛选条件 处理动作:默认显示所有文件 筛选条件: -name ...
- day85:luffy:购物车根据有效期不同切换价格&购物车删除操作&价格结算&订单页面前戏
目录 1.购物车有效期切换 2.根据有效期不同切换价格 3.购物车删除操作 4.价格结算 5.订单页面-初始化 1.购物车有效期切换 1.关于有效期表结构的设计 1.course/models.py ...
- Python如何快速复制序列?
1 基本用法 把序列乘以一个整数,就会产生一个新序列.这个新序列是原始序列复制了整数份,然后再拼接起来的结果. l=[1,2,3] l2=l * 3 logging.info('l2 -> %s ...
- 你的旧版本 App 为何运行在 iPhone 12 上没有异常?
背景 当我在 10月14日 iPhone 12 系列发布直播,看到 iPhone 12 系列的分辨率后,我注意到这些分辨率是全新的时,我立即在群里吐槽:又需要适配一波了.我只是以为宽高变化会导致字号变 ...
- 这个Map你肯定不知道,毕竟存在感确实太低了。
这是why哥的第 75 篇原创文章 从Dubbo的优雅停机说起 好吧,其实本文并不是讲 Dubbo 的优雅停机的. 只是我在 Dubbo 停机方法 DubboShutdownHook 类中,看到了这样 ...
- RPS/RFS/ GRO
http://www.cnhalo.net/2016/09/13/linux-gro/ GRO(Generic receive offload): 在napi poll里把小包封装成大包再递交给协议栈 ...