Transformers 4.37 中文文档(四)(2)https://developer.aliyun.com/article/1564977
图像分割
原始文本:
huggingface.co/docs/transformers/v4.37.2/en/tasks/semantic_segmentation
www.youtube-nocookie.com/embed/dKE8SIt9C-w
图像分割模型将图像中对应不同感兴趣区域的区域分开。这些模型通过为每个像素分配一个标签来工作。有几种类型的分割:语义分割、实例分割和全景分割。
在本指南中,我们将:
- 查看不同类型的分割。
- 有一个用于语义分割的端到端微调示例。
在开始之前,请确保已安装所有必要的库:
pip install -q datasets transformers evaluate
我们鼓励您登录您的 Hugging Face 帐户,这样您就可以上传和与社区分享您的模型。在提示时,输入您的令牌以登录:
>>> from huggingface_hub import notebook_login >>> notebook_login()
分割类型
语义分割为图像中的每个像素分配一个标签或类。让我们看一下语义分割模型的输出。它将为图像中遇到的每个对象实例分配相同的类,例如,所有猫都将被标记为“cat”而不是“cat-1”、“cat-2”。我们可以使用 transformers 的图像分割管道快速推断一个语义分割模型。让我们看一下示例图像。
from transformers import pipeline from PIL import Image import requests url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/segmentation_input.jpg" image = Image.open(requests.get(url, stream=True).raw) image
我们将使用nvidia/segformer-b1-finetuned-cityscapes-1024-1024。
semantic_segmentation = pipeline("image-segmentation", "nvidia/segformer-b1-finetuned-cityscapes-1024-1024") results = semantic_segmentation(image) results
分割管道输出包括每个预测类的掩码。
[{'score': None, 'label': 'road', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'sidewalk', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'building', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'wall', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'pole', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'traffic sign', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'vegetation', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'terrain', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'sky', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': None, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}]
查看汽车类的掩码,我们可以看到每辆汽车都被分类为相同的掩码。
results[-1]["mask"]
在实例分割中,目标不是对每个像素进行分类,而是为给定图像中的每个对象实例预测一个掩码。它的工作方式与目标检测非常相似,其中每个实例都有一个边界框,而这里有一个分割掩码。我们将使用facebook/mask2former-swin-large-cityscapes-instance。
instance_segmentation = pipeline("image-segmentation", "facebook/mask2former-swin-large-cityscapes-instance") results = instance_segmentation(Image.open(image)) results
如下所示,有多辆汽车被分类,除了属于汽车和人实例的像素之外,没有对其他像素进行分类。
[{'score': 0.999944, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999945, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999652, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.903529, 'label': 'person', 'mask': <PIL.Image.Image image mode=L size=612x415>}]
查看下面的一辆汽车掩码。
results[2]["mask"]
全景分割结合了语义分割和实例分割,其中每个像素被分类为一个类和该类的一个实例,并且每个类的每个实例有多个掩码。我们可以使用facebook/mask2former-swin-large-cityscapes-panoptic。
panoptic_segmentation = pipeline("image-segmentation", "facebook/mask2former-swin-large-cityscapes-panoptic") results = panoptic_segmentation(Image.open(image)) results
如下所示,我们有更多的类。稍后我们将说明,每个像素都被分类为其中的一个类。
[{'score': 0.999981, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999958, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.99997, 'label': 'vegetation', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999575, 'label': 'pole', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999958, 'label': 'building', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999634, 'label': 'road', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.996092, 'label': 'sidewalk', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.999221, 'label': 'car', 'mask': <PIL.Image.Image image mode=L size=612x415>}, {'score': 0.99987, 'label': 'sky', 'mask': <PIL.Image.Image image mode=L size=612x415>}]
让我们对所有类型的分割进行一次并排比较。
看到所有类型的分割,让我们深入研究为语义分割微调模型。
语义分割的常见实际应用包括训练自动驾驶汽车识别行人和重要的交通信息,识别医学图像中的细胞和异常,以及监测卫星图像中的环境变化。
为分割微调模型
我们现在将:
- 在SceneParse150数据集上对SegFormer进行微调。
- 使用您微调的模型进行推断。
本教程中演示的任务由以下模型架构支持:
BEiT, Data2VecVision, DPT, MobileNetV2, MobileViT, MobileViTV2, SegFormer, UPerNet
加载 SceneParse150 数据集
首先从 🤗 数据集库中加载 SceneParse150 数据集的一个较小子集。这将让您有机会进行实验,并确保一切正常,然后再花更多时间在完整数据集上进行训练。
>>> from datasets import load_dataset >>> ds = load_dataset("scene_parse_150", split="train[:50]")
使用 train_test_split 方法将数据集的 train
分割为训练集和测试集:
>>> ds = ds.train_test_split(test_size=0.2) >>> train_ds = ds["train"] >>> test_ds = ds["test"]
然后看一个例子:
>>> train_ds[0] {'image': <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=512x683 at 0x7F9B0C201F90>, 'annotation': <PIL.PngImagePlugin.PngImageFile image mode=L size=512x683 at 0x7F9B0C201DD0>, 'scene_category': 368}
image
:场景的 PIL 图像。annotation
:分割地图的 PIL 图像,也是模型的目标。scene_category
:描述图像场景的类别 id,如“厨房”或“办公室”。在本指南中,您只需要image
和annotation
,两者都是 PIL 图像。
您还需要创建一个将标签 id 映射到标签类的字典,这在稍后设置模型时会很有用。从 Hub 下载映射并创建 id2label
和 label2id
字典:
>>> import json >>> from huggingface_hub import cached_download, hf_hub_url >>> repo_id = "huggingface/label-files" >>> filename = "ade20k-id2label.json" >>> id2label = json.load(open(cached_download(hf_hub_url(repo_id, filename, repo_type="dataset")), "r")) >>> id2label = {int(k): v for k, v in id2label.items()} >>> label2id = {v: k for k, v in id2label.items()} >>> num_labels = len(id2label)
自定义数据集
如果您更喜欢使用 run_semantic_segmentation.py 脚本而不是笔记本实例进行训练,您也可以创建并使用自己的数据集。该脚本需要:
- 一个包含两个 Image 列“image”和“label”的 DatasetDict。
from datasets import Dataset, DatasetDict, Image image_paths_train = ["path/to/image_1.jpg/jpg", "path/to/image_2.jpg/jpg", ..., "path/to/image_n.jpg/jpg"] label_paths_train = ["path/to/annotation_1.png", "path/to/annotation_2.png", ..., "path/to/annotation_n.png"] image_paths_validation = [...] label_paths_validation = [...] def create_dataset(image_paths, label_paths): dataset = Dataset.from_dict({"image": sorted(image_paths), "label": sorted(label_paths)}) dataset = dataset.cast_column("image", Image()) dataset = dataset.cast_column("label", Image()) return dataset # step 1: create Dataset objects train_dataset = create_dataset(image_paths_train, label_paths_train) validation_dataset = create_dataset(image_paths_validation, label_paths_validation) # step 2: create DatasetDict dataset = DatasetDict({ "train": train_dataset, "validation": validation_dataset, } ) # step 3: push to Hub (assumes you have ran the huggingface-cli login command in a terminal/notebook) dataset.push_to_hub("your-name/dataset-repo") # optionally, you can push to a private repo on the Hub # dataset.push_to_hub("name of repo on the hub", private=True)
- 一个 id2label 字典,将类整数映射到它们的类名
import json # simple example id2label = {0: 'cat', 1: 'dog'} with open('id2label.json', 'w') as fp: json.dump(id2label, fp)
例如,查看这个示例数据集,该数据集是使用上述步骤创建的。
预处理
下一步是加载一个 SegFormer 图像处理器,准备图像和注释以供模型使用。某些数据集,如此类数据集,使用零索引作为背景类。但是,背景类实际上不包括在 150 个类中,因此您需要设置 reduce_labels=True
,从所有标签中减去一个。零索引被替换为 255
,因此 SegFormer 的损失函数会忽略它:
>>> from transformers import AutoImageProcessor >>> checkpoint = "nvidia/mit-b0" >>> image_processor = AutoImageProcessor.from_pretrained(checkpoint, reduce_labels=True)
Pytorch 隐藏 Pytorch 内容
通常会对图像数据集应用一些数据增强,以使模型更具抗过拟合能力。在本指南中,您将使用 ColorJitter
函数从 torchvision 随机更改图像的颜色属性,但您也可以使用任何您喜欢的图像库。
>>> from torchvision.transforms import ColorJitter >>> jitter = ColorJitter(brightness=0.25, contrast=0.25, saturation=0.25, hue=0.1)
现在创建两个预处理函数,准备图像和注释以供模型使用。这些函数将图像转换为 pixel_values
,将注释转换为 labels
。对于训练集,在将图像提供给图像处理器之前应用 jitter
。对于测试集,图像处理器裁剪和规范化 images
,仅裁剪 labels
,因为在测试期间不应用数据增强。
>>> def train_transforms(example_batch): ... images = [jitter(x) for x in example_batch["image"]] ... labels = [x for x in example_batch["annotation"]] ... inputs = image_processor(images, labels) ... return inputs >>> def val_transforms(example_batch): ... images = [x for x in example_batch["image"]] ... labels = [x for x in example_batch["annotation"]] ... inputs = image_processor(images, labels) ... return inputs
要在整个数据集上应用 jitter
,请使用 🤗 数据集 set_transform 函数。变换是实时应用的,速度更快,占用的磁盘空间更少:
>>> train_ds.set_transform(train_transforms) >>> test_ds.set_transform(val_transforms)
TensorFlow 隐藏 TensorFlow 内容
对图像数据集应用一些数据增强是常见的,可以使模型更具抗过拟合能力。在本指南中,您将使用tf.image
来随机更改图像的颜色属性,但您也可以使用任何您喜欢的图像库。定义两个单独的转换函数:
- 包括图像增强的训练数据转换
- 验证数据转换仅转置图像,因为🤗 Transformers 中的计算机视觉模型期望通道优先布局
>>> import tensorflow as tf >>> def aug_transforms(image): ... image = tf.keras.utils.img_to_array(image) ... image = tf.image.random_brightness(image, 0.25) ... image = tf.image.random_contrast(image, 0.5, 2.0) ... image = tf.image.random_saturation(image, 0.75, 1.25) ... image = tf.image.random_hue(image, 0.1) ... image = tf.transpose(image, (2, 0, 1)) ... return image >>> def transforms(image): ... image = tf.keras.utils.img_to_array(image) ... image = tf.transpose(image, (2, 0, 1)) ... return image
接下来,创建两个预处理函数,用于为模型准备图像和注释的批处理。这些函数应用图像转换,并使用之前加载的image_processor
将图像转换为pixel_values
,将注释转换为labels
。ImageProcessor
还负责调整大小和规范化图像。
>>> def train_transforms(example_batch): ... images = [aug_transforms(x.convert("RGB")) for x in example_batch["image"]] ... labels = [x for x in example_batch["annotation"]] ... inputs = image_processor(images, labels) ... return inputs >>> def val_transforms(example_batch): ... images = [transforms(x.convert("RGB")) for x in example_batch["image"]] ... labels = [x for x in example_batch["annotation"]] ... inputs = image_processor(images, labels) ... return inputs
要在整个数据集上应用预处理转换,使用🤗 Datasets set_transform函数。转换是实时应用的,速度更快,占用的磁盘空间更少:
>>> train_ds.set_transform(train_transforms) >>> test_ds.set_transform(val_transforms)
Transformers 4.37 中文文档(四)(4)https://developer.aliyun.com/article/1564979