使用Python和HuggingFace转换器进行对象检测

2023年11月27日 由 alex 发表 352 0

在本文中,你将学习关于这种类型的变压器模型。你还将学习使用Python、一个默认的变压器模型和HuggingFace Transformers库创建自己的对象检测管道。


什么是对象检测?


环顾四周。你很可能会看到很多东西——可能是一个计算机显示器、一个键盘和鼠标,或者当你在移动浏览器中浏览时,一个智能手机。


这些都是对象,一个特定类别的实例。例如,在下面的图片中,我们看到了人类这个类别的一个实例。我们还看到了许多瓶子类的实例。虽然类是一个蓝图,但对象是实际的存在,拥有许多独特的特征,同时因为共享的特征而属于该类别。


在图片和视频中,我们看到很多这样的对象。例如,当你正在拍摄交通视频时,很可能会看到很多行人、汽车、自行车等实例。而知道它们在图像中是非常有价值的!


4


物体检测和 Transformer


传统上,物体检测是通过卷积神经网络(Convolutional Neural Networks, CNN)来执行的。通常,它们的架构是特别为物体检测量身定制的,因为它们将图像作为输入,并输出图像的边界框。


如果你熟悉神经网络,你就会知道,卷积网络在学习图像中的重要特征,以及实现空间不变性方面非常有用——换句话说,学习到的对象在图像中的位置或大小并不重要。如果网络能够看到对象的特点,并将其与特定的类别相关联,那么它就能识别它。例如,可以将许多不同的猫识别为猫类的实例。


Transformers通过将输入编码成一个高维状态,然后将其解码回所需的输出。通过巧妙地使用自注意力(self-attention)概念,Transformers不仅学会了检测特定的模式,还学会了将这些模式与其他模式关联起来。


如果Transformers可以被用于图像分类,那么将它们用于物体检测只是距离上的一小步。Carion等人(2020年)已经展示了实际上可以使用基于Transformer的架构来执行此操作。在他们的工作《用Transformers进行端到端物体检测》中,他们引入了检测Transformer(Detection Transformer,简称DETR),我们今天将使用它来创建我们的物体检测管道。


它的工作过程如下,并且甚至没有完全放弃CNN:


  • 使用卷积神经网络,从输入图像中得出重要特征。这些特征被进行位置编码,类似于语言Transformers,以帮助神经网络学习这些特征在图像中的位置。
  • 输入被扁平化并随后使用transformer编码器和注意力机制编码成中间状态。
  • transformer解码器的输入是这个状态和在训练过程中获得的一组学习过的对象查询。
  • 实际上,解码器的输出是一系列通过多个预测头的预测:每个查询一个。由于DETR默认情况下查询的数量设置为100,它每张图像只能预测100个物体,除非你进行了不同的配置。


5


HuggingFace Transformers 和 ObjectDetectionPipeline


ObjectDetectionPipeline可以很容易地作为一个流水线实例初始化……换句话说,通过pipeline("object-detection")的方式,我们将在下面的示例中看到这一点。根据GitHub(没有日期)所述,当你不提供其他输入时,流水线就是这样初始化的:


    "object-detection": {
        "impl": ObjectDetectionPipeline,
        "tf": (),
        "pt": (AutoModelForObjectDetection,) if is_torch_available() else (),
        "default": {"model": {"pt": "facebook/detr-resnet-50"}},
        "type": "image",
    },


不出意外,对象检测任务中会使用一个专门为目标检测量身定制的ObjectDetectionPipeline实例。在HuggingFace Transformers的PyTorch版本中,使用AutoModelForObjectDetection来达到这个目的。


正如你所了解的,默认情况下,facebook/detr-resnet-50模型用于提取图像特征。


COCO数据集(Common Objects in Context,即上下文中的常见对象)是用于训练目标检测模型的标准数据集之一,并被用于训练这个模型。


要使用ObjectDetectionPipeline,必须安装包含PyTorch图像模型的timm包。如果你还没安装它,确保运行以下命令:pip install timm。


使用Python实现简易的目标检测管道


现在让我们看看如何使用Python实现一个简单的目标检测解决方案。你在使用HuggingFace Transformers,必须安装在你的系统上 —— 如果你还没有安装,请运行pip install transformers。


我还假设已经安装了PyTorch,这是当今深度学习领域的领先库之一。


这是我们将在本文后面为之创建目标检测管道并运行的图像:


6


我们从导入开始:


from transformers import pipeline
from PIL import Image, ImageDraw, ImageFont


显然,我们正在使用变压器,特别是它的管道表示形式。然后,我们还使用了PIL,这是一个用于加载、可视化和操作图片的Python库。具体来说,我们正在使用第一个导入 - Image来加载图片,ImageDraw来绘制边界框和标签,后者还需要ImageFont。


说到这两个,接下来是加载字体(我们选择了Arial)并初始化我们上面提到的目标检测管道。


# Load font
font = ImageFont.truetype("arial.ttf", 40)
# Initialize the object detection pipeline
object_detector = pipeline("object-detection")


然后,我们创建一个名为draw_bounding_box的定义,顾名思义,它将用于绘制边界框。它需要输入图像(im)、类概率、边界框的坐标、该定义将用于的边界框列表中的边界框索引,以及该列表的长度。


在这个定义中,你将会:


  • 首先在图像上方绘制实际的边界框,表示为一个带有红色和小半径的圆角矩形bbox,以确保边缘平滑。
  • 其次,在边界框的上方稍微位置绘制文本标签。
  • 最后,返回中间结果,以便我们可以在上面继续绘制下一个边界框和标签。


# Draw bounding box definition
def draw_bounding_box(im, score, label, xmin, ymin, xmax, ymax, index, num_boxes):
 """ Draw a bounding box. """
 print(f"Drawing bounding box {index} of {num_boxes}...")
 # Draw the actual bounding box
 im_with_rectangle = ImageDraw.Draw(im)  
 im_with_rectangle.rounded_rectangle((xmin, ymin, xmax, ymax), outline = "red", width = 5, radius = 10)
 # Draw the label
 im_with_rectangle.text((xmin+35, ymin-25), label, fill="white", stroke_fill = "red", font = font)
 # Return the intermediate result
 return im


剩下的就是核心部分 —— 使用管道然后根据其结果绘制边界框。


首先,图片 —— 我们称呼其为street.jpg,它和Python脚本存放在同一个目录下 —— 将会被打开并存储在一个名为im的PIL对象中。我们只需将其提供给已初始化的object_detector —— 这就足够让模型返回边界框了!Transformers库会处理剩余的部分。


我们接着给一些变量分配数据,并迭代每一个结果,绘制边界框。


最后,我们将图片保存到street_bboxes.jpg。


# Open the image
with Image.open("street.jpg") as im:
 # Perform object detection
 bounding_boxes = object_detector(im)
 # Iteration elements
 num_boxes = len(bounding_boxes)
 index = 0
 # Draw bounding box for each result
 for bounding_box in bounding_boxes:
  # Get actual box
  box = bounding_box["box"]
  # Draw the bounding box
  im = draw_bounding_box(im, bounding_box["score"], bounding_box["label"],\
   box["xmin"], box["ymin"], box["xmax"], box["ymax"], index, num_boxes)
  # Increase index by one
  index += 1
 # Save image
 im.save("street_bboxes.jpg")
 # Done
 print("Done!")


使用不同的模型进行对象检测


如果你创建了自己的模型,或者想要使用一个不同的模型,将它代替基于ResNet-50的DETR Transformer使用起来非常简单。


这样做将需要你在导入部分添加以下内容:


from transformers import DetrFeatureExtractor, DetrForObjectDetection


然后,你可以初始化特征提取器和模型,并用它们来初始化object_detector,而不是使用默认的那个。例如,如果你想使用ResNet-101作为你的主干网络,你可以按照以下方式操作:


# Initialize another model and feature extractor
feature_extractor = DetrFeatureExtractor.from_pretrained('facebook/detr-resnet-101')
model = DetrForObjectDetection.from_pretrained('facebook/detr-resnet-101')
# Initialize the object detection pipeline
object_detector = pipeline("object-detection", model = model, feature_extractor = feature_extractor)


结果


以下是我们对输入图像运行对象检测流程后得到的结果:


7


或者,当放大查看时:


8


对象检测示例 —— 完整代码


以下是完整代码,供想要立即开始的人使用:


from transformers import pipeline
from PIL import Image, ImageDraw, ImageFont

# Load font
font = ImageFont.truetype("arial.ttf", 40)
# Initialize the object detection pipeline
object_detector = pipeline("object-detection")

# Draw bounding box definition
def draw_bounding_box(im, score, label, xmin, ymin, xmax, ymax, index, num_boxes):
 """ Draw a bounding box. """
 print(f"Drawing bounding box {index} of {num_boxes}...")
 # Draw the actual bounding box
 im_with_rectangle = ImageDraw.Draw(im)  
 im_with_rectangle.rounded_rectangle((xmin, ymin, xmax, ymax), outline = "red", width = 5, radius = 10)
 # Draw the label
 im_with_rectangle.text((xmin+35, ymin-25), label, fill="white", stroke_fill = "red", font = font)
 # Return the intermediate result
 return im

# Open the image
with Image.open("street.jpg") as im:
 # Perform object detection
 bounding_boxes = object_detector(im)
 # Iteration elements
 num_boxes = len(bounding_boxes)
 index = 0
 # Draw bounding box for each result
 for bounding_box in bounding_boxes:
  # Get actual box
  box = bounding_box["box"]
  # Draw the bounding box
  im = draw_bounding_box(im, bounding_box["score"], bounding_box["label"],\
   box["xmin"], box["ymin"], box["xmax"], box["ymax"], index, num_boxes)
  # Increase index by one
  index += 1
 # Save image
 im.save("street_bboxes.jpg")
 # Done
 print("Done!")
文章来源:https://medium.com/@francescofranco_39234/object-detection-with-python-and-huggingface-transformers-3f9379c88e69
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消