Kaggle competition: Lyft Motion Prediction for Autonomous Vehicles
<SOS> metric: PostProcessorKernel Kaggle data source: lyft-motion-prediction-autonomous-vehicles<feature_engineering>
import argparse
import os
import random
import sys
from typing import Tuple
import matplotlib.pyplot as plt
import numpy as np
import pytorch_lightning as pl
import torch
import l5kit
from l5kit.configs import load_config_data
from l5kit.data import ChunkedDataset, LocalDataManager
from l5kit.dataset import AgentDataset
from l5kit.evaluation import compute_metrics_csv, write_pred_csv
from l5kit.evaluation.metrics import neg_multi_log_likelihood, time_displace
from l5kit.geometry import transform_points
from l5kit.rasterization import build_rasterizer
from l5kit.visualization import TARGET_POINTS_COLOR, draw_trajectory
from torch.utils.data import DataLoader
import lyft_loss
import lyft_models
import lyft_utils
matchSum = match.sum().rename(columns=lambda s: '_msum.' + s ).reset_index()
all_data = reduce_mem_usage(pd.merge(all_data, matchSum))
del matchSum
gc.collect()
all_data['_enemy.sum.players'] = all_data['_msum.players'] - all_data['players']
all_data['_enemy.kills'] =(all_data['_msum.kills'] - all_data['_gsum.kills'])/ all_data['_enemy.sum.players']
all_data['_enemy.damageDealt'] =(all_data['_msum.damageDealt'] - all_data['_gsum.damageDealt'])/ all_data['_enemy.sum.players']
for c in agg_col:
all_data['_perc.gmax_msum.' + c] = all_data['_max.' + c] / all_data['_msum.' + c]
if c in gcol:
all_data['_perc.gsum_msum.' + c] = all_data['_gsum.' + c] / all_data['_msum.' + c]
fillInf(all_data, 0)
 print(all_data.shape )<categorify>
ALL_DATA_SIZE = 198474478
VAL_INTERVAL_SAMPLES = 250000
CFG_PATH = ".. /input/lyft-mpred-seresnext26-pretrained/agent_motion_config.yaml"
CSV_PATH = "./submission.csv"
MIN_FRAME_HISTORY = 0
MIN_FRAME_FUTURE = 10
VAL_SELECTED_FRAME =(99,)
 SEED = 42
os.environ["PYTHONHASHSEED"] = str(SEED)
 random.seed(SEED)
 np.random.seed(SEED )
matchMean = match.max().rename(columns=lambda s: '_mmax.' + s ).reset_index()
all_data = reduce_mem_usage(pd.merge(all_data, matchMean))
del matchMean
gc.collect()
for c in agg_col:
all_data['_perc.gmax_mmax.' + c] = all_data['_max.' + c] / all_data['_mmax.' + c]
all_data.drop(['_mmax.' + c], axis=1, inplace=True)
 fillInf(all_data, 0)
 print(all_data.shape )<merge>
class LyftMpredDatamodule(pl.LightningDataModule):
def __init__(
 self,
l5kit_data_folder: str,
cfg: dict,
batch_size: int = 440,
num_workers: int = 16,
downsample_train: bool = False,
is_test: bool = False,
is_debug: bool = False, 
)-> None:
super().__init__()
os.environ["L5KIT_DATA_FOLDER"] = l5kit_data_folder
self.cfg = cfg
self.batch_size = batch_size
self.num_workers = num_workers
self.downsample_train = downsample_train
self.is_test = is_test
self.is_debug = is_debug
def prepare_data(self):
self.dm = LocalDataManager(None)
 self.rasterizer = build_rasterizer(cfg, self.dm)
 def setup(self):
if self.is_test:
print("test mode setup")
 self.test_path, test_zarr, self.test_dataset = self.load_zarr_dataset(
 loader_name="test_data_loader" 
)
 else:
print("train mode setup")
 self.train_path, train_zarr, self.train_dataset = self.load_zarr_dataset(
 loader_name="train_data_loader" 
)
 self.val_path, val_zarr, self.val_dataset = self.load_zarr_dataset(
 loader_name="val_data_loader" 
)
 self.plot_dataset(self.train_dataset)
 if self.downsample_train:
print(
 "downsampling agents, using only {} frames from each scene".format(
 len(lyft_utils.TRAIN_DSAMPLE_FRAMES)
)
)
 train_agents_list = lyft_utils.downsample_agents(
 train_zarr,
self.train_dataset,
selected_frames=lyft_utils.TRAIN_DSAMPLE_FRAMES, 
)
 self.train_dataset = torch.utils.data.Subset(
 self.train_dataset, train_agents_list 
)
 val_agents_list = lyft_utils.downsample_agents(
 val_zarr, self.val_dataset, selected_frames=VAL_SELECTED_FRAME 
)
 self.val_dataset = torch.utils.data.Subset(
 self.val_dataset, val_agents_list 
)
 def train_dataloader(self):
return DataLoader(
 self.train_dataset,
shuffle=True,
batch_size=self.batch_size,
num_workers=self.num_workers, 
)
 def val_dataloader(self):
return DataLoader(
 self.val_dataset,
shuffle=False,
batch_size=self.batch_size,
num_workers=self.num_workers, 
)
 def test_dataloader(self):
return DataLoader(
 self.test_dataset,
shuffle=False,
batch_size=self.batch_size,
num_workers=self.num_workers, 
)
 def load_zarr_dataset(
 self, loader_name: str = "train_data_loder" 
)-> Tuple[str, ChunkedDataset, AgentDataset]:
zarr_path = self.dm.require(self.cfg[loader_name]["key"])
 print("load zarr data:", zarr_path)
 zarr_dataset = ChunkedDataset(zarr_path ).open()
if loader_name == "test_data_loader":
mask_path = os.path.join(os.path.dirname(zarr_path), "mask.npz")
 agents_mask = np.load(mask_path)["arr_0"]
agent_dataset = AgentDataset(
 self.cfg, zarr_dataset, self.rasterizer, agents_mask=agents_mask 
)
 else:
agent_dataset = AgentDataset(
 self.cfg,
zarr_dataset,
self.rasterizer,
min_frame_history=MIN_FRAME_HISTORY,
min_frame_future=MIN_FRAME_FUTURE, 
)
 print(zarr_dataset)
 return zarr_path, zarr_dataset, agent_dataset
def plot_dataset(self, agent_dataset: AgentDataset, plot_num: int = 10)-> None:
print("Ploting dataset")
 ind = np.random.randint(0, len(agent_dataset), size=plot_num)
 for i in range(plot_num):
data = agent_dataset[ind[i]]
im = data["image"].transpose(1, 2, 0)
 im = agent_dataset.rasterizer.to_rgb(im)
 target_positions_pixels = transform_points(
 data["target_positions"], data["raster_from_agent"] 
)
 draw_trajectory(
 im,
target_positions_pixels,
TARGET_POINTS_COLOR,
yaws=data["target_yaws"], 
)
 plt.imshow(im[::-1])
 if self.is_debug:
plt.show()
killMinorRank = all_data[['matchId','_min.kills','_max.killPlace']].copy()
group = killMinorRank.groupby(['matchId','_min.kills'])
 killMinorRank['_rank.minor.maxKillPlace'] = group.rank().values
all_data = pd.merge(all_data, killMinorRank)
 killMinorRank = all_data[['matchId','_max.kills','_min.killPlace']].copy()
group = killMinorRank.groupby(['matchId','_max.kills'])
 killMinorRank['_rank.minor.minKillPlace'] = group.rank().values
all_data = pd.merge(all_data, killMinorRank)
 del killMinorRank
gc.collect()<count_values>
class LitModel(pl.LightningModule):
def __init__(
 self,
cfg: dict,
num_modes: int = 3,
ba_size: int = 128,
lr: float = 3.0e-4,
backbone_name: str = "efficientnet_b1",
epochs: int = 1,
total_steps: int = 100,
data_size: int = ALL_DATA_SIZE,
optim_name: str = "adam", 
)-> None:
super().__init__()
self.save_hyperparameters(
 "lr",
"backbone_name",
"num_modes",
"ba_size",
"epochs",
"optim_name",
"data_size",
"total_steps", 
)
 self.model = lyft_models.LyftMultiModel(
 cfg, num_modes=num_modes, backbone_name=backbone_name 
)
 self.test_keys =("world_from_agent", "centroid", "timestamp", "track_id")
 def forward(self, x):
x = self.model(x)
 return x
def training_step(self, batch, batch_idx):
inputs = batch["image"]
target_availabilities = batch["target_availabilities"].unsqueeze(-1)
 targets = batch["target_positions"]
outputs, confidences = self.model(inputs)
 loss = lyft_loss.pytorch_neg_multi_log_likelihood_batch(
 targets,
outputs,
confidences.squeeze() ,
target_availabilities.squeeze() , 
)
 self.log(
 "train_epoch_loss",
loss,
prog_bar=False,
on_epoch=True,
on_step=False, 
)
 self.log("train_loss", loss)
 return loss
def validation_step(self, batch, batch_idx):
inputs = batch["image"]
target_availabilities = batch["target_availabilities"].unsqueeze(-1)
 targets = batch["target_positions"]
outputs, confidences = self.model(inputs)
 loss = lyft_loss.pytorch_neg_multi_log_likelihood_batch(
 targets,
outputs,
confidences.squeeze() ,
target_availabilities.squeeze() , 
)
 self.log("val_loss", loss)
 return loss
def test_step(self, batch, batch_idx):
inputs = batch["image"]
outputs, confidences = self.model(inputs)
 test_batch = {key_: batch[key_] for key_ in self.test_keys}
return outputs, confidences, test_batch
def test_epoch_end(self, outputs):

 pred_coords_list = []
confidences_list = []
timestamps_list = []
track_id_list = []
for outputs, confidences, batch in outputs:
outputs = outputs.cpu().numpy()
world_from_agents = batch["world_from_agent"].cpu().numpy()
centroids = batch["centroid"].cpu().numpy()
for idx in range(len(outputs)) :
for mode in range(3):
outputs[idx, mode, :, :] =(
 transform_points(
 outputs[idx, mode, :, :], world_from_agents[idx] 
)
 - centroids[idx][:2] 
)
 pred_coords_list.append(outputs)
 confidences_list.append(confidences)
 timestamps_list.append(batch["timestamp"])
 track_id_list.append(batch["track_id"])
 coords = np.concatenate(pred_coords_list)
 confs = torch.cat(confidences_list ).cpu().numpy()
track_ids = torch.cat(track_id_list ).cpu().numpy()
timestamps = torch.cat(timestamps_list ).cpu().numpy()
write_pred_csv(
 CSV_PATH,
timestamps=timestamps,
track_ids=track_ids,
coords=coords,
confs=confs, 
)
 print(f"Saved to {CSV_PATH}")
 def configure_optimizers(self):
if self.hparams.optim_name == "sgd":
optimizer = torch.optim.SGD(
 self.parameters() ,
lr=self.hparams.lr,
momentum=0.9,
weight_decay=4e-5, 
)
 elif self.hparams.optim_name == "adam":
optimizer = torch.optim.Adam(self.parameters() , lr=self.hparams.lr)
 else:
raise NotImplementedError
scheduler = torch.optim.lr_scheduler.OneCycleLR(
 optimizer, max_lr=self.hparams.lr, total_steps=self.hparams.total_steps 
)
 return [optimizer], [scheduler]
mapper = lambda x: 'solo' if('solo' in x)else 'duo' if('duo' in x)or('crash' in x)else 'squad'
all_data['matchTypeCat'] = all_data['matchType'].map(mapper)
 print(all_data['matchTypeCat'].value_counts() )<count_unique_values>
mpred_dm = LyftMpredDatamodule(
 args.l5kit_data_folder,
cfg,
batch_size=args.batch_size,
num_workers=args.num_workers,
downsample_train=args.downsample_train,
is_test=args.is_test,
is_debug=args.is_debug, 
)
 mpred_dm.prepare_data()
mpred_dm.setup()
constant_column = [col for col in all_data.columns if all_data[col].nunique() == 1]
print('drop columns:', constant_column)
 all_data.drop(constant_column, axis=1, inplace=True )<sort_values>
if args.is_test:
print("\t\t ==== TEST MODE ====")
 print("load from: ", args.ckpt_path)
 model = LitModel.load_from_checkpoint(args.ckpt_path, cfg=cfg)
 trainer = pl.Trainer(gpus=len(args.visible_gpus.split(",")))
 trainer.test(model, datamodule=mpred_dm )
null_cnt = all_data.isnull().sum().sort_values()
print(null_cnt[null_cnt > 0])
 all_data.head()<feature_engineering>
if not args.is_test:
print("\t\t ==== TRAIN MODE ====")
 print(
 "training samples: {}, valid samples: {}".format(
 len(mpred_dm.train_dataset), len(mpred_dm.val_dataset)
)
)
 total_steps = args.epochs * len(mpred_dm.train_dataset)// args.batch_size
val_check_interval = VAL_INTERVAL_SAMPLES // args.batch_size
model = LitModel(
 cfg,
lr=args.lr,
backbone_name=args.backbone_name,
num_modes=args.num_modes,
optim_name=args.optim_name,
ba_size=args.batch_size,
epochs=args.epochs,
data_size=len(mpred_dm.train_dataset),
total_steps=total_steps, 
)
 checkpoint_callback = pl.callbacks.ModelCheckpoint(
 monitor="val_loss",
save_last=True,
mode="min",
verbose=True, 
)
 pl.trainer.seed_everything(seed=SEED)
 trainer = pl.Trainer(
 gpus=len(args.visible_gpus.split(",")) ,
max_steps=total_steps,
val_check_interval=val_check_interval,
precision=args.precision,
benchmark=True,
deterministic=False,
checkpoint_callback=checkpoint_callback, 
)
 trainer.fit(model, datamodule=mpred_dm )