自動運転車にミスは許されません。信号や歩行者を見逃すと大惨事になりかねません。しかし、動きの激しい都市環境で物体を検出するのは困難です。
私は、Atrous Spatial Pyramid Pooling (ASPP) と転移学習を使用して、自律走行車の物体検出を最適化する作業に取り組みました。その結果、照明条件が悪い場合でも複数のスケールで物体を検出し、リアルタイムで効率的に実行するモデルが完成しました。
これが私がやった方法です。
自動運転車は物体を検出するために畳み込みニューラル ネットワーク (CNN)に依存していますが、現実世界の状況では次のような課題が生じます。
従来の CNN は、マルチスケールのオブジェクト検出に苦労し、ゼロからのトレーニングに非常に長い時間がかかります。そこで、 ASPP と転移学習が役立ちます。
CNN は固定サイズのオブジェクトには適していますが、現実世界のオブジェクトはサイズと距離が異なります。Atrous Spatial Pyramid Pooling (ASPP) は、拡張畳み込みを使用して複数のスケールで特徴をキャプチャすることでこの問題を解決します。
ASPP は、異なる膨張率を持つ複数の畳み込みフィルターを適用して、さまざまな解像度、小さなオブジェクト、大きなオブジェクト、およびその間のあらゆるものの特徴を抽出します。
複雑な環境で堅牢なパフォーマンスを実現するために、グループ正規化とアテンションを組み込んだ ASPP を PyTorch に実装した方法を次に示します。
import torch import torch.nn as nn import torch.nn.functional as F class ASPP(nn.Module): """ A more advanced ASPP with optional attention and group normalization. """ def __init__(self, in_channels, out_channels, dilation_rates=(6,12,18), groups=8): super(ASPP, self).__init__() self.aspp_branches = nn.ModuleList() #1x1 Conv branch self.aspp_branches.append( nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=False), nn.GroupNorm(groups, out_channels), nn.ReLU(inplace=True) ) ) for rate in dilation_rates: self.aspp_branches.append( nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=rate, dilation=rate, bias=False), nn.GroupNorm(groups, out_channels), nn.ReLU(inplace=True) ) ) #Global average pooling branch self.global_pool = nn.AdaptiveAvgPool2d((1, 1)) self.global_conv = nn.Sequential( nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, bias=False), nn.GroupNorm(groups, out_channels), nn.ReLU(inplace=True) ) #Attention mechanism to refine the concatenated features self.attention = nn.Sequential( nn.Conv2d(out_channels*(len(dilation_rates)+2), out_channels, kernel_size =1, bias=False), nn.Sigmoid() ) self.project = nn.Sequential( nn.Conv2d(out_channels*(len(dilation_rates)+2), out_channels, kernel_size=1, bias=False), nn.GroupNorm(groups, out_channels), nn.ReLU(inplace=True) ) def forward(self, x): cat_feats = [] for branch in self.aspp_branches: cat_feats.append(branch(x)) g_feat = self.global_pool(x) g_feat = self.global_conv(g_feat) g_feat = F.interpolate(g_feat, size=x.shape[2:], mode='bilinear', align_corners=False) cat_feats.append(g_feat) #Concatenate along channels x_cat = torch.cat(cat_feats, dim=1) #channel-wise attention att_map = self.attention(x_cat) x_cat = x_cat * att_map out = self.project(x_cat) return out
事前にトレーニングされたモデルが存在する場合、オブジェクト検出モデルを最初からトレーニングしても、あまりメリットはありません。転移学習を使用すると、すでにオブジェクトを理解しているモデルを微調整できます。
私は、Facebook AI のトランスフォーマーベースの物体検出モデルである DETR (Detection Transformer) を使用しました。このモデルはコンテキストを学習するため、一時停止標識を見つけるだけでなく、それが道路のシーンの一部であることを理解します。
自動運転データセットで DETR を微調整した方法は次のとおりです。
import torch import torch.nn as nn from transformers import DetrConfig, DetrForObjectDetection class CustomBackbone(nn.Module): def __init__(self, in_channels=3, hidden_dim=256): super(CustomBackbone, self).__init__() # Example: basic conv layers + ASPP self.initial_conv = nn.Sequential( nn.Conv2d(in_channels, 64, kernel_size=7, stride=2, padding=3, bias=False), nn.BatchNorm2d(64), nn.ReLU(inplace=True), nn.MaxPool2d(kernel_size=3, stride=2, padding=1) ) self.aspp = ASPP(in_channels=64, out_channels=hidden_dim) def forward(self, x): x = self.initial_conv(x) x = self.aspp(x) return x class DETRWithASPP(nn.Module): def __init__(self, num_classes=91): super(DETRWithASPP, self).__init__() self.backbone = CustomBackbone() config = DetrConfig.from_pretrained("facebook/detr-resnet-50") config.num_labels = num_classes self.detr = DetrForObjectDetection.from_pretrained("facebook/detr-resnet-50", config=config) self.detr.model.backbone.body = nn.Identity() def forward(self, images, pixel_masks=None): features = self.backbone(images) feature_dict = { "0": features } outputs = self.detr.model(inputs_embeds=None, pixel_values=None, pixel_mask=pixel_masks, features=feature_dict, output_attentions=False) return outputs model = DETRWithASPP(num_classes=10) images = torch.randn(2, 3, 512, 512) outputs = model(images)
自動運転車には膨大なデータセットが必要ですが、現実世界のラベル付きデータは不足しています。解決策は? GAN (Generative Adversarial Networks) を使用して合成データを生成することです。
私はデータセットを拡張するために、GAN を使用して、偽物でありながらリアルな車線標示と交通シーンを作成しました。
以下は車線マーキング生成用のシンプルな GAN です。
import torch import torch.nn as nn import torch.nn.functional as F class LaneMarkingGenerator(nn.Module): """ A DCGAN-style generator designed for producing synthetic lane or road-like images. Input is a latent vector (noise), and the output is a (1 x 64 x 64) grayscale image. You can adjust channels, resolution, and layers to match your target data. """ def __init__(self, z_dim=100, feature_maps=64): super(LaneMarkingGenerator, self).__init__() self.net = nn.Sequential( #Z latent vector of shape (z_dim, 1, 1) nn.utils.spectral_norm(nn.ConvTranspose2d(z_dim, feature_maps * 8, 4, 1, 0, bias=False)), nn.BatchNorm2d(feature_maps * 8), nn.ReLU(True), #(feature_maps * 8) x 4 x 4 nn.utils.spectral_norm(nn.ConvTranspose2d(feature_maps * 8, feature_maps * 4, 4, 2, 1, bias=False)), nn.BatchNorm2d(feature_maps * 4), nn.ReLU(True), #(feature_maps * 4) x 8 x 8 nn.utils.spectral_norm(nn.ConvTranspose2d(feature_maps * 4, feature_maps * 2, 4, 2, 1, bias=False)), nn.BatchNorm2d(feature_maps * 2), nn.ReLU(True), #(feature_maps * 2) x 16 x 16 nn.utils.spectral_norm(nn.ConvTranspose2d(feature_maps * 2, feature_maps, 4, 2, 1, bias=False)), nn.BatchNorm2d(feature_maps), nn.ReLU(True), #(feature_maps) x 32 x 32 nn.utils.spectral_norm(nn.ConvTranspose2d(feature_maps, 1, 4, 2, 1, bias=False)), nn.Tanh() ) def forward(self, z): return self.net(z) class LaneMarkingDiscriminator(nn.Module): """ A DCGAN-style discriminator. It takes a (1 x 64 x 64) image and attempts to classify whether it's real or generated (fake). """ def __init__(self, feature_maps=64): super(LaneMarkingDiscriminator, self).__init__() self.net = nn.Sequential( #1x 64 x 64 nn.utils.spectral_norm(nn.Conv2d(1, feature_maps, 4, 2, 1, bias=False)), nn.LeakyReLU(0.2, inplace=True), #(feature_maps) x 32 x 32 nn.utils.spectral_norm(nn.Conv2d(feature_maps, feature_maps * 2, 4, 2, 1, bias=False)), nn.BatchNorm2d(feature_maps * 2), nn.LeakyReLU(0.2, inplace=True), #(feature_maps * 2) x 16 x 16 nn.utils.spectral_norm(nn.Conv2d(feature_maps * 2, feature_maps * 4, 4, 2, 1, bias=False)), nn.BatchNorm2d(feature_maps * 4), nn.LeakyReLU(0.2, inplace=True), #(feature_maps * 4) x 8 x 8 nn.utils.spectral_norm(nn.Conv2d(feature_maps * 4, feature_maps * 8, 4, 2, 1, bias=False)), nn.BatchNorm2d(feature_maps * 8), nn.LeakyReLU(0.2, inplace=True), #(feature_maps * 8) x 4 x 4 nn.utils.spectral_norm(nn.Conv2d(feature_maps * 8, 1, 4, 1, 0, bias=False)), ) def forward(self, x): return self.net(x).view(-1)
ASPP、転移学習、合成データを組み合わせることで、自動運転車向けのより正確でスケーラブルな物体検出システムを構築しました。主な結果は次のとおりです。
私たちは、ASPP、Transformers、合成データを統合して、自律的な物体検出の 3 つの脅威を生み出しました。これにより、かつては動作が遅く、死角になりやすいモデルが、1 ブロック先から信号機を検知できる高速で知覚力のあるシステムへと変化しました。拡張畳み込みを使用してマルチスケールの詳細を、転移学習を使用して迅速に微調整し、GAN で生成されたデータを使用してあらゆるギャップを埋めることで、推論時間をほぼ半分に短縮し、トレーニング時間を節約しました。これは、人間と同じように世界をより速く、より正確に認識し、最も混沌とした道路を自信を持ってナビゲートする車に向けた大きな飛躍です。