【2020华为云AI实战营】TensorFlow2.x物体检测初体验

举报
胡琦 发表于 2020/06/15 07:55:18 2020/06/15
【摘要】 理论学再多,不如动手做AI!

本文首次发表于华为云社区ModelArts版块,主要是作者在学习使用AI开发平台ModelArts过程中的一些经验产出。
此次要和大家分享的是ModelArts新增加热乎乎的TensorFlow2.1和jupyterLab的初体验,我们通过学习TensorFlow
官方提供的Demo,了解如何使用预模型来检测图像中的对象。

start.png
↑开局一张图,故事全靠编。

虽然说学习不能“三天打鱼两天晒网”,但是实际情况是“周一到周五摸鱼,周六周日一天打鱼一天晒网”。前阵子听了个推
技术专家的《Vue+Tensorflow.js实现口罩检测》讲座,本想在ModelArts上实现,不过之前一直遇到这样那样的问题。
看到TensorFlow官方提供的Object Detection API Demo就是用的TensorFlow2.X的版本,于是趁着ModelArts刚支持
TensorFlow2及更新了jupyterLab的热度,先跑一跑这个借助预模型实现物体检测的实践。懒人福利:简版操作指南见附件

准备

本文默认您已经注册了华为云账户,并且已领取相关优惠券。当然没有领到优惠券也没关系,目前有ModelArts免费算力活动,而且
【2020华为云AI实战营】等活动已经强势来袭,这也是学习AI的大好时机。此次实践只需用到ModelArts,只需在notobook中jupyterLab执行脚本即可。

What'sModeArts.png
ModelArtshttps://www.huaweicloud.com/product/modelarts.html
AI开发平台ModelArts是面向开发者的一站式AI开发平台,为机器学习与深度学习提供海量数据预处理及半自动化标注、大规模分布式Training、自动化模型生成,及端-边-云模型按需部署能力,帮助用户快速创建和部署模型,管理全周期AI工作流。

AKCK.png
访问密钥配置https://support.huaweicloud.com/prepare-modelarts/modelarts_08_0002.html
获取访问密钥并完成ModelArts全局配置只是使用AI开发平台ModerArts的其中一个步骤,当然尤为重要的一步。

resources.png
源码地址https://github.com/tensorflow/models
gitee备份https://gitee.com/hu-qi/models

创建免费算力实例

2020年了,想学AI的朋友赶紧来 2020.huaweicloud.ai ,不仅资源丰富,还能动手实践,“理论学再多,不如动手做!华为专家带你免费学AI”,就等您来!一段硬广之后,开启今天的实践。点击图片或者打开华为云普惠AI链接-https://activity.huaweicloud.com/2020ModelArts_Promotion.html,
点击立即免费体验应该是能进入到notebook创建界面,如果提示需要授权的话可能还需执行准备阶段提到的访问密钥配置操作。
FreeAI.png

在创建Notebook界面,我们选择TF-2.1.0-python3.6作为工作环境,选择类型为GPU的[限时免费]体验规格GPU版,点击下一步确认配置费用是0元再提交就可以创建一个免费的Notebook。待Notebook启动成功之后点击右侧的【打开】进入jupyter工作台。如果遇到系统繁忙请耐心等待,毕竟免费算力的活动实在是太火爆了!
CreateNotebook.png

Open JupyterLab开始实践

在Notobook中Jupyter的右上角有一个Open JupyterLab的按钮,点击即可进入介真的係里没有玩过的船新版本,上手只需半分钟的JupyterLab。从
JupyterLab的控制台界面来看,简单又明了,顶部是菜单栏,左侧是工具栏和文件目录,中间是编辑区域,顶部右侧还有CPU、内存使用情况,底部是一些状态提示。我们点击中间区域Notebook下大写的T,创建一个TensorFlow-2.1.0的文件,跟Copy攻城狮开始我们的 物体检测 代码Copy之旅!
jupyterLab.png

检查依赖

看过一些ModelArts的实操教程,99%的教程不会告诉我们要先检查python的依赖,也许这一步真的是脱裤子放屁--多此一举;不过我想说的是,Make sure you have installed**确保我是否安装了某个依赖,不是凭空就能知道的,也不是直接安装依赖就行,太暴力了!关于是否需要检查依赖,这仅仅是我个人的看法和习惯,不影响后续的操作。通过文件中执行!pip list,我们环境中安装了什么版本的什么依赖一览无余。

!pip list

安装依赖

TensorFlow Slim:一个用于定义、训练和评估TensorFlow中复杂模型的轻量级库。

pycocotools:用于处理MSCOCO数据集的工具

!pip install tf_slim
!pip install pycocotools

下载tensorflow/models仓库

其实我们可以先执行这段代码,之后进入到models/research/object_detection目录,打开object_detection_tutorial.ipynb文件即可开始实践,这里我们的代码基本Copy自那个文件。
由于众所周知的原因,我们下载gayhub上的仓库比较慢,所以我们可以把仓库同步到gitee上,从gitee
上clone就会快很多。以下代码执行完毕之后,工作目录会多一个models的文件夹,我们后续步骤依赖于models下
的一些文件。

import os
import pathlib


if "models" in pathlib.Path.cwd().parts:
  while "models" in pathlib.Path.cwd().parts:
    os.chdir('..')
elif not pathlib.Path('models').exists():
  !git clone --depth 1 https://gitee.com/hu-qi/models
print('Done!')

编译protobufs并安装object_detection

之前在TensorFlow1.x的版本上安装objec_detection时,总能遇到这样那样的问题,直到放弃(PS:主要是没找到门道,一个瞎琢磨),自从尝试在TensorFlow2.x上运行,出来些许警告,一路执行脚本都很顺畅。

%%bash
cd models/research/
protoc object_detection/protos/*.proto --python_out=.
%%bash 
cd models/research
pip install .

依赖引用

此处引用到一些常用Python内置库以及numpy等,

import numpy as np
import os
import six.moves.urllib as urllib
import sys
import tarfile
import tensorflow as tf
import zipfile

from collections import defaultdict
from io import StringIO
from matplotlib import pyplot as plt
from PIL import Image
from IPython.display import display

# 引入object_detection模块
from object_detection.utils import ops as utils_ops
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util

# patch
# 补丁:从tf1引入 `utils.ops`
utils_ops.tf = tf.compat.v1
# 补丁:gfile位置
tf.gfile = tf.io.gfile

模型准备

定义load_model函数,使得我们可以根据速度和精度替换不同的检测预模型,更多模型详见模型检测库:https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md。 我们在接下来的实实践中也会尝试替换不同的预模型。

def load_model(model_name):
  base_url = 'http://download.tensorflow.org/models/object_detection/'
  model_file = model_name + '.tar.gz'
  model_dir = tf.keras.utils.get_file(
    fname=model_name, 
    origin=base_url + model_file,
    untar=True)

  model_dir = pathlib.Path(model_dir)/"saved_model"

  model = tf.saved_model.load(str(model_dir))
  model = model.signatures['serving_default']

  return model

加载标签集,有人、单车、摩托等90个分类的标签。

# 用于为每个框添加正确标签的字符串列表。
PATH_TO_LABELS = 'models/research/object_detection/data/mscoco_label_map.pbtxt'
category_index = label_map_util.create_category_index_from_labelmap(PATH_TO_LABELS, use_display_name=True)

这里为了方便,我们直接使用models仓库中自带的测试图片,也可以自己上传或者自定义

# 如果要用图像测试代码,只需将图像的路径添加到测试图像路径
PATH_TO_TEST_IMAGES_DIR = pathlib.Path('models/research/object_detection/test_images')
TEST_IMAGE_PATHS = sorted(list(PATH_TO_TEST_IMAGES_DIR.glob("*.jpg")))
TEST_IMAGE_PATHS

检测

加载对象检测模型,通过执行load_model从TensorFlow官网下载指定模型

# 这里model_name可替换,对应上面提到检测模型库中的模型名称
model_name = 'ssd_mobilenet_v1_coco_2017_11_17'
detection_model = load_model(model_name)
print('Done!')

检查模型

print(detection_model.inputs)
detection_model.output_dtypes
detection_model.output_shapes

添加包装器函数以调用模型,并清除输出:

def run_inference_for_single_image(model, image):
  image = np.asarray(image)
  # 输入必须是张量(tensor),使用`tf.convert_to_tensor`进行转换。
  input_tensor = tf.convert_to_tensor(image)
  # 模型预测需要一批图像,因此使用`tf.newaxis`添加一个axis。
  input_tensor = input_tensor[tf.newaxis,...]

  # 运行推理
  output_dict = model(input_tensor)

  # 所有输出均为批次张量(batches tensors)
  # 转换为numpy数组,并采用索引[0]删除批处理维度
  # 我们只对前num_detections个感兴趣
  num_detections = int(output_dict.pop('num_detections'))
  output_dict = {key:value[0, :num_detections].numpy() 
                 for key,value in output_dict.items()}
  output_dict['num_detections'] = num_detections

  # detection_classes应该是整型
  output_dict['detection_classes'] = output_dict['detection_classes'].astype(np.int64)

  # 带蒙版(mask)的模型处理:
  if 'detection_masks' in output_dict:
    # 将bbox蒙版重新调整为图像大小
    detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks(
              output_dict['detection_masks'], output_dict['detection_boxes'],
               image.shape[0], image.shape[1])      
    detection_masks_reframed = tf.cast(detection_masks_reframed > 0.5,
                                       tf.uint8)
    output_dict['detection_masks_reframed'] = detection_masks_reframed.numpy()

  return output_dict

在每个测试图像上运行并显示结果:

def show_inference(model, image_path):
  # 之后将使用基于数组的图像表示形式来展示带有框和标签的结果图像。
  image_np = np.array(Image.open(image_path))
  # 实际检测
  output_dict = run_inference_for_single_image(model, image_np)
  # 可视化检测结果
  vis_util.visualize_boxes_and_labels_on_image_array(
      image_np,
      output_dict['detection_boxes'],
      output_dict['detection_classes'],
      output_dict['detection_scores'],
      category_index,
      instance_masks=output_dict.get('detection_masks_reframed', None),
      use_normalized_coordinates=True,
      line_thickness=1)

  display(Image.fromarray(image_np))

遍历检测TEST_IMAGE_PATHS路径下的图片,最终展示预测结果

# 执行检测
for image_path in TEST_IMAGE_PATHS:
  show_inference(detection_model, image_path)

输出结果如下:
ssd_mobilenet_v1_coco_2017_11_17-1.png
ssd_mobilenet_v1_coco_2017_11_17-2.png
从图中可以看出效果并不理想,如图一中人没识别出来,图二中也有部分物体没检测到。

实例细分

我们可以通过加载其他模型重新检测

model_name = "mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28"
masking_model = load_model(model_name)
print('Done!')

实例细分模型包括以下detection_masks输出:

masking_model.output_shapes

再次执行检测:

for image_path in TEST_IMAGE_PATHS:
  show_inference(masking_model, image_path)

输出结果如下:
mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28-1.png
mask_rcnn_inception_resnet_v2_atrous_coco_2018_01_28-2.png
相比ssd_mobilenet_v1_cocomask_rcnn_inception_resnet_v2_atrous_coco的效果稍微好点,能检测到人和另一个小的风筝。

替换测试图片重新检测

我们还可以检测自己上传的图片,这里我以【2020华为云AI实战营】第二章中物体检测Faster R-CNN实践的测试图片为例。上传两张图片到models/research/object_detection/test_images,我们再换种模型试试。

model_name = "faster_rcnn_nas_coco_2018_01_28"
masking_model = load_model(model_name)
print('Done!')
masking_model.output_shapes

再次执行检测

for image_path in TEST_IMAGE_PATHS:
  show_inference(masking_model, image_path)

输出结果如下:
faster_rcnn_nas_coco_2018_01_28-1.png
faster_rcnn_nas_coco_2018_01_28-2.png
new-1.png
new-2.png

我们发现faster_rcnn_nas_coco相比之下,又要好一点点,能正确的识别人,甚至还能检测到细微之处的风筝和人

总结

通过以上简短的实践,我们借助TensorFlow2.x实现了一个简单的物体检测,并切换了多种预模型进行检测,粗略地体验了不同模型速度和精度的差异。



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。