Los coches autónomos no pueden permitirse errores. Pasarse por alto un semáforo o un peatón podría suponer un desastre. Pero ¿la detección de objetos en entornos urbanos dinámicos? Eso es difícil.
Trabajé en la optimización de la detección de objetos para vehículos autónomos utilizando Atrous Spatial Pyramid Pooling (ASPP) y Transfer Learning. ¿El resultado? Un modelo que detecta objetos en múltiples escalas, incluso con poca iluminación, y funciona de manera eficiente en tiempo real.
Así es como lo hice.
Los automóviles autónomos dependen de redes neuronales convolucionales (CNN) para detectar objetos, pero las condiciones del mundo real presentan desafíos:
Las CNN tradicionales tienen dificultades para detectar objetos en múltiples escalas y el entrenamiento desde cero lleva mucho tiempo. Ahí es donde entran en juego ASPP y Transfer Learning .
Las CNN funcionan bien para objetos de tamaño fijo, pero los objetos del mundo real varían en tamaño y distancia. Atrous Spatial Pyramid Pooling (ASPP) resuelve este problema mediante el uso de convoluciones dilatadas para capturar características en múltiples escalas.
ASPP aplica múltiples filtros de convolución con diferentes tasas de dilatación para extraer características en diferentes resoluciones, objetos pequeños, objetos grandes y todo lo demás.
Así es como implementé ASPP en PyTorch incorporando normalización de grupo y atención para un rendimiento sólido en entornos complejos:
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 modelo de detección de objetos desde cero no ofrece muchos beneficios cuando existen modelos previamente entrenados. El aprendizaje por transferencia nos permite ajustar un modelo que ya comprende objetos.
Utilicé DETR (Detection Transformer), un modelo de detección de objetos basado en transformadores de Facebook AI. Aprende el contexto, por lo que no solo encuentra una señal de stop, sino que entiende que es parte de una escena de la carretera.
Así es como ajusté el DETR en los conjuntos de datos de conducción 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)
Los vehículos autónomos necesitan conjuntos de datos masivos, pero los datos etiquetados del mundo real son escasos. ¿La solución? Generar datos sintéticos mediante GAN (redes generativas antagónicas).
Utilicé una GAN para crear marcas de carril y escenas de tráfico falsas pero realistas para ampliar el conjunto de datos .
A continuación se muestra una GAN simple para la generación de marcas 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)
Al combinar ASPP, aprendizaje por transferencia y datos sintéticos , construí un sistema de detección de objetos más preciso y escalable para vehículos autónomos. Algunos de los resultados clave son:
Fusionamos ASPP, Transformers y Synthetic Data en una triple amenaza para la detección autónoma de objetos: convertimos modelos que antes eran lentos y propensos a los puntos ciegos en sistemas rápidos y perceptivos que detectan un semáforo a una cuadra de distancia. Al adoptar convoluciones dilatadas para obtener detalles a múltiples escalas, aprendizaje por transferencia para un ajuste fino rápido y datos generados por GAN para llenar cada vacío, redujimos los tiempos de inferencia casi a la mitad y ahorramos horas de entrenamiento. Es un gran salto hacia autos que ven el mundo más como nosotros lo vemos, solo que más rápido, con mayor precisión y en camino de navegar por nuestras calles más caóticas con confianza.