背景介绍
SegFormer:实例分割在自动驾驶汽车技术的快速发展中发挥了关键作用。对于任何在道路上行驶的车辆来说,车道检测都是必不可少的。车道是道路上的标记,有助于区分道路上可行驶地区和不可行驶地区。车道检测算法有很多种,每种算法都有各自的优缺点。
在本文中,我们将使用Berkeley Deep Drive数据集对HuggingFace(Enze Xie、Wenhai Wang、Zhiding Yu 等人)中非常著名的SegFormer 模型进行微调,以对车辆的POV视频进行车道检测。此实行甚至适用于处置惩罚起来很复杂的夜间驾驶场景。
车道检测在ADAS中的作用
总体而言,车道检测对ADAS系统产生了深远影响。让我们在这里探讨其中的几个:
- 车道保持:除了警告系统之外,车道检测也是车道保持辅助 (LKA) 技术不可或缺的一部门,它不仅可以提示驾驶员,还可以采取纠正措施,例如轻柔的转向干预,以使车辆保持在车道中心。
- 交通流分析:车道检测使车辆可以或许相识道路几何形状,这在归并和变道等复杂驾驶场景中至关紧张,而且对于根据四周交通流量调解速率的自适应巡航控制系统至关紧张。
- 自动导航:对于半自动或自动驾驶汽车,车道检测是使车辆可以或许在道路底子设施内导航和保持其位置的根本组件。它对于自动驾驶算法中的路线规划和决策过程至关紧张。
- 驾驶舒适度:使用车道检测的系统可以接管部门驾驶任务,减少驾驶员疲惫,提供更舒适的驾驶体验,尤其是在高速公路远程行驶时。
- 道路状况监测:车道检测系统也有助于监测道路状况。例如,如果系统连续检测到车道标记不清晰或根本没有车道标记,则可以反馈此信息以用于底子设施维护和改进。
伯克利Deep Drive数据集
Berkeley Deep Drive 100K (BDD100K) 数据集是从各个城市和郊区收集的各种驾驶视频序列的综合集合。其紧张用于促进自动驾驶的研究和开发。该数据集非常庞大,包罗约100,000 个视频,每个视频时长 40 秒,涵盖各种驾驶场景、天气条件和一天中的时间。BDD100K 数据集中的每个视频都附有一组丰富的帧级注释。这些注释包括车道、可驾驶地区、物体(如车辆、行人和交通标记)的标签以及全帧实例分割。数据集的多样性对于开发强大的车道检测算法至关紧张,由于它可以将模型暴露给各种车道标记、道路范例和情况条件。
在本文中, BDD100K 数据集的10% 样本用于微调 SegFormer 模型。这种子采样方法允许更易于管理的数据集巨细,同时保持整个数据集中存在的整体多样性的代表性子集。10% 的样本包括10,000 张图像,这些图像是颠末精心挑选以代表数据集的全面驾驶条件和场景。
让我们看一下示例数据集中的一些示例图像和标注掩码:
从上图可以看出,对于BDD数据集中的每个图像,都有一个有用的真实二进制掩码,可协助完成车道检测任务。这可以视为一个2 类分割问题,其中车道由一个类表现,背景是另一个类。在这种情况下,训练集有7000张图像和掩码,有用集有大约3000张图像和掩码。
接下来,让我们为这个实行构建训练管道。
代码演练
在本节中,我们将探讨使用 BDD 数据集微调HuggingFace SegFormer 模型(本文还表明了内部架构)所涉及的各种过程。
先决条件
'BDDDataset' 类的紧张目的是高效地从指定目次加载和预处置惩罚图像数据及其相应的分割掩码。它负责以下功能:
- 使用路径加载图像及其对应的蒙版。
- 图像转换为 RGB 格式,而蒙版转换为灰度(单通道)。
- 然后将掩码转换为二进制格式,其中非零像素被视为车道的一部门(假设车道分割任务)。
- 将蒙版调解巨细以匹配图像尺寸,然后转换为张量。
- 末了,将掩码阈值化回二进制值并转换为 LongTensor,得当 PyTorch 中的分割任务
- class BDDDataset(Dataset): def __init__(self, images_dir, masks_dir, transform=None): self.images_dir = images_dir self.masks_dir = masks_dir self.transform = transform self.images = [img for img in os.listdir(images_dir) if img.endswith('.jpg')] self.masks = [mask.replace('.jpg', '.png') for mask in self.images] def __len__(self): return len(self.images) def __getitem__(self, idx): image_path = os.path.join(self.images_dir, self.images[idx]) mask_path = os.path.join(self.masks_dir, self.masks[idx]) image = Image.open(image_path).convert("RGB") mask = Image.open(mask_path).convert('L') # Convert mask to grayscale # Convert mask to binary format with 0 and 1 values mask = np.array(mask) mask = (mask > 0).astype(np.uint8) # Assuming non-zero pixels are lanes # Convert to PIL Image for consistency in transforms mask = Image.fromarray(mask) if self.transform: image = self.transform(image) # Assuming to_tensor transform is included which scales pixel values between 0-1 # mask = to_tensor(mask) # Convert the mask to [0, 1] range mask = TF.functional.resize(img=mask, size=[360, 640], interpolation=Image.NEAREST) mask = TF.functional.to_tensor(mask) mask = (mask > 0).long() # Threshold back to binary and convert to LongTensor return image, mask
复制代码 数据加载器界说和初始化
使用之前创建的“BDDDataset”类,我们需要界说和初始化数据加载器。为此,必须创建两个单独的数据加载器,一个用于训练集,另一个用于验证集。训练数据加载器还需要一些转换。下面的代码片段可用于此目的:
- # Define the appropriate transformationstransform = TF.Compose([ TF.Resize((360, 640)), TF.ToTensor(), TF.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])]) # Create the datasettrain_dataset = BDDDataset(images_dir='deep_drive_10K/train/images', masks_dir='deep_drive_10K/train/masks', transform=transform) valid_dataset = BDDDataset(images_dir='deep_drive_10K/valid/images', masks_dir='deep_drive_10K/valid/masks', transform=transform) # Create the data loaderstrain_loader = DataLoader(train_dataset, batch_size=4, shuffle=True, num_workers=6)valid_loader = DataLoader(valid_dataset, batch_size=4, shuffle=False, num_workers=6)
复制代码 让我们看一下该管道中使用的转换。
- TF.Resize((360, 640)):将图像巨细调解为 360×640 像素的统一巨细。
- TF.ToTensor():将图像转换为 PyTorch 张量。
- TF.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):使用指定的平均值和尺度差对图像进行归一化,这些平均值和尺度差通常来自 ImageNet 数据集。此步调对于在ImageNet上预训练的模型至关紧张。
根据本身的计算资源,您大概盼望调解“batch_size”和“num_workers”等参数。
HuggingFace SegFormer |