Els cotxes autònoms no es poden permetre errors. Faltar un semàfor o un vianant pot significar un desastre. Però la detecció d'objectes en entorns urbans dinàmics? Això és difícil.
Vaig treballar en l'optimització de la detecció d'objectes per a vehicles autònoms mitjançant Atrous Spatial Pyramid Pooling (ASPP) i Transfer Learning. El resultat? Un model que detecta objectes a múltiples escales, fins i tot amb mala il·luminació, i funciona de manera eficient en temps real.
Així és com ho vaig fer.
Els cotxes autònoms depenen de les xarxes neuronals convolucionals (CNN) per detectar objectes, però les condicions del món real presenten reptes:
Les CNN tradicionals lluiten amb la detecció d'objectes multiescala i l'entrenament des de zero triga una eternitat. Aquí és on entren ASPP i Transfer Learning .
Les CNN funcionen bé per a objectes de mida fixa, però els objectes del món real varien en mida i distància. Atrous Spatial Pyramid Pooling (ASPP) soluciona això mitjançant l'ús de convolucions dilatades per capturar característiques a múltiples escales.
L'ASPP aplica diversos filtres de convolució amb diferents taxes de dilatació per extreure funcions a diferents resolucions, objectes petits, objectes grans i tot el que hi ha entremig.
Així és com vaig implementar ASPP a PyTorch incorporant la normalització i l'atenció del grup per a un rendiment robust en entorns complexos:
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
Entrenar un model de detecció d'objectes des de zero no aporta gaires beneficis quan existeixen models pre-entrenats. L'aprenentatge de transferència ens permet afinar un model que ja entén els objectes.
Vaig utilitzar DETR (Detection Transformer), un model de detecció d'objectes basat en transformadors de Facebook AI. Aprèn context, de manera que no només troba un senyal de stop, sinó que entén que forma part d'una escena de carretera.
Així és com vaig ajustar DETR en conjunts de dades de conducció autònoma:
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)
Els vehicles autònoms necessiten conjunts de dades massius, però les dades etiquetades del món real són escasses. La correcció? Generar dades sintètiques mitjançant GAN (Generative Adversarial Networks).
Vaig utilitzar un GAN per crear marques de carril falses però realistes i escenes de trànsit per ampliar el conjunt de dades .
Aquí teniu un GAN senzill per a la generació de marques de carril:
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)
Combinant ASPP, Transfer Learning i Synthetic Data , vaig crear un sistema de detecció d'objectes més precís i escalable per a cotxes autònoms. Alguns dels resultats clau són:
Vam fusionar ASPP, Transformers i Synthetic Data en una triple amenaça per a la detecció d'objectes autònoms, convertint models que abans era lents i propensos als punts cecs en sistemes ràpids i perceptius que detecten un semàfor a una illa de distància. En adoptar circumvolucions dilatades per obtenir detalls a diverses escalas, transferir l'aprenentatge per a un ajustament ràpid i dades generades per GAN per omplir tots els buits, reduïm els temps d'inferència gairebé a la meitat i estalviem hores d'entrenament. És un gran salt cap als cotxes que veuen el món més com nosaltres, només més ràpid, amb més precisió, i en camí de navegar pels nostres carrers més caòtics amb confiança.